/* Minification failed. Returning unminified contents.
(145447,17-26): run-time error JS1019: Can't have 'break' outside of loop: break OUT
(141249,41-50): run-time error JS1019: Can't have 'break' outside of loop: break OUT
 */
/*!
 * jQuery JavaScript Library v1.12.3
 * http://jquery.com/
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2016-04-05T19:16Z
 */

(function( global, factory ) {

	if ( typeof module === "object" && typeof module.exports === "object" ) {
		// For CommonJS and CommonJS-like environments where a proper `window`
		// is present, execute the factory and get jQuery.
		// For environments that do not have a `window` with a `document`
		// (such as Node.js), expose a factory as module.exports.
		// This accentuates the need for the creation of a real `window`.
		// e.g. var jQuery = require("jquery")(window);
		// See ticket #14549 for more info.
		module.exports = global.document ?
			factory( global, true ) :
			function( w ) {
				if ( !w.document ) {
					throw new Error( "jQuery requires a window with a document" );
				}
				return factory( w );
			};
	} else {
		factory( global );
	}

// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {

// Support: Firefox 18+
// Can't be in strict mode, several libs including ASP.NET trace
// the stack via arguments.caller.callee and Firefox dies if
// you try to trace through "use strict" call chains. (#13335)
//"use strict";
var deletedIds = [];

var document = window.document;

var slice = deletedIds.slice;

var concat = deletedIds.concat;

var push = deletedIds.push;

var indexOf = deletedIds.indexOf;

var class2type = {};

var toString = class2type.toString;

var hasOwn = class2type.hasOwnProperty;

var support = {};



var
	version = "1.12.3",

	// Define a local copy of jQuery
	jQuery = function( selector, context ) {

		// The jQuery object is actually just the init constructor 'enhanced'
		// Need init if jQuery is called (just allow error to be thrown if not included)
		return new jQuery.fn.init( selector, context );
	},

	// Support: Android<4.1, IE<9
	// Make sure we trim BOM and NBSP
	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,

	// Matches dashed string for camelizing
	rmsPrefix = /^-ms-/,
	rdashAlpha = /-([\da-z])/gi,

	// Used by jQuery.camelCase as callback to replace()
	fcamelCase = function( all, letter ) {
		return letter.toUpperCase();
	};

jQuery.fn = jQuery.prototype = {

	// The current version of jQuery being used
	jquery: version,

	constructor: jQuery,

	// Start with an empty selector
	selector: "",

	// The default length of a jQuery object is 0
	length: 0,

	toArray: function() {
		return slice.call( this );
	},

	// Get the Nth element in the matched element set OR
	// Get the whole matched element set as a clean array
	get: function( num ) {
		return num != null ?

			// Return just the one element from the set
			( num < 0 ? this[ num + this.length ] : this[ num ] ) :

			// Return all the elements in a clean array
			slice.call( this );
	},

	// Take an array of elements and push it onto the stack
	// (returning the new matched element set)
	pushStack: function( elems ) {

		// Build a new jQuery matched element set
		var ret = jQuery.merge( this.constructor(), elems );

		// Add the old object onto the stack (as a reference)
		ret.prevObject = this;
		ret.context = this.context;

		// Return the newly-formed element set
		return ret;
	},

	// Execute a callback for every element in the matched set.
	each: function( callback ) {
		return jQuery.each( this, callback );
	},

	map: function( callback ) {
		return this.pushStack( jQuery.map( this, function( elem, i ) {
			return callback.call( elem, i, elem );
		} ) );
	},

	slice: function() {
		return this.pushStack( slice.apply( this, arguments ) );
	},

	first: function() {
		return this.eq( 0 );
	},

	last: function() {
		return this.eq( -1 );
	},

	eq: function( i ) {
		var len = this.length,
			j = +i + ( i < 0 ? len : 0 );
		return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
	},

	end: function() {
		return this.prevObject || this.constructor();
	},

	// For internal use only.
	// Behaves like an Array's method, not like a jQuery method.
	push: push,
	sort: deletedIds.sort,
	splice: deletedIds.splice
};

jQuery.extend = jQuery.fn.extend = function() {
	var src, copyIsArray, copy, name, options, clone,
		target = arguments[ 0 ] || {},
		i = 1,
		length = arguments.length,
		deep = false;

	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
		deep = target;

		// skip the boolean and the target
		target = arguments[ i ] || {};
		i++;
	}

	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
		target = {};
	}

	// extend jQuery itself if only one argument is passed
	if ( i === length ) {
		target = this;
		i--;
	}

	for ( ; i < length; i++ ) {

		// Only deal with non-null/undefined values
		if ( ( options = arguments[ i ] ) != null ) {

			// Extend the base object
			for ( name in options ) {
				src = target[ name ];
				copy = options[ name ];

				// Prevent never-ending loop
				if ( target === copy ) {
					continue;
				}

				// Recurse if we're merging plain objects or arrays
				if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
					( copyIsArray = jQuery.isArray( copy ) ) ) ) {

					if ( copyIsArray ) {
						copyIsArray = false;
						clone = src && jQuery.isArray( src ) ? src : [];

					} else {
						clone = src && jQuery.isPlainObject( src ) ? src : {};
					}

					// Never move original objects, clone them
					target[ name ] = jQuery.extend( deep, clone, copy );

				// Don't bring in undefined values
				} else if ( copy !== undefined ) {
					target[ name ] = copy;
				}
			}
		}
	}

	// Return the modified object
	return target;
};

jQuery.extend( {

	// Unique for each copy of jQuery on the page
	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),

	// Assume jQuery is ready without the ready module
	isReady: true,

	error: function( msg ) {
		throw new Error( msg );
	},

	noop: function() {},

	// See test/unit/core.js for details concerning isFunction.
	// Since version 1.3, DOM methods and functions like alert
	// aren't supported. They return false on IE (#2968).
	isFunction: function( obj ) {
		return jQuery.type( obj ) === "function";
	},

	isArray: Array.isArray || function( obj ) {
		return jQuery.type( obj ) === "array";
	},

	isWindow: function( obj ) {
		/* jshint eqeqeq: false */
		return obj != null && obj == obj.window;
	},

	isNumeric: function( obj ) {

		// parseFloat NaNs numeric-cast false positives (null|true|false|"")
		// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
		// subtraction forces infinities to NaN
		// adding 1 corrects loss of precision from parseFloat (#15100)
		var realStringObj = obj && obj.toString();
		return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;
	},

	isEmptyObject: function( obj ) {
		var name;
		for ( name in obj ) {
			return false;
		}
		return true;
	},

	isPlainObject: function( obj ) {
		var key;

		// Must be an Object.
		// Because of IE, we also have to check the presence of the constructor property.
		// Make sure that DOM nodes and window objects don't pass through, as well
		if ( !obj || jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
			return false;
		}

		try {

			// Not own constructor property must be Object
			if ( obj.constructor &&
				!hasOwn.call( obj, "constructor" ) &&
				!hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
				return false;
			}
		} catch ( e ) {

			// IE8,9 Will throw exceptions on certain host objects #9897
			return false;
		}

		// Support: IE<9
		// Handle iteration over inherited properties before own properties.
		if ( !support.ownFirst ) {
			for ( key in obj ) {
				return hasOwn.call( obj, key );
			}
		}

		// Own properties are enumerated firstly, so to speed up,
		// if last one is own, then all properties are own.
		for ( key in obj ) {}

		return key === undefined || hasOwn.call( obj, key );
	},

	type: function( obj ) {
		if ( obj == null ) {
			return obj + "";
		}
		return typeof obj === "object" || typeof obj === "function" ?
			class2type[ toString.call( obj ) ] || "object" :
			typeof obj;
	},

	// Workarounds based on findings by Jim Driscoll
	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
	globalEval: function( data ) {
		if ( data && jQuery.trim( data ) ) {

			// We use execScript on Internet Explorer
			// We use an anonymous function so that context is window
			// rather than jQuery in Firefox
			( window.execScript || function( data ) {
				window[ "eval" ].call( window, data ); // jscs:ignore requireDotNotation
			} )( data );
		}
	},

	// Convert dashed to camelCase; used by the css and data modules
	// Microsoft forgot to hump their vendor prefix (#9572)
	camelCase: function( string ) {
		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
	},

	nodeName: function( elem, name ) {
		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
	},

	each: function( obj, callback ) {
		var length, i = 0;

		if ( isArrayLike( obj ) ) {
			length = obj.length;
			for ( ; i < length; i++ ) {
				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
					break;
				}
			}
		} else {
			for ( i in obj ) {
				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
					break;
				}
			}
		}

		return obj;
	},

	// Support: Android<4.1, IE<9
	trim: function( text ) {
		return text == null ?
			"" :
			( text + "" ).replace( rtrim, "" );
	},

	// results is for internal usage only
	makeArray: function( arr, results ) {
		var ret = results || [];

		if ( arr != null ) {
			if ( isArrayLike( Object( arr ) ) ) {
				jQuery.merge( ret,
					typeof arr === "string" ?
					[ arr ] : arr
				);
			} else {
				push.call( ret, arr );
			}
		}

		return ret;
	},

	inArray: function( elem, arr, i ) {
		var len;

		if ( arr ) {
			if ( indexOf ) {
				return indexOf.call( arr, elem, i );
			}

			len = arr.length;
			i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;

			for ( ; i < len; i++ ) {

				// Skip accessing in sparse arrays
				if ( i in arr && arr[ i ] === elem ) {
					return i;
				}
			}
		}

		return -1;
	},

	merge: function( first, second ) {
		var len = +second.length,
			j = 0,
			i = first.length;

		while ( j < len ) {
			first[ i++ ] = second[ j++ ];
		}

		// Support: IE<9
		// Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
		if ( len !== len ) {
			while ( second[ j ] !== undefined ) {
				first[ i++ ] = second[ j++ ];
			}
		}

		first.length = i;

		return first;
	},

	grep: function( elems, callback, invert ) {
		var callbackInverse,
			matches = [],
			i = 0,
			length = elems.length,
			callbackExpect = !invert;

		// Go through the array, only saving the items
		// that pass the validator function
		for ( ; i < length; i++ ) {
			callbackInverse = !callback( elems[ i ], i );
			if ( callbackInverse !== callbackExpect ) {
				matches.push( elems[ i ] );
			}
		}

		return matches;
	},

	// arg is for internal usage only
	map: function( elems, callback, arg ) {
		var length, value,
			i = 0,
			ret = [];

		// Go through the array, translating each of the items to their new values
		if ( isArrayLike( elems ) ) {
			length = elems.length;
			for ( ; i < length; i++ ) {
				value = callback( elems[ i ], i, arg );

				if ( value != null ) {
					ret.push( value );
				}
			}

		// Go through every key on the object,
		} else {
			for ( i in elems ) {
				value = callback( elems[ i ], i, arg );

				if ( value != null ) {
					ret.push( value );
				}
			}
		}

		// Flatten any nested arrays
		return concat.apply( [], ret );
	},

	// A global GUID counter for objects
	guid: 1,

	// Bind a function to a context, optionally partially applying any
	// arguments.
	proxy: function( fn, context ) {
		var args, proxy, tmp;

		if ( typeof context === "string" ) {
			tmp = fn[ context ];
			context = fn;
			fn = tmp;
		}

		// Quick check to determine if target is callable, in the spec
		// this throws a TypeError, but we will just return undefined.
		if ( !jQuery.isFunction( fn ) ) {
			return undefined;
		}

		// Simulated bind
		args = slice.call( arguments, 2 );
		proxy = function() {
			return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
		};

		// Set the guid of unique handler to the same of original handler, so it can be removed
		proxy.guid = fn.guid = fn.guid || jQuery.guid++;

		return proxy;
	},

	now: function() {
		return +( new Date() );
	},

	// jQuery.support is not used in Core but other projects attach their
	// properties to it so it needs to exist.
	support: support
} );

// JSHint would error on this code due to the Symbol not being defined in ES5.
// Defining this global in .jshintrc would create a danger of using the global
// unguarded in another place, it seems safer to just disable JSHint for these
// three lines.
/* jshint ignore: start */
if ( typeof Symbol === "function" ) {
	jQuery.fn[ Symbol.iterator ] = deletedIds[ Symbol.iterator ];
}
/* jshint ignore: end */

// Populate the class2type map
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( i, name ) {
	class2type[ "[object " + name + "]" ] = name.toLowerCase();
} );

function isArrayLike( obj ) {

	// Support: iOS 8.2 (not reproducible in simulator)
	// `in` check used to prevent JIT error (gh-2145)
	// hasOwn isn't used here due to false negatives
	// regarding Nodelist length in IE
	var length = !!obj && "length" in obj && obj.length,
		type = jQuery.type( obj );

	if ( type === "function" || jQuery.isWindow( obj ) ) {
		return false;
	}

	return type === "array" || length === 0 ||
		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}
var Sizzle =
/*!
 * Sizzle CSS Selector Engine v2.2.1
 * http://sizzlejs.com/
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2015-10-17
 */
(function( window ) {

var i,
	support,
	Expr,
	getText,
	isXML,
	tokenize,
	compile,
	select,
	outermostContext,
	sortInput,
	hasDuplicate,

	// Local document vars
	setDocument,
	document,
	docElem,
	documentIsHTML,
	rbuggyQSA,
	rbuggyMatches,
	matches,
	contains,

	// Instance-specific data
	expando = "sizzle" + 1 * new Date(),
	preferredDoc = window.document,
	dirruns = 0,
	done = 0,
	classCache = createCache(),
	tokenCache = createCache(),
	compilerCache = createCache(),
	sortOrder = function( a, b ) {
		if ( a === b ) {
			hasDuplicate = true;
		}
		return 0;
	},

	// General-purpose constants
	MAX_NEGATIVE = 1 << 31,

	// Instance methods
	hasOwn = ({}).hasOwnProperty,
	arr = [],
	pop = arr.pop,
	push_native = arr.push,
	push = arr.push,
	slice = arr.slice,
	// Use a stripped-down indexOf as it's faster than native
	// http://jsperf.com/thor-indexof-vs-for/5
	indexOf = function( list, elem ) {
		var i = 0,
			len = list.length;
		for ( ; i < len; i++ ) {
			if ( list[i] === elem ) {
				return i;
			}
		}
		return -1;
	},

	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",

	// Regular expressions

	// http://www.w3.org/TR/css3-selectors/#whitespace
	whitespace = "[\\x20\\t\\r\\n\\f]",

	// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
	identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",

	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
	attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
		// Operator (capture 2)
		"*([*^$|!~]?=)" + whitespace +
		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
		"*\\]",

	pseudos = ":(" + identifier + ")(?:\\((" +
		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
		// 1. quoted (capture 3; capture 4 or capture 5)
		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
		// 2. simple (capture 6)
		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
		// 3. anything else (capture 2)
		".*" +
		")\\)|)",

	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
	rwhitespace = new RegExp( whitespace + "+", "g" ),
	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),

	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),

	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),

	rpseudo = new RegExp( pseudos ),
	ridentifier = new RegExp( "^" + identifier + "$" ),

	matchExpr = {
		"ID": new RegExp( "^#(" + identifier + ")" ),
		"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
		"TAG": new RegExp( "^(" + identifier + "|[*])" ),
		"ATTR": new RegExp( "^" + attributes ),
		"PSEUDO": new RegExp( "^" + pseudos ),
		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
		// For use in libraries implementing .is()
		// We use this for POS matching in `select`
		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
	},

	rinputs = /^(?:input|select|textarea|button)$/i,
	rheader = /^h\d$/i,

	rnative = /^[^{]+\{\s*\[native \w/,

	// Easily-parseable/retrievable ID or TAG or CLASS selectors
	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,

	rsibling = /[+~]/,
	rescape = /'|\\/g,

	// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
	funescape = function( _, escaped, escapedWhitespace ) {
		var high = "0x" + escaped - 0x10000;
		// NaN means non-codepoint
		// Support: Firefox<24
		// Workaround erroneous numeric interpretation of +"0x"
		return high !== high || escapedWhitespace ?
			escaped :
			high < 0 ?
				// BMP codepoint
				String.fromCharCode( high + 0x10000 ) :
				// Supplemental Plane codepoint (surrogate pair)
				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
	},

	// Used for iframes
	// See setDocument()
	// Removing the function wrapper causes a "Permission Denied"
	// error in IE
	unloadHandler = function() {
		setDocument();
	};

// Optimize for push.apply( _, NodeList )
try {
	push.apply(
		(arr = slice.call( preferredDoc.childNodes )),
		preferredDoc.childNodes
	);
	// Support: Android<4.0
	// Detect silently failing push.apply
	arr[ preferredDoc.childNodes.length ].nodeType;
} catch ( e ) {
	push = { apply: arr.length ?

		// Leverage slice if possible
		function( target, els ) {
			push_native.apply( target, slice.call(els) );
		} :

		// Support: IE<9
		// Otherwise append directly
		function( target, els ) {
			var j = target.length,
				i = 0;
			// Can't trust NodeList.length
			while ( (target[j++] = els[i++]) ) {}
			target.length = j - 1;
		}
	};
}

function Sizzle( selector, context, results, seed ) {
	var m, i, elem, nid, nidselect, match, groups, newSelector,
		newContext = context && context.ownerDocument,

		// nodeType defaults to 9, since context defaults to document
		nodeType = context ? context.nodeType : 9;

	results = results || [];

	// Return early from calls with invalid selector or context
	if ( typeof selector !== "string" || !selector ||
		nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {

		return results;
	}

	// Try to shortcut find operations (as opposed to filters) in HTML documents
	if ( !seed ) {

		if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
			setDocument( context );
		}
		context = context || document;

		if ( documentIsHTML ) {

			// If the selector is sufficiently simple, try using a "get*By*" DOM method
			// (excepting DocumentFragment context, where the methods don't exist)
			if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {

				// ID selector
				if ( (m = match[1]) ) {

					// Document context
					if ( nodeType === 9 ) {
						if ( (elem = context.getElementById( m )) ) {

							// Support: IE, Opera, Webkit
							// TODO: identify versions
							// getElementById can match elements by name instead of ID
							if ( elem.id === m ) {
								results.push( elem );
								return results;
							}
						} else {
							return results;
						}

					// Element context
					} else {

						// Support: IE, Opera, Webkit
						// TODO: identify versions
						// getElementById can match elements by name instead of ID
						if ( newContext && (elem = newContext.getElementById( m )) &&
							contains( context, elem ) &&
							elem.id === m ) {

							results.push( elem );
							return results;
						}
					}

				// Type selector
				} else if ( match[2] ) {
					push.apply( results, context.getElementsByTagName( selector ) );
					return results;

				// Class selector
				} else if ( (m = match[3]) && support.getElementsByClassName &&
					context.getElementsByClassName ) {

					push.apply( results, context.getElementsByClassName( m ) );
					return results;
				}
			}

			// Take advantage of querySelectorAll
			if ( support.qsa &&
				!compilerCache[ selector + " " ] &&
				(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {

				if ( nodeType !== 1 ) {
					newContext = context;
					newSelector = selector;

				// qSA looks outside Element context, which is not what we want
				// Thanks to Andrew Dupont for this workaround technique
				// Support: IE <=8
				// Exclude object elements
				} else if ( context.nodeName.toLowerCase() !== "object" ) {

					// Capture the context ID, setting it first if necessary
					if ( (nid = context.getAttribute( "id" )) ) {
						nid = nid.replace( rescape, "\\$&" );
					} else {
						context.setAttribute( "id", (nid = expando) );
					}

					// Prefix every selector in the list
					groups = tokenize( selector );
					i = groups.length;
					nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']";
					while ( i-- ) {
						groups[i] = nidselect + " " + toSelector( groups[i] );
					}
					newSelector = groups.join( "," );

					// Expand context for sibling selectors
					newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
						context;
				}

				if ( newSelector ) {
					try {
						push.apply( results,
							newContext.querySelectorAll( newSelector )
						);
						return results;
					} catch ( qsaError ) {
					} finally {
						if ( nid === expando ) {
							context.removeAttribute( "id" );
						}
					}
				}
			}
		}
	}

	// All others
	return select( selector.replace( rtrim, "$1" ), context, results, seed );
}

/**
 * Create key-value caches of limited size
 * @returns {function(string, object)} Returns the Object data after storing it on itself with
 *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
 *	deleting the oldest entry
 */
function createCache() {
	var keys = [];

	function cache( key, value ) {
		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
		if ( keys.push( key + " " ) > Expr.cacheLength ) {
			// Only keep the most recent entries
			delete cache[ keys.shift() ];
		}
		return (cache[ key + " " ] = value);
	}
	return cache;
}

/**
 * Mark a function for special use by Sizzle
 * @param {Function} fn The function to mark
 */
function markFunction( fn ) {
	fn[ expando ] = true;
	return fn;
}

/**
 * Support testing using an element
 * @param {Function} fn Passed the created div and expects a boolean result
 */
function assert( fn ) {
	var div = document.createElement("div");

	try {
		return !!fn( div );
	} catch (e) {
		return false;
	} finally {
		// Remove from its parent by default
		if ( div.parentNode ) {
			div.parentNode.removeChild( div );
		}
		// release memory in IE
		div = null;
	}
}

/**
 * Adds the same handler for all of the specified attrs
 * @param {String} attrs Pipe-separated list of attributes
 * @param {Function} handler The method that will be applied
 */
function addHandle( attrs, handler ) {
	var arr = attrs.split("|"),
		i = arr.length;

	while ( i-- ) {
		Expr.attrHandle[ arr[i] ] = handler;
	}
}

/**
 * Checks document order of two siblings
 * @param {Element} a
 * @param {Element} b
 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
 */
function siblingCheck( a, b ) {
	var cur = b && a,
		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
			( ~b.sourceIndex || MAX_NEGATIVE ) -
			( ~a.sourceIndex || MAX_NEGATIVE );

	// Use IE sourceIndex if available on both nodes
	if ( diff ) {
		return diff;
	}

	// Check if b follows a
	if ( cur ) {
		while ( (cur = cur.nextSibling) ) {
			if ( cur === b ) {
				return -1;
			}
		}
	}

	return a ? 1 : -1;
}

/**
 * Returns a function to use in pseudos for input types
 * @param {String} type
 */
function createInputPseudo( type ) {
	return function( elem ) {
		var name = elem.nodeName.toLowerCase();
		return name === "input" && elem.type === type;
	};
}

/**
 * Returns a function to use in pseudos for buttons
 * @param {String} type
 */
function createButtonPseudo( type ) {
	return function( elem ) {
		var name = elem.nodeName.toLowerCase();
		return (name === "input" || name === "button") && elem.type === type;
	};
}

/**
 * Returns a function to use in pseudos for positionals
 * @param {Function} fn
 */
function createPositionalPseudo( fn ) {
	return markFunction(function( argument ) {
		argument = +argument;
		return markFunction(function( seed, matches ) {
			var j,
				matchIndexes = fn( [], seed.length, argument ),
				i = matchIndexes.length;

			// Match elements found at the specified indexes
			while ( i-- ) {
				if ( seed[ (j = matchIndexes[i]) ] ) {
					seed[j] = !(matches[j] = seed[j]);
				}
			}
		});
	});
}

/**
 * Checks a node for validity as a Sizzle context
 * @param {Element|Object=} context
 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
 */
function testContext( context ) {
	return context && typeof context.getElementsByTagName !== "undefined" && context;
}

// Expose support vars for convenience
support = Sizzle.support = {};

/**
 * Detects XML nodes
 * @param {Element|Object} elem An element or a document
 * @returns {Boolean} True iff elem is a non-HTML XML node
 */
isXML = Sizzle.isXML = function( elem ) {
	// documentElement is verified for cases where it doesn't yet exist
	// (such as loading iframes in IE - #4833)
	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
	return documentElement ? documentElement.nodeName !== "HTML" : false;
};

/**
 * Sets document-related variables once based on the current document
 * @param {Element|Object} [doc] An element or document object to use to set the document
 * @returns {Object} Returns the current document
 */
setDocument = Sizzle.setDocument = function( node ) {
	var hasCompare, parent,
		doc = node ? node.ownerDocument || node : preferredDoc;

	// Return early if doc is invalid or already selected
	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
		return document;
	}

	// Update global variables
	document = doc;
	docElem = document.documentElement;
	documentIsHTML = !isXML( document );

	// Support: IE 9-11, Edge
	// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
	if ( (parent = document.defaultView) && parent.top !== parent ) {
		// Support: IE 11
		if ( parent.addEventListener ) {
			parent.addEventListener( "unload", unloadHandler, false );

		// Support: IE 9 - 10 only
		} else if ( parent.attachEvent ) {
			parent.attachEvent( "onunload", unloadHandler );
		}
	}

	/* Attributes
	---------------------------------------------------------------------- */

	// Support: IE<8
	// Verify that getAttribute really returns attributes and not properties
	// (excepting IE8 booleans)
	support.attributes = assert(function( div ) {
		div.className = "i";
		return !div.getAttribute("className");
	});

	/* getElement(s)By*
	---------------------------------------------------------------------- */

	// Check if getElementsByTagName("*") returns only elements
	support.getElementsByTagName = assert(function( div ) {
		div.appendChild( document.createComment("") );
		return !div.getElementsByTagName("*").length;
	});

	// Support: IE<9
	support.getElementsByClassName = rnative.test( document.getElementsByClassName );

	// Support: IE<10
	// Check if getElementById returns elements by name
	// The broken getElementById methods don't pick up programatically-set names,
	// so use a roundabout getElementsByName test
	support.getById = assert(function( div ) {
		docElem.appendChild( div ).id = expando;
		return !document.getElementsByName || !document.getElementsByName( expando ).length;
	});

	// ID find and filter
	if ( support.getById ) {
		Expr.find["ID"] = function( id, context ) {
			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
				var m = context.getElementById( id );
				return m ? [ m ] : [];
			}
		};
		Expr.filter["ID"] = function( id ) {
			var attrId = id.replace( runescape, funescape );
			return function( elem ) {
				return elem.getAttribute("id") === attrId;
			};
		};
	} else {
		// Support: IE6/7
		// getElementById is not reliable as a find shortcut
		delete Expr.find["ID"];

		Expr.filter["ID"] =  function( id ) {
			var attrId = id.replace( runescape, funescape );
			return function( elem ) {
				var node = typeof elem.getAttributeNode !== "undefined" &&
					elem.getAttributeNode("id");
				return node && node.value === attrId;
			};
		};
	}

	// Tag
	Expr.find["TAG"] = support.getElementsByTagName ?
		function( tag, context ) {
			if ( typeof context.getElementsByTagName !== "undefined" ) {
				return context.getElementsByTagName( tag );

			// DocumentFragment nodes don't have gEBTN
			} else if ( support.qsa ) {
				return context.querySelectorAll( tag );
			}
		} :

		function( tag, context ) {
			var elem,
				tmp = [],
				i = 0,
				// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
				results = context.getElementsByTagName( tag );

			// Filter out possible comments
			if ( tag === "*" ) {
				while ( (elem = results[i++]) ) {
					if ( elem.nodeType === 1 ) {
						tmp.push( elem );
					}
				}

				return tmp;
			}
			return results;
		};

	// Class
	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
		if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
			return context.getElementsByClassName( className );
		}
	};

	/* QSA/matchesSelector
	---------------------------------------------------------------------- */

	// QSA and matchesSelector support

	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
	rbuggyMatches = [];

	// qSa(:focus) reports false when true (Chrome 21)
	// We allow this because of a bug in IE8/9 that throws an error
	// whenever `document.activeElement` is accessed on an iframe
	// So, we allow :focus to pass through QSA all the time to avoid the IE error
	// See http://bugs.jquery.com/ticket/13378
	rbuggyQSA = [];

	if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
		// Build QSA regex
		// Regex strategy adopted from Diego Perini
		assert(function( div ) {
			// Select is set to empty string on purpose
			// This is to test IE's treatment of not explicitly
			// setting a boolean content attribute,
			// since its presence should be enough
			// http://bugs.jquery.com/ticket/12359
			docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
				"<select id='" + expando + "-\r\\' msallowcapture=''>" +
				"<option selected=''></option></select>";

			// Support: IE8, Opera 11-12.16
			// Nothing should be selected when empty strings follow ^= or $= or *=
			// The test attribute must be unknown in Opera but "safe" for WinRT
			// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
			if ( div.querySelectorAll("[msallowcapture^='']").length ) {
				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
			}

			// Support: IE8
			// Boolean attributes and "value" are not treated correctly
			if ( !div.querySelectorAll("[selected]").length ) {
				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
			}

			// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
			if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
				rbuggyQSA.push("~=");
			}

			// Webkit/Opera - :checked should return selected option elements
			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
			// IE8 throws error here and will not see later tests
			if ( !div.querySelectorAll(":checked").length ) {
				rbuggyQSA.push(":checked");
			}

			// Support: Safari 8+, iOS 8+
			// https://bugs.webkit.org/show_bug.cgi?id=136851
			// In-page `selector#id sibing-combinator selector` fails
			if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
				rbuggyQSA.push(".#.+[+~]");
			}
		});

		assert(function( div ) {
			// Support: Windows 8 Native Apps
			// The type and name attributes are restricted during .innerHTML assignment
			var input = document.createElement("input");
			input.setAttribute( "type", "hidden" );
			div.appendChild( input ).setAttribute( "name", "D" );

			// Support: IE8
			// Enforce case-sensitivity of name attribute
			if ( div.querySelectorAll("[name=d]").length ) {
				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
			}

			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
			// IE8 throws error here and will not see later tests
			if ( !div.querySelectorAll(":enabled").length ) {
				rbuggyQSA.push( ":enabled", ":disabled" );
			}

			// Opera 10-11 does not throw on post-comma invalid pseudos
			div.querySelectorAll("*,:x");
			rbuggyQSA.push(",.*:");
		});
	}

	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
		docElem.webkitMatchesSelector ||
		docElem.mozMatchesSelector ||
		docElem.oMatchesSelector ||
		docElem.msMatchesSelector) )) ) {

		assert(function( div ) {
			// Check to see if it's possible to do matchesSelector
			// on a disconnected node (IE 9)
			support.disconnectedMatch = matches.call( div, "div" );

			// This should fail with an exception
			// Gecko does not error, returns false instead
			matches.call( div, "[s!='']:x" );
			rbuggyMatches.push( "!=", pseudos );
		});
	}

	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );

	/* Contains
	---------------------------------------------------------------------- */
	hasCompare = rnative.test( docElem.compareDocumentPosition );

	// Element contains another
	// Purposefully self-exclusive
	// As in, an element does not contain itself
	contains = hasCompare || rnative.test( docElem.contains ) ?
		function( a, b ) {
			var adown = a.nodeType === 9 ? a.documentElement : a,
				bup = b && b.parentNode;
			return a === bup || !!( bup && bup.nodeType === 1 && (
				adown.contains ?
					adown.contains( bup ) :
					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
			));
		} :
		function( a, b ) {
			if ( b ) {
				while ( (b = b.parentNode) ) {
					if ( b === a ) {
						return true;
					}
				}
			}
			return false;
		};

	/* Sorting
	---------------------------------------------------------------------- */

	// Document order sorting
	sortOrder = hasCompare ?
	function( a, b ) {

		// Flag for duplicate removal
		if ( a === b ) {
			hasDuplicate = true;
			return 0;
		}

		// Sort on method existence if only one input has compareDocumentPosition
		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
		if ( compare ) {
			return compare;
		}

		// Calculate position if both inputs belong to the same document
		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
			a.compareDocumentPosition( b ) :

			// Otherwise we know they are disconnected
			1;

		// Disconnected nodes
		if ( compare & 1 ||
			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {

			// Choose the first element that is related to our preferred document
			if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
				return -1;
			}
			if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
				return 1;
			}

			// Maintain original order
			return sortInput ?
				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
				0;
		}

		return compare & 4 ? -1 : 1;
	} :
	function( a, b ) {
		// Exit early if the nodes are identical
		if ( a === b ) {
			hasDuplicate = true;
			return 0;
		}

		var cur,
			i = 0,
			aup = a.parentNode,
			bup = b.parentNode,
			ap = [ a ],
			bp = [ b ];

		// Parentless nodes are either documents or disconnected
		if ( !aup || !bup ) {
			return a === document ? -1 :
				b === document ? 1 :
				aup ? -1 :
				bup ? 1 :
				sortInput ?
				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
				0;

		// If the nodes are siblings, we can do a quick check
		} else if ( aup === bup ) {
			return siblingCheck( a, b );
		}

		// Otherwise we need full lists of their ancestors for comparison
		cur = a;
		while ( (cur = cur.parentNode) ) {
			ap.unshift( cur );
		}
		cur = b;
		while ( (cur = cur.parentNode) ) {
			bp.unshift( cur );
		}

		// Walk down the tree looking for a discrepancy
		while ( ap[i] === bp[i] ) {
			i++;
		}

		return i ?
			// Do a sibling check if the nodes have a common ancestor
			siblingCheck( ap[i], bp[i] ) :

			// Otherwise nodes in our document sort first
			ap[i] === preferredDoc ? -1 :
			bp[i] === preferredDoc ? 1 :
			0;
	};

	return document;
};

Sizzle.matches = function( expr, elements ) {
	return Sizzle( expr, null, null, elements );
};

Sizzle.matchesSelector = function( elem, expr ) {
	// Set document vars if needed
	if ( ( elem.ownerDocument || elem ) !== document ) {
		setDocument( elem );
	}

	// Make sure that attribute selectors are quoted
	expr = expr.replace( rattributeQuotes, "='$1']" );

	if ( support.matchesSelector && documentIsHTML &&
		!compilerCache[ expr + " " ] &&
		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {

		try {
			var ret = matches.call( elem, expr );

			// IE 9's matchesSelector returns false on disconnected nodes
			if ( ret || support.disconnectedMatch ||
					// As well, disconnected nodes are said to be in a document
					// fragment in IE 9
					elem.document && elem.document.nodeType !== 11 ) {
				return ret;
			}
		} catch (e) {}
	}

	return Sizzle( expr, document, null, [ elem ] ).length > 0;
};

Sizzle.contains = function( context, elem ) {
	// Set document vars if needed
	if ( ( context.ownerDocument || context ) !== document ) {
		setDocument( context );
	}
	return contains( context, elem );
};

Sizzle.attr = function( elem, name ) {
	// Set document vars if needed
	if ( ( elem.ownerDocument || elem ) !== document ) {
		setDocument( elem );
	}

	var fn = Expr.attrHandle[ name.toLowerCase() ],
		// Don't get fooled by Object.prototype properties (jQuery #13807)
		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
			fn( elem, name, !documentIsHTML ) :
			undefined;

	return val !== undefined ?
		val :
		support.attributes || !documentIsHTML ?
			elem.getAttribute( name ) :
			(val = elem.getAttributeNode(name)) && val.specified ?
				val.value :
				null;
};

Sizzle.error = function( msg ) {
	throw new Error( "Syntax error, unrecognized expression: " + msg );
};

/**
 * Document sorting and removing duplicates
 * @param {ArrayLike} results
 */
Sizzle.uniqueSort = function( results ) {
	var elem,
		duplicates = [],
		j = 0,
		i = 0;

	// Unless we *know* we can detect duplicates, assume their presence
	hasDuplicate = !support.detectDuplicates;
	sortInput = !support.sortStable && results.slice( 0 );
	results.sort( sortOrder );

	if ( hasDuplicate ) {
		while ( (elem = results[i++]) ) {
			if ( elem === results[ i ] ) {
				j = duplicates.push( i );
			}
		}
		while ( j-- ) {
			results.splice( duplicates[ j ], 1 );
		}
	}

	// Clear input after sorting to release objects
	// See https://github.com/jquery/sizzle/pull/225
	sortInput = null;

	return results;
};

/**
 * Utility function for retrieving the text value of an array of DOM nodes
 * @param {Array|Element} elem
 */
getText = Sizzle.getText = function( elem ) {
	var node,
		ret = "",
		i = 0,
		nodeType = elem.nodeType;

	if ( !nodeType ) {
		// If no nodeType, this is expected to be an array
		while ( (node = elem[i++]) ) {
			// Do not traverse comment nodes
			ret += getText( node );
		}
	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
		// Use textContent for elements
		// innerText usage removed for consistency of new lines (jQuery #11153)
		if ( typeof elem.textContent === "string" ) {
			return elem.textContent;
		} else {
			// Traverse its children
			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
				ret += getText( elem );
			}
		}
	} else if ( nodeType === 3 || nodeType === 4 ) {
		return elem.nodeValue;
	}
	// Do not include comment or processing instruction nodes

	return ret;
};

Expr = Sizzle.selectors = {

	// Can be adjusted by the user
	cacheLength: 50,

	createPseudo: markFunction,

	match: matchExpr,

	attrHandle: {},

	find: {},

	relative: {
		">": { dir: "parentNode", first: true },
		" ": { dir: "parentNode" },
		"+": { dir: "previousSibling", first: true },
		"~": { dir: "previousSibling" }
	},

	preFilter: {
		"ATTR": function( match ) {
			match[1] = match[1].replace( runescape, funescape );

			// Move the given value to match[3] whether quoted or unquoted
			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );

			if ( match[2] === "~=" ) {
				match[3] = " " + match[3] + " ";
			}

			return match.slice( 0, 4 );
		},

		"CHILD": function( match ) {
			/* matches from matchExpr["CHILD"]
				1 type (only|nth|...)
				2 what (child|of-type)
				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
				4 xn-component of xn+y argument ([+-]?\d*n|)
				5 sign of xn-component
				6 x of xn-component
				7 sign of y-component
				8 y of y-component
			*/
			match[1] = match[1].toLowerCase();

			if ( match[1].slice( 0, 3 ) === "nth" ) {
				// nth-* requires argument
				if ( !match[3] ) {
					Sizzle.error( match[0] );
				}

				// numeric x and y parameters for Expr.filter.CHILD
				// remember that false/true cast respectively to 0/1
				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );

			// other types prohibit arguments
			} else if ( match[3] ) {
				Sizzle.error( match[0] );
			}

			return match;
		},

		"PSEUDO": function( match ) {
			var excess,
				unquoted = !match[6] && match[2];

			if ( matchExpr["CHILD"].test( match[0] ) ) {
				return null;
			}

			// Accept quoted arguments as-is
			if ( match[3] ) {
				match[2] = match[4] || match[5] || "";

			// Strip excess characters from unquoted arguments
			} else if ( unquoted && rpseudo.test( unquoted ) &&
				// Get excess from tokenize (recursively)
				(excess = tokenize( unquoted, true )) &&
				// advance to the next closing parenthesis
				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {

				// excess is a negative index
				match[0] = match[0].slice( 0, excess );
				match[2] = unquoted.slice( 0, excess );
			}

			// Return only captures needed by the pseudo filter method (type and argument)
			return match.slice( 0, 3 );
		}
	},

	filter: {

		"TAG": function( nodeNameSelector ) {
			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
			return nodeNameSelector === "*" ?
				function() { return true; } :
				function( elem ) {
					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
				};
		},

		"CLASS": function( className ) {
			var pattern = classCache[ className + " " ];

			return pattern ||
				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
				classCache( className, function( elem ) {
					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
				});
		},

		"ATTR": function( name, operator, check ) {
			return function( elem ) {
				var result = Sizzle.attr( elem, name );

				if ( result == null ) {
					return operator === "!=";
				}
				if ( !operator ) {
					return true;
				}

				result += "";

				return operator === "=" ? result === check :
					operator === "!=" ? result !== check :
					operator === "^=" ? check && result.indexOf( check ) === 0 :
					operator === "*=" ? check && result.indexOf( check ) > -1 :
					operator === "$=" ? check && result.slice( -check.length ) === check :
					operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
					false;
			};
		},

		"CHILD": function( type, what, argument, first, last ) {
			var simple = type.slice( 0, 3 ) !== "nth",
				forward = type.slice( -4 ) !== "last",
				ofType = what === "of-type";

			return first === 1 && last === 0 ?

				// Shortcut for :nth-*(n)
				function( elem ) {
					return !!elem.parentNode;
				} :

				function( elem, context, xml ) {
					var cache, uniqueCache, outerCache, node, nodeIndex, start,
						dir = simple !== forward ? "nextSibling" : "previousSibling",
						parent = elem.parentNode,
						name = ofType && elem.nodeName.toLowerCase(),
						useCache = !xml && !ofType,
						diff = false;

					if ( parent ) {

						// :(first|last|only)-(child|of-type)
						if ( simple ) {
							while ( dir ) {
								node = elem;
								while ( (node = node[ dir ]) ) {
									if ( ofType ?
										node.nodeName.toLowerCase() === name :
										node.nodeType === 1 ) {

										return false;
									}
								}
								// Reverse direction for :only-* (if we haven't yet done so)
								start = dir = type === "only" && !start && "nextSibling";
							}
							return true;
						}

						start = [ forward ? parent.firstChild : parent.lastChild ];

						// non-xml :nth-child(...) stores cache data on `parent`
						if ( forward && useCache ) {

							// Seek `elem` from a previously-cached index

							// ...in a gzip-friendly way
							node = parent;
							outerCache = node[ expando ] || (node[ expando ] = {});

							// Support: IE <9 only
							// Defend against cloned attroperties (jQuery gh-1709)
							uniqueCache = outerCache[ node.uniqueID ] ||
								(outerCache[ node.uniqueID ] = {});

							cache = uniqueCache[ type ] || [];
							nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
							diff = nodeIndex && cache[ 2 ];
							node = nodeIndex && parent.childNodes[ nodeIndex ];

							while ( (node = ++nodeIndex && node && node[ dir ] ||

								// Fallback to seeking `elem` from the start
								(diff = nodeIndex = 0) || start.pop()) ) {

								// When found, cache indexes on `parent` and break
								if ( node.nodeType === 1 && ++diff && node === elem ) {
									uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
									break;
								}
							}

						} else {
							// Use previously-cached element index if available
							if ( useCache ) {
								// ...in a gzip-friendly way
								node = elem;
								outerCache = node[ expando ] || (node[ expando ] = {});

								// Support: IE <9 only
								// Defend against cloned attroperties (jQuery gh-1709)
								uniqueCache = outerCache[ node.uniqueID ] ||
									(outerCache[ node.uniqueID ] = {});

								cache = uniqueCache[ type ] || [];
								nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
								diff = nodeIndex;
							}

							// xml :nth-child(...)
							// or :nth-last-child(...) or :nth(-last)?-of-type(...)
							if ( diff === false ) {
								// Use the same loop as above to seek `elem` from the start
								while ( (node = ++nodeIndex && node && node[ dir ] ||
									(diff = nodeIndex = 0) || start.pop()) ) {

									if ( ( ofType ?
										node.nodeName.toLowerCase() === name :
										node.nodeType === 1 ) &&
										++diff ) {

										// Cache the index of each encountered element
										if ( useCache ) {
											outerCache = node[ expando ] || (node[ expando ] = {});

											// Support: IE <9 only
											// Defend against cloned attroperties (jQuery gh-1709)
											uniqueCache = outerCache[ node.uniqueID ] ||
												(outerCache[ node.uniqueID ] = {});

											uniqueCache[ type ] = [ dirruns, diff ];
										}

										if ( node === elem ) {
											break;
										}
									}
								}
							}
						}

						// Incorporate the offset, then check against cycle size
						diff -= last;
						return diff === first || ( diff % first === 0 && diff / first >= 0 );
					}
				};
		},

		"PSEUDO": function( pseudo, argument ) {
			// pseudo-class names are case-insensitive
			// http://www.w3.org/TR/selectors/#pseudo-classes
			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
			// Remember that setFilters inherits from pseudos
			var args,
				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
					Sizzle.error( "unsupported pseudo: " + pseudo );

			// The user may use createPseudo to indicate that
			// arguments are needed to create the filter function
			// just as Sizzle does
			if ( fn[ expando ] ) {
				return fn( argument );
			}

			// But maintain support for old signatures
			if ( fn.length > 1 ) {
				args = [ pseudo, pseudo, "", argument ];
				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
					markFunction(function( seed, matches ) {
						var idx,
							matched = fn( seed, argument ),
							i = matched.length;
						while ( i-- ) {
							idx = indexOf( seed, matched[i] );
							seed[ idx ] = !( matches[ idx ] = matched[i] );
						}
					}) :
					function( elem ) {
						return fn( elem, 0, args );
					};
			}

			return fn;
		}
	},

	pseudos: {
		// Potentially complex pseudos
		"not": markFunction(function( selector ) {
			// Trim the selector passed to compile
			// to avoid treating leading and trailing
			// spaces as combinators
			var input = [],
				results = [],
				matcher = compile( selector.replace( rtrim, "$1" ) );

			return matcher[ expando ] ?
				markFunction(function( seed, matches, context, xml ) {
					var elem,
						unmatched = matcher( seed, null, xml, [] ),
						i = seed.length;

					// Match elements unmatched by `matcher`
					while ( i-- ) {
						if ( (elem = unmatched[i]) ) {
							seed[i] = !(matches[i] = elem);
						}
					}
				}) :
				function( elem, context, xml ) {
					input[0] = elem;
					matcher( input, null, xml, results );
					// Don't keep the element (issue #299)
					input[0] = null;
					return !results.pop();
				};
		}),

		"has": markFunction(function( selector ) {
			return function( elem ) {
				return Sizzle( selector, elem ).length > 0;
			};
		}),

		"contains": markFunction(function( text ) {
			text = text.replace( runescape, funescape );
			return function( elem ) {
				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
			};
		}),

		// "Whether an element is represented by a :lang() selector
		// is based solely on the element's language value
		// being equal to the identifier C,
		// or beginning with the identifier C immediately followed by "-".
		// The matching of C against the element's language value is performed case-insensitively.
		// The identifier C does not have to be a valid language name."
		// http://www.w3.org/TR/selectors/#lang-pseudo
		"lang": markFunction( function( lang ) {
			// lang value must be a valid identifier
			if ( !ridentifier.test(lang || "") ) {
				Sizzle.error( "unsupported lang: " + lang );
			}
			lang = lang.replace( runescape, funescape ).toLowerCase();
			return function( elem ) {
				var elemLang;
				do {
					if ( (elemLang = documentIsHTML ?
						elem.lang :
						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {

						elemLang = elemLang.toLowerCase();
						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
					}
				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
				return false;
			};
		}),

		// Miscellaneous
		"target": function( elem ) {
			var hash = window.location && window.location.hash;
			return hash && hash.slice( 1 ) === elem.id;
		},

		"root": function( elem ) {
			return elem === docElem;
		},

		"focus": function( elem ) {
			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
		},

		// Boolean properties
		"enabled": function( elem ) {
			return elem.disabled === false;
		},

		"disabled": function( elem ) {
			return elem.disabled === true;
		},

		"checked": function( elem ) {
			// In CSS3, :checked should return both checked and selected elements
			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
			var nodeName = elem.nodeName.toLowerCase();
			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
		},

		"selected": function( elem ) {
			// Accessing this property makes selected-by-default
			// options in Safari work properly
			if ( elem.parentNode ) {
				elem.parentNode.selectedIndex;
			}

			return elem.selected === true;
		},

		// Contents
		"empty": function( elem ) {
			// http://www.w3.org/TR/selectors/#empty-pseudo
			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
			//   but not by others (comment: 8; processing instruction: 7; etc.)
			// nodeType < 6 works because attributes (2) do not appear as children
			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
				if ( elem.nodeType < 6 ) {
					return false;
				}
			}
			return true;
		},

		"parent": function( elem ) {
			return !Expr.pseudos["empty"]( elem );
		},

		// Element/input types
		"header": function( elem ) {
			return rheader.test( elem.nodeName );
		},

		"input": function( elem ) {
			return rinputs.test( elem.nodeName );
		},

		"button": function( elem ) {
			var name = elem.nodeName.toLowerCase();
			return name === "input" && elem.type === "button" || name === "button";
		},

		"text": function( elem ) {
			var attr;
			return elem.nodeName.toLowerCase() === "input" &&
				elem.type === "text" &&

				// Support: IE<8
				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
		},

		// Position-in-collection
		"first": createPositionalPseudo(function() {
			return [ 0 ];
		}),

		"last": createPositionalPseudo(function( matchIndexes, length ) {
			return [ length - 1 ];
		}),

		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
			return [ argument < 0 ? argument + length : argument ];
		}),

		"even": createPositionalPseudo(function( matchIndexes, length ) {
			var i = 0;
			for ( ; i < length; i += 2 ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		}),

		"odd": createPositionalPseudo(function( matchIndexes, length ) {
			var i = 1;
			for ( ; i < length; i += 2 ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		}),

		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
			var i = argument < 0 ? argument + length : argument;
			for ( ; --i >= 0; ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		}),

		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
			var i = argument < 0 ? argument + length : argument;
			for ( ; ++i < length; ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		})
	}
};

Expr.pseudos["nth"] = Expr.pseudos["eq"];

// Add button/input type pseudos
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
	Expr.pseudos[ i ] = createInputPseudo( i );
}
for ( i in { submit: true, reset: true } ) {
	Expr.pseudos[ i ] = createButtonPseudo( i );
}

// Easy API for creating new setFilters
function setFilters() {}
setFilters.prototype = Expr.filters = Expr.pseudos;
Expr.setFilters = new setFilters();

tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
	var matched, match, tokens, type,
		soFar, groups, preFilters,
		cached = tokenCache[ selector + " " ];

	if ( cached ) {
		return parseOnly ? 0 : cached.slice( 0 );
	}

	soFar = selector;
	groups = [];
	preFilters = Expr.preFilter;

	while ( soFar ) {

		// Comma and first run
		if ( !matched || (match = rcomma.exec( soFar )) ) {
			if ( match ) {
				// Don't consume trailing commas as valid
				soFar = soFar.slice( match[0].length ) || soFar;
			}
			groups.push( (tokens = []) );
		}

		matched = false;

		// Combinators
		if ( (match = rcombinators.exec( soFar )) ) {
			matched = match.shift();
			tokens.push({
				value: matched,
				// Cast descendant combinators to space
				type: match[0].replace( rtrim, " " )
			});
			soFar = soFar.slice( matched.length );
		}

		// Filters
		for ( type in Expr.filter ) {
			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
				(match = preFilters[ type ]( match ))) ) {
				matched = match.shift();
				tokens.push({
					value: matched,
					type: type,
					matches: match
				});
				soFar = soFar.slice( matched.length );
			}
		}

		if ( !matched ) {
			break;
		}
	}

	// Return the length of the invalid excess
	// if we're just parsing
	// Otherwise, throw an error or return tokens
	return parseOnly ?
		soFar.length :
		soFar ?
			Sizzle.error( selector ) :
			// Cache the tokens
			tokenCache( selector, groups ).slice( 0 );
};

function toSelector( tokens ) {
	var i = 0,
		len = tokens.length,
		selector = "";
	for ( ; i < len; i++ ) {
		selector += tokens[i].value;
	}
	return selector;
}

function addCombinator( matcher, combinator, base ) {
	var dir = combinator.dir,
		checkNonElements = base && dir === "parentNode",
		doneName = done++;

	return combinator.first ?
		// Check against closest ancestor/preceding element
		function( elem, context, xml ) {
			while ( (elem = elem[ dir ]) ) {
				if ( elem.nodeType === 1 || checkNonElements ) {
					return matcher( elem, context, xml );
				}
			}
		} :

		// Check against all ancestor/preceding elements
		function( elem, context, xml ) {
			var oldCache, uniqueCache, outerCache,
				newCache = [ dirruns, doneName ];

			// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
			if ( xml ) {
				while ( (elem = elem[ dir ]) ) {
					if ( elem.nodeType === 1 || checkNonElements ) {
						if ( matcher( elem, context, xml ) ) {
							return true;
						}
					}
				}
			} else {
				while ( (elem = elem[ dir ]) ) {
					if ( elem.nodeType === 1 || checkNonElements ) {
						outerCache = elem[ expando ] || (elem[ expando ] = {});

						// Support: IE <9 only
						// Defend against cloned attroperties (jQuery gh-1709)
						uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});

						if ( (oldCache = uniqueCache[ dir ]) &&
							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {

							// Assign to newCache so results back-propagate to previous elements
							return (newCache[ 2 ] = oldCache[ 2 ]);
						} else {
							// Reuse newcache so results back-propagate to previous elements
							uniqueCache[ dir ] = newCache;

							// A match means we're done; a fail means we have to keep checking
							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
								return true;
							}
						}
					}
				}
			}
		};
}

function elementMatcher( matchers ) {
	return matchers.length > 1 ?
		function( elem, context, xml ) {
			var i = matchers.length;
			while ( i-- ) {
				if ( !matchers[i]( elem, context, xml ) ) {
					return false;
				}
			}
			return true;
		} :
		matchers[0];
}

function multipleContexts( selector, contexts, results ) {
	var i = 0,
		len = contexts.length;
	for ( ; i < len; i++ ) {
		Sizzle( selector, contexts[i], results );
	}
	return results;
}

function condense( unmatched, map, filter, context, xml ) {
	var elem,
		newUnmatched = [],
		i = 0,
		len = unmatched.length,
		mapped = map != null;

	for ( ; i < len; i++ ) {
		if ( (elem = unmatched[i]) ) {
			if ( !filter || filter( elem, context, xml ) ) {
				newUnmatched.push( elem );
				if ( mapped ) {
					map.push( i );
				}
			}
		}
	}

	return newUnmatched;
}

function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
	if ( postFilter && !postFilter[ expando ] ) {
		postFilter = setMatcher( postFilter );
	}
	if ( postFinder && !postFinder[ expando ] ) {
		postFinder = setMatcher( postFinder, postSelector );
	}
	return markFunction(function( seed, results, context, xml ) {
		var temp, i, elem,
			preMap = [],
			postMap = [],
			preexisting = results.length,

			// Get initial elements from seed or context
			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),

			// Prefilter to get matcher input, preserving a map for seed-results synchronization
			matcherIn = preFilter && ( seed || !selector ) ?
				condense( elems, preMap, preFilter, context, xml ) :
				elems,

			matcherOut = matcher ?
				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?

					// ...intermediate processing is necessary
					[] :

					// ...otherwise use results directly
					results :
				matcherIn;

		// Find primary matches
		if ( matcher ) {
			matcher( matcherIn, matcherOut, context, xml );
		}

		// Apply postFilter
		if ( postFilter ) {
			temp = condense( matcherOut, postMap );
			postFilter( temp, [], context, xml );

			// Un-match failing elements by moving them back to matcherIn
			i = temp.length;
			while ( i-- ) {
				if ( (elem = temp[i]) ) {
					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
				}
			}
		}

		if ( seed ) {
			if ( postFinder || preFilter ) {
				if ( postFinder ) {
					// Get the final matcherOut by condensing this intermediate into postFinder contexts
					temp = [];
					i = matcherOut.length;
					while ( i-- ) {
						if ( (elem = matcherOut[i]) ) {
							// Restore matcherIn since elem is not yet a final match
							temp.push( (matcherIn[i] = elem) );
						}
					}
					postFinder( null, (matcherOut = []), temp, xml );
				}

				// Move matched elements from seed to results to keep them synchronized
				i = matcherOut.length;
				while ( i-- ) {
					if ( (elem = matcherOut[i]) &&
						(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {

						seed[temp] = !(results[temp] = elem);
					}
				}
			}

		// Add elements to results, through postFinder if defined
		} else {
			matcherOut = condense(
				matcherOut === results ?
					matcherOut.splice( preexisting, matcherOut.length ) :
					matcherOut
			);
			if ( postFinder ) {
				postFinder( null, results, matcherOut, xml );
			} else {
				push.apply( results, matcherOut );
			}
		}
	});
}

function matcherFromTokens( tokens ) {
	var checkContext, matcher, j,
		len = tokens.length,
		leadingRelative = Expr.relative[ tokens[0].type ],
		implicitRelative = leadingRelative || Expr.relative[" "],
		i = leadingRelative ? 1 : 0,

		// The foundational matcher ensures that elements are reachable from top-level context(s)
		matchContext = addCombinator( function( elem ) {
			return elem === checkContext;
		}, implicitRelative, true ),
		matchAnyContext = addCombinator( function( elem ) {
			return indexOf( checkContext, elem ) > -1;
		}, implicitRelative, true ),
		matchers = [ function( elem, context, xml ) {
			var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
				(checkContext = context).nodeType ?
					matchContext( elem, context, xml ) :
					matchAnyContext( elem, context, xml ) );
			// Avoid hanging onto element (issue #299)
			checkContext = null;
			return ret;
		} ];

	for ( ; i < len; i++ ) {
		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
		} else {
			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );

			// Return special upon seeing a positional matcher
			if ( matcher[ expando ] ) {
				// Find the next relative operator (if any) for proper handling
				j = ++i;
				for ( ; j < len; j++ ) {
					if ( Expr.relative[ tokens[j].type ] ) {
						break;
					}
				}
				return setMatcher(
					i > 1 && elementMatcher( matchers ),
					i > 1 && toSelector(
						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
					).replace( rtrim, "$1" ),
					matcher,
					i < j && matcherFromTokens( tokens.slice( i, j ) ),
					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
					j < len && toSelector( tokens )
				);
			}
			matchers.push( matcher );
		}
	}

	return elementMatcher( matchers );
}

function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
	var bySet = setMatchers.length > 0,
		byElement = elementMatchers.length > 0,
		superMatcher = function( seed, context, xml, results, outermost ) {
			var elem, j, matcher,
				matchedCount = 0,
				i = "0",
				unmatched = seed && [],
				setMatched = [],
				contextBackup = outermostContext,
				// We must always have either seed elements or outermost context
				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
				// Use integer dirruns iff this is the outermost matcher
				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
				len = elems.length;

			if ( outermost ) {
				outermostContext = context === document || context || outermost;
			}

			// Add elements passing elementMatchers directly to results
			// Support: IE<9, Safari
			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
				if ( byElement && elem ) {
					j = 0;
					if ( !context && elem.ownerDocument !== document ) {
						setDocument( elem );
						xml = !documentIsHTML;
					}
					while ( (matcher = elementMatchers[j++]) ) {
						if ( matcher( elem, context || document, xml) ) {
							results.push( elem );
							break;
						}
					}
					if ( outermost ) {
						dirruns = dirrunsUnique;
					}
				}

				// Track unmatched elements for set filters
				if ( bySet ) {
					// They will have gone through all possible matchers
					if ( (elem = !matcher && elem) ) {
						matchedCount--;
					}

					// Lengthen the array for every element, matched or not
					if ( seed ) {
						unmatched.push( elem );
					}
				}
			}

			// `i` is now the count of elements visited above, and adding it to `matchedCount`
			// makes the latter nonnegative.
			matchedCount += i;

			// Apply set filters to unmatched elements
			// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
			// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
			// no element matchers and no seed.
			// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
			// case, which will result in a "00" `matchedCount` that differs from `i` but is also
			// numerically zero.
			if ( bySet && i !== matchedCount ) {
				j = 0;
				while ( (matcher = setMatchers[j++]) ) {
					matcher( unmatched, setMatched, context, xml );
				}

				if ( seed ) {
					// Reintegrate element matches to eliminate the need for sorting
					if ( matchedCount > 0 ) {
						while ( i-- ) {
							if ( !(unmatched[i] || setMatched[i]) ) {
								setMatched[i] = pop.call( results );
							}
						}
					}

					// Discard index placeholder values to get only actual matches
					setMatched = condense( setMatched );
				}

				// Add matches to results
				push.apply( results, setMatched );

				// Seedless set matches succeeding multiple successful matchers stipulate sorting
				if ( outermost && !seed && setMatched.length > 0 &&
					( matchedCount + setMatchers.length ) > 1 ) {

					Sizzle.uniqueSort( results );
				}
			}

			// Override manipulation of globals by nested matchers
			if ( outermost ) {
				dirruns = dirrunsUnique;
				outermostContext = contextBackup;
			}

			return unmatched;
		};

	return bySet ?
		markFunction( superMatcher ) :
		superMatcher;
}

compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
	var i,
		setMatchers = [],
		elementMatchers = [],
		cached = compilerCache[ selector + " " ];

	if ( !cached ) {
		// Generate a function of recursive functions that can be used to check each element
		if ( !match ) {
			match = tokenize( selector );
		}
		i = match.length;
		while ( i-- ) {
			cached = matcherFromTokens( match[i] );
			if ( cached[ expando ] ) {
				setMatchers.push( cached );
			} else {
				elementMatchers.push( cached );
			}
		}

		// Cache the compiled function
		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );

		// Save selector and tokenization
		cached.selector = selector;
	}
	return cached;
};

/**
 * A low-level selection function that works with Sizzle's compiled
 *  selector functions
 * @param {String|Function} selector A selector or a pre-compiled
 *  selector function built with Sizzle.compile
 * @param {Element} context
 * @param {Array} [results]
 * @param {Array} [seed] A set of elements to match against
 */
select = Sizzle.select = function( selector, context, results, seed ) {
	var i, tokens, token, type, find,
		compiled = typeof selector === "function" && selector,
		match = !seed && tokenize( (selector = compiled.selector || selector) );

	results = results || [];

	// Try to minimize operations if there is only one selector in the list and no seed
	// (the latter of which guarantees us context)
	if ( match.length === 1 ) {

		// Reduce context if the leading compound selector is an ID
		tokens = match[0] = match[0].slice( 0 );
		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
				support.getById && context.nodeType === 9 && documentIsHTML &&
				Expr.relative[ tokens[1].type ] ) {

			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
			if ( !context ) {
				return results;

			// Precompiled matchers will still verify ancestry, so step up a level
			} else if ( compiled ) {
				context = context.parentNode;
			}

			selector = selector.slice( tokens.shift().value.length );
		}

		// Fetch a seed set for right-to-left matching
		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
		while ( i-- ) {
			token = tokens[i];

			// Abort if we hit a combinator
			if ( Expr.relative[ (type = token.type) ] ) {
				break;
			}
			if ( (find = Expr.find[ type ]) ) {
				// Search, expanding context for leading sibling combinators
				if ( (seed = find(
					token.matches[0].replace( runescape, funescape ),
					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
				)) ) {

					// If seed is empty or no tokens remain, we can return early
					tokens.splice( i, 1 );
					selector = seed.length && toSelector( tokens );
					if ( !selector ) {
						push.apply( results, seed );
						return results;
					}

					break;
				}
			}
		}
	}

	// Compile and execute a filtering function if one is not provided
	// Provide `match` to avoid retokenization if we modified the selector above
	( compiled || compile( selector, match ) )(
		seed,
		context,
		!documentIsHTML,
		results,
		!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
	);
	return results;
};

// One-time assignments

// Sort stability
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;

// Support: Chrome 14-35+
// Always assume duplicates if they aren't passed to the comparison function
support.detectDuplicates = !!hasDuplicate;

// Initialize against the default document
setDocument();

// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
// Detached nodes confoundingly follow *each other*
support.sortDetached = assert(function( div1 ) {
	// Should return 1, but returns 4 (following)
	return div1.compareDocumentPosition( document.createElement("div") ) & 1;
});

// Support: IE<8
// Prevent attribute/property "interpolation"
// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
if ( !assert(function( div ) {
	div.innerHTML = "<a href='#'></a>";
	return div.firstChild.getAttribute("href") === "#" ;
}) ) {
	addHandle( "type|href|height|width", function( elem, name, isXML ) {
		if ( !isXML ) {
			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
		}
	});
}

// Support: IE<9
// Use defaultValue in place of getAttribute("value")
if ( !support.attributes || !assert(function( div ) {
	div.innerHTML = "<input/>";
	div.firstChild.setAttribute( "value", "" );
	return div.firstChild.getAttribute( "value" ) === "";
}) ) {
	addHandle( "value", function( elem, name, isXML ) {
		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
			return elem.defaultValue;
		}
	});
}

// Support: IE<9
// Use getAttributeNode to fetch booleans when getAttribute lies
if ( !assert(function( div ) {
	return div.getAttribute("disabled") == null;
}) ) {
	addHandle( booleans, function( elem, name, isXML ) {
		var val;
		if ( !isXML ) {
			return elem[ name ] === true ? name.toLowerCase() :
					(val = elem.getAttributeNode( name )) && val.specified ?
					val.value :
				null;
		}
	});
}

return Sizzle;

})( window );



jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;



var dir = function( elem, dir, until ) {
	var matched = [],
		truncate = until !== undefined;

	while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
		if ( elem.nodeType === 1 ) {
			if ( truncate && jQuery( elem ).is( until ) ) {
				break;
			}
			matched.push( elem );
		}
	}
	return matched;
};


var siblings = function( n, elem ) {
	var matched = [];

	for ( ; n; n = n.nextSibling ) {
		if ( n.nodeType === 1 && n !== elem ) {
			matched.push( n );
		}
	}

	return matched;
};


var rneedsContext = jQuery.expr.match.needsContext;

var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ );



var risSimple = /^.[^:#\[\.,]*$/;

// Implement the identical functionality for filter and not
function winnow( elements, qualifier, not ) {
	if ( jQuery.isFunction( qualifier ) ) {
		return jQuery.grep( elements, function( elem, i ) {
			/* jshint -W018 */
			return !!qualifier.call( elem, i, elem ) !== not;
		} );

	}

	if ( qualifier.nodeType ) {
		return jQuery.grep( elements, function( elem ) {
			return ( elem === qualifier ) !== not;
		} );

	}

	if ( typeof qualifier === "string" ) {
		if ( risSimple.test( qualifier ) ) {
			return jQuery.filter( qualifier, elements, not );
		}

		qualifier = jQuery.filter( qualifier, elements );
	}

	return jQuery.grep( elements, function( elem ) {
		return ( jQuery.inArray( elem, qualifier ) > -1 ) !== not;
	} );
}

jQuery.filter = function( expr, elems, not ) {
	var elem = elems[ 0 ];

	if ( not ) {
		expr = ":not(" + expr + ")";
	}

	return elems.length === 1 && elem.nodeType === 1 ?
		jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
		jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
			return elem.nodeType === 1;
		} ) );
};

jQuery.fn.extend( {
	find: function( selector ) {
		var i,
			ret = [],
			self = this,
			len = self.length;

		if ( typeof selector !== "string" ) {
			return this.pushStack( jQuery( selector ).filter( function() {
				for ( i = 0; i < len; i++ ) {
					if ( jQuery.contains( self[ i ], this ) ) {
						return true;
					}
				}
			} ) );
		}

		for ( i = 0; i < len; i++ ) {
			jQuery.find( selector, self[ i ], ret );
		}

		// Needed because $( selector, context ) becomes $( context ).find( selector )
		ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
		ret.selector = this.selector ? this.selector + " " + selector : selector;
		return ret;
	},
	filter: function( selector ) {
		return this.pushStack( winnow( this, selector || [], false ) );
	},
	not: function( selector ) {
		return this.pushStack( winnow( this, selector || [], true ) );
	},
	is: function( selector ) {
		return !!winnow(
			this,

			// If this is a positional/relative selector, check membership in the returned set
			// so $("p:first").is("p:last") won't return true for a doc with two "p".
			typeof selector === "string" && rneedsContext.test( selector ) ?
				jQuery( selector ) :
				selector || [],
			false
		).length;
	}
} );


// Initialize a jQuery object


// A central reference to the root jQuery(document)
var rootjQuery,

	// A simple way to check for HTML strings
	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
	// Strict HTML recognition (#11290: must start with <)
	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

	init = jQuery.fn.init = function( selector, context, root ) {
		var match, elem;

		// HANDLE: $(""), $(null), $(undefined), $(false)
		if ( !selector ) {
			return this;
		}

		// init accepts an alternate rootjQuery
		// so migrate can support jQuery.sub (gh-2101)
		root = root || rootjQuery;

		// Handle HTML strings
		if ( typeof selector === "string" ) {
			if ( selector.charAt( 0 ) === "<" &&
				selector.charAt( selector.length - 1 ) === ">" &&
				selector.length >= 3 ) {

				// Assume that strings that start and end with <> are HTML and skip the regex check
				match = [ null, selector, null ];

			} else {
				match = rquickExpr.exec( selector );
			}

			// Match html or make sure no context is specified for #id
			if ( match && ( match[ 1 ] || !context ) ) {

				// HANDLE: $(html) -> $(array)
				if ( match[ 1 ] ) {
					context = context instanceof jQuery ? context[ 0 ] : context;

					// scripts is true for back-compat
					// Intentionally let the error be thrown if parseHTML is not present
					jQuery.merge( this, jQuery.parseHTML(
						match[ 1 ],
						context && context.nodeType ? context.ownerDocument || context : document,
						true
					) );

					// HANDLE: $(html, props)
					if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
						for ( match in context ) {

							// Properties of context are called as methods if possible
							if ( jQuery.isFunction( this[ match ] ) ) {
								this[ match ]( context[ match ] );

							// ...and otherwise set as attributes
							} else {
								this.attr( match, context[ match ] );
							}
						}
					}

					return this;

				// HANDLE: $(#id)
				} else {
					elem = document.getElementById( match[ 2 ] );

					// Check parentNode to catch when Blackberry 4.6 returns
					// nodes that are no longer in the document #6963
					if ( elem && elem.parentNode ) {

						// Handle the case where IE and Opera return items
						// by name instead of ID
						if ( elem.id !== match[ 2 ] ) {
							return rootjQuery.find( selector );
						}

						// Otherwise, we inject the element directly into the jQuery object
						this.length = 1;
						this[ 0 ] = elem;
					}

					this.context = document;
					this.selector = selector;
					return this;
				}

			// HANDLE: $(expr, $(...))
			} else if ( !context || context.jquery ) {
				return ( context || root ).find( selector );

			// HANDLE: $(expr, context)
			// (which is just equivalent to: $(context).find(expr)
			} else {
				return this.constructor( context ).find( selector );
			}

		// HANDLE: $(DOMElement)
		} else if ( selector.nodeType ) {
			this.context = this[ 0 ] = selector;
			this.length = 1;
			return this;

		// HANDLE: $(function)
		// Shortcut for document ready
		} else if ( jQuery.isFunction( selector ) ) {
			return typeof root.ready !== "undefined" ?
				root.ready( selector ) :

				// Execute immediately if ready is not present
				selector( jQuery );
		}

		if ( selector.selector !== undefined ) {
			this.selector = selector.selector;
			this.context = selector.context;
		}

		return jQuery.makeArray( selector, this );
	};

// Give the init function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;

// Initialize central reference
rootjQuery = jQuery( document );


var rparentsprev = /^(?:parents|prev(?:Until|All))/,

	// methods guaranteed to produce a unique set when starting from a unique set
	guaranteedUnique = {
		children: true,
		contents: true,
		next: true,
		prev: true
	};

jQuery.fn.extend( {
	has: function( target ) {
		var i,
			targets = jQuery( target, this ),
			len = targets.length;

		return this.filter( function() {
			for ( i = 0; i < len; i++ ) {
				if ( jQuery.contains( this, targets[ i ] ) ) {
					return true;
				}
			}
		} );
	},

	closest: function( selectors, context ) {
		var cur,
			i = 0,
			l = this.length,
			matched = [],
			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
				jQuery( selectors, context || this.context ) :
				0;

		for ( ; i < l; i++ ) {
			for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {

				// Always skip document fragments
				if ( cur.nodeType < 11 && ( pos ?
					pos.index( cur ) > -1 :

					// Don't pass non-elements to Sizzle
					cur.nodeType === 1 &&
						jQuery.find.matchesSelector( cur, selectors ) ) ) {

					matched.push( cur );
					break;
				}
			}
		}

		return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {

		// No argument, return index in parent
		if ( !elem ) {
			return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
		}

		// index in selector
		if ( typeof elem === "string" ) {
			return jQuery.inArray( this[ 0 ], jQuery( elem ) );
		}

		// Locate the position of the desired element
		return jQuery.inArray(

			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[ 0 ] : elem, this );
	},

	add: function( selector, context ) {
		return this.pushStack(
			jQuery.uniqueSort(
				jQuery.merge( this.get(), jQuery( selector, context ) )
			)
		);
	},

	addBack: function( selector ) {
		return this.add( selector == null ?
			this.prevObject : this.prevObject.filter( selector )
		);
	}
} );

function sibling( cur, dir ) {
	do {
		cur = cur[ dir ];
	} while ( cur && cur.nodeType !== 1 );

	return cur;
}

jQuery.each( {
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	parents: function( elem ) {
		return dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, i, until ) {
		return dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return sibling( elem, "nextSibling" );
	},
	prev: function( elem ) {
		return sibling( elem, "previousSibling" );
	},
	nextAll: function( elem ) {
		return dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return dir( elem, "previousSibling" );
	},
	nextUntil: function( elem, i, until ) {
		return dir( elem, "nextSibling", until );
	},
	prevUntil: function( elem, i, until ) {
		return dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return siblings( ( elem.parentNode || {} ).firstChild, elem );
	},
	children: function( elem ) {
		return siblings( elem.firstChild );
	},
	contents: function( elem ) {
		return jQuery.nodeName( elem, "iframe" ) ?
			elem.contentDocument || elem.contentWindow.document :
			jQuery.merge( [], elem.childNodes );
	}
}, function( name, fn ) {
	jQuery.fn[ name ] = function( until, selector ) {
		var ret = jQuery.map( this, fn, until );

		if ( name.slice( -5 ) !== "Until" ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			ret = jQuery.filter( selector, ret );
		}

		if ( this.length > 1 ) {

			// Remove duplicates
			if ( !guaranteedUnique[ name ] ) {
				ret = jQuery.uniqueSort( ret );
			}

			// Reverse order for parents* and prev-derivatives
			if ( rparentsprev.test( name ) ) {
				ret = ret.reverse();
			}
		}

		return this.pushStack( ret );
	};
} );
var rnotwhite = ( /\S+/g );



// Convert String-formatted options into Object-formatted ones
function createOptions( options ) {
	var object = {};
	jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
		object[ flag ] = true;
	} );
	return object;
}

/*
 * Create a callback list using the following parameters:
 *
 *	options: an optional list of space-separated options that will change how
 *			the callback list behaves or a more traditional option object
 *
 * By default a callback list will act like an event callback list and can be
 * "fired" multiple times.
 *
 * Possible options:
 *
 *	once:			will ensure the callback list can only be fired once (like a Deferred)
 *
 *	memory:			will keep track of previous values and will call any callback added
 *					after the list has been fired right away with the latest "memorized"
 *					values (like a Deferred)
 *
 *	unique:			will ensure a callback can only be added once (no duplicate in the list)
 *
 *	stopOnFalse:	interrupt callings when a callback returns false
 *
 */
jQuery.Callbacks = function( options ) {

	// Convert options from String-formatted to Object-formatted if needed
	// (we check in cache first)
	options = typeof options === "string" ?
		createOptions( options ) :
		jQuery.extend( {}, options );

	var // Flag to know if list is currently firing
		firing,

		// Last fire value for non-forgettable lists
		memory,

		// Flag to know if list was already fired
		fired,

		// Flag to prevent firing
		locked,

		// Actual callback list
		list = [],

		// Queue of execution data for repeatable lists
		queue = [],

		// Index of currently firing callback (modified by add/remove as needed)
		firingIndex = -1,

		// Fire callbacks
		fire = function() {

			// Enforce single-firing
			locked = options.once;

			// Execute callbacks for all pending executions,
			// respecting firingIndex overrides and runtime changes
			fired = firing = true;
			for ( ; queue.length; firingIndex = -1 ) {
				memory = queue.shift();
				while ( ++firingIndex < list.length ) {

					// Run callback and check for early termination
					if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
						options.stopOnFalse ) {

						// Jump to end and forget the data so .add doesn't re-fire
						firingIndex = list.length;
						memory = false;
					}
				}
			}

			// Forget the data if we're done with it
			if ( !options.memory ) {
				memory = false;
			}

			firing = false;

			// Clean up if we're done firing for good
			if ( locked ) {

				// Keep an empty list if we have data for future add calls
				if ( memory ) {
					list = [];

				// Otherwise, this object is spent
				} else {
					list = "";
				}
			}
		},

		// Actual Callbacks object
		self = {

			// Add a callback or a collection of callbacks to the list
			add: function() {
				if ( list ) {

					// If we have memory from a past run, we should fire after adding
					if ( memory && !firing ) {
						firingIndex = list.length - 1;
						queue.push( memory );
					}

					( function add( args ) {
						jQuery.each( args, function( _, arg ) {
							if ( jQuery.isFunction( arg ) ) {
								if ( !options.unique || !self.has( arg ) ) {
									list.push( arg );
								}
							} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {

								// Inspect recursively
								add( arg );
							}
						} );
					} )( arguments );

					if ( memory && !firing ) {
						fire();
					}
				}
				return this;
			},

			// Remove a callback from the list
			remove: function() {
				jQuery.each( arguments, function( _, arg ) {
					var index;
					while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
						list.splice( index, 1 );

						// Handle firing indexes
						if ( index <= firingIndex ) {
							firingIndex--;
						}
					}
				} );
				return this;
			},

			// Check if a given callback is in the list.
			// If no argument is given, return whether or not list has callbacks attached.
			has: function( fn ) {
				return fn ?
					jQuery.inArray( fn, list ) > -1 :
					list.length > 0;
			},

			// Remove all callbacks from the list
			empty: function() {
				if ( list ) {
					list = [];
				}
				return this;
			},

			// Disable .fire and .add
			// Abort any current/pending executions
			// Clear all callbacks and values
			disable: function() {
				locked = queue = [];
				list = memory = "";
				return this;
			},
			disabled: function() {
				return !list;
			},

			// Disable .fire
			// Also disable .add unless we have memory (since it would have no effect)
			// Abort any pending executions
			lock: function() {
				locked = true;
				if ( !memory ) {
					self.disable();
				}
				return this;
			},
			locked: function() {
				return !!locked;
			},

			// Call all callbacks with the given context and arguments
			fireWith: function( context, args ) {
				if ( !locked ) {
					args = args || [];
					args = [ context, args.slice ? args.slice() : args ];
					queue.push( args );
					if ( !firing ) {
						fire();
					}
				}
				return this;
			},

			// Call all the callbacks with the given arguments
			fire: function() {
				self.fireWith( this, arguments );
				return this;
			},

			// To know if the callbacks have already been called at least once
			fired: function() {
				return !!fired;
			}
		};

	return self;
};


jQuery.extend( {

	Deferred: function( func ) {
		var tuples = [

				// action, add listener, listener list, final state
				[ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ],
				[ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ],
				[ "notify", "progress", jQuery.Callbacks( "memory" ) ]
			],
			state = "pending",
			promise = {
				state: function() {
					return state;
				},
				always: function() {
					deferred.done( arguments ).fail( arguments );
					return this;
				},
				then: function( /* fnDone, fnFail, fnProgress */ ) {
					var fns = arguments;
					return jQuery.Deferred( function( newDefer ) {
						jQuery.each( tuples, function( i, tuple ) {
							var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];

							// deferred[ done | fail | progress ] for forwarding actions to newDefer
							deferred[ tuple[ 1 ] ]( function() {
								var returned = fn && fn.apply( this, arguments );
								if ( returned && jQuery.isFunction( returned.promise ) ) {
									returned.promise()
										.progress( newDefer.notify )
										.done( newDefer.resolve )
										.fail( newDefer.reject );
								} else {
									newDefer[ tuple[ 0 ] + "With" ](
										this === promise ? newDefer.promise() : this,
										fn ? [ returned ] : arguments
									);
								}
							} );
						} );
						fns = null;
					} ).promise();
				},

				// Get a promise for this deferred
				// If obj is provided, the promise aspect is added to the object
				promise: function( obj ) {
					return obj != null ? jQuery.extend( obj, promise ) : promise;
				}
			},
			deferred = {};

		// Keep pipe for back-compat
		promise.pipe = promise.then;

		// Add list-specific methods
		jQuery.each( tuples, function( i, tuple ) {
			var list = tuple[ 2 ],
				stateString = tuple[ 3 ];

			// promise[ done | fail | progress ] = list.add
			promise[ tuple[ 1 ] ] = list.add;

			// Handle state
			if ( stateString ) {
				list.add( function() {

					// state = [ resolved | rejected ]
					state = stateString;

				// [ reject_list | resolve_list ].disable; progress_list.lock
				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
			}

			// deferred[ resolve | reject | notify ]
			deferred[ tuple[ 0 ] ] = function() {
				deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments );
				return this;
			};
			deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
		} );

		// Make the deferred a promise
		promise.promise( deferred );

		// Call given func if any
		if ( func ) {
			func.call( deferred, deferred );
		}

		// All done!
		return deferred;
	},

	// Deferred helper
	when: function( subordinate /* , ..., subordinateN */ ) {
		var i = 0,
			resolveValues = slice.call( arguments ),
			length = resolveValues.length,

			// the count of uncompleted subordinates
			remaining = length !== 1 ||
				( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,

			// the master Deferred.
			// If resolveValues consist of only a single Deferred, just use that.
			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),

			// Update function for both resolve and progress values
			updateFunc = function( i, contexts, values ) {
				return function( value ) {
					contexts[ i ] = this;
					values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
					if ( values === progressValues ) {
						deferred.notifyWith( contexts, values );

					} else if ( !( --remaining ) ) {
						deferred.resolveWith( contexts, values );
					}
				};
			},

			progressValues, progressContexts, resolveContexts;

		// add listeners to Deferred subordinates; treat others as resolved
		if ( length > 1 ) {
			progressValues = new Array( length );
			progressContexts = new Array( length );
			resolveContexts = new Array( length );
			for ( ; i < length; i++ ) {
				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
					resolveValues[ i ].promise()
						.progress( updateFunc( i, progressContexts, progressValues ) )
						.done( updateFunc( i, resolveContexts, resolveValues ) )
						.fail( deferred.reject );
				} else {
					--remaining;
				}
			}
		}

		// if we're not waiting on anything, resolve the master
		if ( !remaining ) {
			deferred.resolveWith( resolveContexts, resolveValues );
		}

		return deferred.promise();
	}
} );


// The deferred used on DOM ready
var readyList;

jQuery.fn.ready = function( fn ) {

	// Add the callback
	jQuery.ready.promise().done( fn );

	return this;
};

jQuery.extend( {

	// Is the DOM ready to be used? Set to true once it occurs.
	isReady: false,

	// A counter to track how many items to wait for before
	// the ready event fires. See #6781
	readyWait: 1,

	// Hold (or release) the ready event
	holdReady: function( hold ) {
		if ( hold ) {
			jQuery.readyWait++;
		} else {
			jQuery.ready( true );
		}
	},

	// Handle when the DOM is ready
	ready: function( wait ) {

		// Abort if there are pending holds or we're already ready
		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
			return;
		}

		// Remember that the DOM is ready
		jQuery.isReady = true;

		// If a normal DOM Ready event fired, decrement, and wait if need be
		if ( wait !== true && --jQuery.readyWait > 0 ) {
			return;
		}

		// If there are functions bound, to execute
		readyList.resolveWith( document, [ jQuery ] );

		// Trigger any bound ready events
		if ( jQuery.fn.triggerHandler ) {
			jQuery( document ).triggerHandler( "ready" );
			jQuery( document ).off( "ready" );
		}
	}
} );

/**
 * Clean-up method for dom ready events
 */
function detach() {
	if ( document.addEventListener ) {
		document.removeEventListener( "DOMContentLoaded", completed );
		window.removeEventListener( "load", completed );

	} else {
		document.detachEvent( "onreadystatechange", completed );
		window.detachEvent( "onload", completed );
	}
}

/**
 * The ready event handler and self cleanup method
 */
function completed() {

	// readyState === "complete" is good enough for us to call the dom ready in oldIE
	if ( document.addEventListener ||
		window.event.type === "load" ||
		document.readyState === "complete" ) {

		detach();
		jQuery.ready();
	}
}

jQuery.ready.promise = function( obj ) {
	if ( !readyList ) {

		readyList = jQuery.Deferred();

		// Catch cases where $(document).ready() is called
		// after the browser event has already occurred.
		// Support: IE6-10
		// Older IE sometimes signals "interactive" too soon
		if ( document.readyState === "complete" ||
			( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {

			// Handle it asynchronously to allow scripts the opportunity to delay ready
			window.setTimeout( jQuery.ready );

		// Standards-based browsers support DOMContentLoaded
		} else if ( document.addEventListener ) {

			// Use the handy event callback
			document.addEventListener( "DOMContentLoaded", completed );

			// A fallback to window.onload, that will always work
			window.addEventListener( "load", completed );

		// If IE event model is used
		} else {

			// Ensure firing before onload, maybe late but safe also for iframes
			document.attachEvent( "onreadystatechange", completed );

			// A fallback to window.onload, that will always work
			window.attachEvent( "onload", completed );

			// If IE and not a frame
			// continually check to see if the document is ready
			var top = false;

			try {
				top = window.frameElement == null && document.documentElement;
			} catch ( e ) {}

			if ( top && top.doScroll ) {
				( function doScrollCheck() {
					if ( !jQuery.isReady ) {

						try {

							// Use the trick by Diego Perini
							// http://javascript.nwbox.com/IEContentLoaded/
							top.doScroll( "left" );
						} catch ( e ) {
							return window.setTimeout( doScrollCheck, 50 );
						}

						// detach all dom ready events
						detach();

						// and execute any waiting functions
						jQuery.ready();
					}
				} )();
			}
		}
	}
	return readyList.promise( obj );
};

// Kick off the DOM ready check even if the user does not
jQuery.ready.promise();




// Support: IE<9
// Iteration over object's inherited properties before its own
var i;
for ( i in jQuery( support ) ) {
	break;
}
support.ownFirst = i === "0";

// Note: most support tests are defined in their respective modules.
// false until the test is run
support.inlineBlockNeedsLayout = false;

// Execute ASAP in case we need to set body.style.zoom
jQuery( function() {

	// Minified: var a,b,c,d
	var val, div, body, container;

	body = document.getElementsByTagName( "body" )[ 0 ];
	if ( !body || !body.style ) {

		// Return for frameset docs that don't have a body
		return;
	}

	// Setup
	div = document.createElement( "div" );
	container = document.createElement( "div" );
	container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
	body.appendChild( container ).appendChild( div );

	if ( typeof div.style.zoom !== "undefined" ) {

		// Support: IE<8
		// Check if natively block-level elements act like inline-block
		// elements when setting their display to 'inline' and giving
		// them layout
		div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";

		support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
		if ( val ) {

			// Prevent IE 6 from affecting layout for positioned elements #11048
			// Prevent IE from shrinking the body in IE 7 mode #12869
			// Support: IE<8
			body.style.zoom = 1;
		}
	}

	body.removeChild( container );
} );


( function() {
	var div = document.createElement( "div" );

	// Support: IE<9
	support.deleteExpando = true;
	try {
		delete div.test;
	} catch ( e ) {
		support.deleteExpando = false;
	}

	// Null elements to avoid leaks in IE.
	div = null;
} )();
var acceptData = function( elem ) {
	var noData = jQuery.noData[ ( elem.nodeName + " " ).toLowerCase() ],
		nodeType = +elem.nodeType || 1;

	// Do not set data on non-element DOM nodes because it will not be cleared (#8335).
	return nodeType !== 1 && nodeType !== 9 ?
		false :

		// Nodes accept data unless otherwise specified; rejection can be conditional
		!noData || noData !== true && elem.getAttribute( "classid" ) === noData;
};




var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
	rmultiDash = /([A-Z])/g;

function dataAttr( elem, key, data ) {

	// If nothing was found internally, try to fetch any
	// data from the HTML5 data-* attribute
	if ( data === undefined && elem.nodeType === 1 ) {

		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();

		data = elem.getAttribute( name );

		if ( typeof data === "string" ) {
			try {
				data = data === "true" ? true :
					data === "false" ? false :
					data === "null" ? null :

					// Only convert to a number if it doesn't change the string
					+data + "" === data ? +data :
					rbrace.test( data ) ? jQuery.parseJSON( data ) :
					data;
			} catch ( e ) {}

			// Make sure we set the data so it isn't changed later
			jQuery.data( elem, key, data );

		} else {
			data = undefined;
		}
	}

	return data;
}

// checks a cache object for emptiness
function isEmptyDataObject( obj ) {
	var name;
	for ( name in obj ) {

		// if the public data object is empty, the private is still empty
		if ( name === "data" && jQuery.isEmptyObject( obj[ name ] ) ) {
			continue;
		}
		if ( name !== "toJSON" ) {
			return false;
		}
	}

	return true;
}

function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
	if ( !acceptData( elem ) ) {
		return;
	}

	var ret, thisCache,
		internalKey = jQuery.expando,

		// We have to handle DOM nodes and JS objects differently because IE6-7
		// can't GC object references properly across the DOM-JS boundary
		isNode = elem.nodeType,

		// Only DOM nodes need the global jQuery cache; JS object data is
		// attached directly to the object so GC can occur automatically
		cache = isNode ? jQuery.cache : elem,

		// Only defining an ID for JS objects if its cache already exists allows
		// the code to shortcut on the same path as a DOM node with no cache
		id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;

	// Avoid doing any more work than we need to when trying to get data on an
	// object that has no data at all
	if ( ( !id || !cache[ id ] || ( !pvt && !cache[ id ].data ) ) &&
		data === undefined && typeof name === "string" ) {
		return;
	}

	if ( !id ) {

		// Only DOM nodes need a new unique ID for each element since their data
		// ends up in the global cache
		if ( isNode ) {
			id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
		} else {
			id = internalKey;
		}
	}

	if ( !cache[ id ] ) {

		// Avoid exposing jQuery metadata on plain JS objects when the object
		// is serialized using JSON.stringify
		cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
	}

	// An object can be passed to jQuery.data instead of a key/value pair; this gets
	// shallow copied over onto the existing cache
	if ( typeof name === "object" || typeof name === "function" ) {
		if ( pvt ) {
			cache[ id ] = jQuery.extend( cache[ id ], name );
		} else {
			cache[ id ].data = jQuery.extend( cache[ id ].data, name );
		}
	}

	thisCache = cache[ id ];

	// jQuery data() is stored in a separate object inside the object's internal data
	// cache in order to avoid key collisions between internal data and user-defined
	// data.
	if ( !pvt ) {
		if ( !thisCache.data ) {
			thisCache.data = {};
		}

		thisCache = thisCache.data;
	}

	if ( data !== undefined ) {
		thisCache[ jQuery.camelCase( name ) ] = data;
	}

	// Check for both converted-to-camel and non-converted data property names
	// If a data property was specified
	if ( typeof name === "string" ) {

		// First Try to find as-is property data
		ret = thisCache[ name ];

		// Test for null|undefined property data
		if ( ret == null ) {

			// Try to find the camelCased property
			ret = thisCache[ jQuery.camelCase( name ) ];
		}
	} else {
		ret = thisCache;
	}

	return ret;
}

function internalRemoveData( elem, name, pvt ) {
	if ( !acceptData( elem ) ) {
		return;
	}

	var thisCache, i,
		isNode = elem.nodeType,

		// See jQuery.data for more information
		cache = isNode ? jQuery.cache : elem,
		id = isNode ? elem[ jQuery.expando ] : jQuery.expando;

	// If there is already no cache entry for this object, there is no
	// purpose in continuing
	if ( !cache[ id ] ) {
		return;
	}

	if ( name ) {

		thisCache = pvt ? cache[ id ] : cache[ id ].data;

		if ( thisCache ) {

			// Support array or space separated string names for data keys
			if ( !jQuery.isArray( name ) ) {

				// try the string as a key before any manipulation
				if ( name in thisCache ) {
					name = [ name ];
				} else {

					// split the camel cased version by spaces unless a key with the spaces exists
					name = jQuery.camelCase( name );
					if ( name in thisCache ) {
						name = [ name ];
					} else {
						name = name.split( " " );
					}
				}
			} else {

				// If "name" is an array of keys...
				// When data is initially created, via ("key", "val") signature,
				// keys will be converted to camelCase.
				// Since there is no way to tell _how_ a key was added, remove
				// both plain key and camelCase key. #12786
				// This will only penalize the array argument path.
				name = name.concat( jQuery.map( name, jQuery.camelCase ) );
			}

			i = name.length;
			while ( i-- ) {
				delete thisCache[ name[ i ] ];
			}

			// If there is no data left in the cache, we want to continue
			// and let the cache object itself get destroyed
			if ( pvt ? !isEmptyDataObject( thisCache ) : !jQuery.isEmptyObject( thisCache ) ) {
				return;
			}
		}
	}

	// See jQuery.data for more information
	if ( !pvt ) {
		delete cache[ id ].data;

		// Don't destroy the parent cache unless the internal data object
		// had been the only thing left in it
		if ( !isEmptyDataObject( cache[ id ] ) ) {
			return;
		}
	}

	// Destroy the cache
	if ( isNode ) {
		jQuery.cleanData( [ elem ], true );

	// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
	/* jshint eqeqeq: false */
	} else if ( support.deleteExpando || cache != cache.window ) {
		/* jshint eqeqeq: true */
		delete cache[ id ];

	// When all else fails, undefined
	} else {
		cache[ id ] = undefined;
	}
}

jQuery.extend( {
	cache: {},

	// The following elements (space-suffixed to avoid Object.prototype collisions)
	// throw uncatchable exceptions if you attempt to set expando properties
	noData: {
		"applet ": true,
		"embed ": true,

		// ...but Flash objects (which have this classid) *can* handle expandos
		"object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
	},

	hasData: function( elem ) {
		elem = elem.nodeType ? jQuery.cache[ elem[ jQuery.expando ] ] : elem[ jQuery.expando ];
		return !!elem && !isEmptyDataObject( elem );
	},

	data: function( elem, name, data ) {
		return internalData( elem, name, data );
	},

	removeData: function( elem, name ) {
		return internalRemoveData( elem, name );
	},

	// For internal use only.
	_data: function( elem, name, data ) {
		return internalData( elem, name, data, true );
	},

	_removeData: function( elem, name ) {
		return internalRemoveData( elem, name, true );
	}
} );

jQuery.fn.extend( {
	data: function( key, value ) {
		var i, name, data,
			elem = this[ 0 ],
			attrs = elem && elem.attributes;

		// Special expections of .data basically thwart jQuery.access,
		// so implement the relevant behavior ourselves

		// Gets all values
		if ( key === undefined ) {
			if ( this.length ) {
				data = jQuery.data( elem );

				if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
					i = attrs.length;
					while ( i-- ) {

						// Support: IE11+
						// The attrs elements can be null (#14894)
						if ( attrs[ i ] ) {
							name = attrs[ i ].name;
							if ( name.indexOf( "data-" ) === 0 ) {
								name = jQuery.camelCase( name.slice( 5 ) );
								dataAttr( elem, name, data[ name ] );
							}
						}
					}
					jQuery._data( elem, "parsedAttrs", true );
				}
			}

			return data;
		}

		// Sets multiple values
		if ( typeof key === "object" ) {
			return this.each( function() {
				jQuery.data( this, key );
			} );
		}

		return arguments.length > 1 ?

			// Sets one value
			this.each( function() {
				jQuery.data( this, key, value );
			} ) :

			// Gets one value
			// Try to fetch any internally stored data first
			elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
	},

	removeData: function( key ) {
		return this.each( function() {
			jQuery.removeData( this, key );
		} );
	}
} );


jQuery.extend( {
	queue: function( elem, type, data ) {
		var queue;

		if ( elem ) {
			type = ( type || "fx" ) + "queue";
			queue = jQuery._data( elem, type );

			// Speed up dequeue by getting out quickly if this is just a lookup
			if ( data ) {
				if ( !queue || jQuery.isArray( data ) ) {
					queue = jQuery._data( elem, type, jQuery.makeArray( data ) );
				} else {
					queue.push( data );
				}
			}
			return queue || [];
		}
	},

	dequeue: function( elem, type ) {
		type = type || "fx";

		var queue = jQuery.queue( elem, type ),
			startLength = queue.length,
			fn = queue.shift(),
			hooks = jQuery._queueHooks( elem, type ),
			next = function() {
				jQuery.dequeue( elem, type );
			};

		// If the fx queue is dequeued, always remove the progress sentinel
		if ( fn === "inprogress" ) {
			fn = queue.shift();
			startLength--;
		}

		if ( fn ) {

			// Add a progress sentinel to prevent the fx queue from being
			// automatically dequeued
			if ( type === "fx" ) {
				queue.unshift( "inprogress" );
			}

			// clear up the last queue stop function
			delete hooks.stop;
			fn.call( elem, next, hooks );
		}

		if ( !startLength && hooks ) {
			hooks.empty.fire();
		}
	},

	// not intended for public consumption - generates a queueHooks object,
	// or returns the current one
	_queueHooks: function( elem, type ) {
		var key = type + "queueHooks";
		return jQuery._data( elem, key ) || jQuery._data( elem, key, {
			empty: jQuery.Callbacks( "once memory" ).add( function() {
				jQuery._removeData( elem, type + "queue" );
				jQuery._removeData( elem, key );
			} )
		} );
	}
} );

jQuery.fn.extend( {
	queue: function( type, data ) {
		var setter = 2;

		if ( typeof type !== "string" ) {
			data = type;
			type = "fx";
			setter--;
		}

		if ( arguments.length < setter ) {
			return jQuery.queue( this[ 0 ], type );
		}

		return data === undefined ?
			this :
			this.each( function() {
				var queue = jQuery.queue( this, type, data );

				// ensure a hooks for this queue
				jQuery._queueHooks( this, type );

				if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
					jQuery.dequeue( this, type );
				}
			} );
	},
	dequeue: function( type ) {
		return this.each( function() {
			jQuery.dequeue( this, type );
		} );
	},
	clearQueue: function( type ) {
		return this.queue( type || "fx", [] );
	},

	// Get a promise resolved when queues of a certain type
	// are emptied (fx is the type by default)
	promise: function( type, obj ) {
		var tmp,
			count = 1,
			defer = jQuery.Deferred(),
			elements = this,
			i = this.length,
			resolve = function() {
				if ( !( --count ) ) {
					defer.resolveWith( elements, [ elements ] );
				}
			};

		if ( typeof type !== "string" ) {
			obj = type;
			type = undefined;
		}
		type = type || "fx";

		while ( i-- ) {
			tmp = jQuery._data( elements[ i ], type + "queueHooks" );
			if ( tmp && tmp.empty ) {
				count++;
				tmp.empty.add( resolve );
			}
		}
		resolve();
		return defer.promise( obj );
	}
} );


( function() {
	var shrinkWrapBlocksVal;

	support.shrinkWrapBlocks = function() {
		if ( shrinkWrapBlocksVal != null ) {
			return shrinkWrapBlocksVal;
		}

		// Will be changed later if needed.
		shrinkWrapBlocksVal = false;

		// Minified: var b,c,d
		var div, body, container;

		body = document.getElementsByTagName( "body" )[ 0 ];
		if ( !body || !body.style ) {

			// Test fired too early or in an unsupported environment, exit.
			return;
		}

		// Setup
		div = document.createElement( "div" );
		container = document.createElement( "div" );
		container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
		body.appendChild( container ).appendChild( div );

		// Support: IE6
		// Check if elements with layout shrink-wrap their children
		if ( typeof div.style.zoom !== "undefined" ) {

			// Reset CSS: box-sizing; display; margin; border
			div.style.cssText =

				// Support: Firefox<29, Android 2.3
				// Vendor-prefix box-sizing
				"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
				"box-sizing:content-box;display:block;margin:0;border:0;" +
				"padding:1px;width:1px;zoom:1";
			div.appendChild( document.createElement( "div" ) ).style.width = "5px";
			shrinkWrapBlocksVal = div.offsetWidth !== 3;
		}

		body.removeChild( container );

		return shrinkWrapBlocksVal;
	};

} )();
var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;

var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );


var cssExpand = [ "Top", "Right", "Bottom", "Left" ];

var isHidden = function( elem, el ) {

		// isHidden might be called from jQuery#filter function;
		// in that case, element will be second argument
		elem = el || elem;
		return jQuery.css( elem, "display" ) === "none" ||
			!jQuery.contains( elem.ownerDocument, elem );
	};



function adjustCSS( elem, prop, valueParts, tween ) {
	var adjusted,
		scale = 1,
		maxIterations = 20,
		currentValue = tween ?
			function() { return tween.cur(); } :
			function() { return jQuery.css( elem, prop, "" ); },
		initial = currentValue(),
		unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),

		// Starting value computation is required for potential unit mismatches
		initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
			rcssNum.exec( jQuery.css( elem, prop ) );

	if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {

		// Trust units reported by jQuery.css
		unit = unit || initialInUnit[ 3 ];

		// Make sure we update the tween properties later on
		valueParts = valueParts || [];

		// Iteratively approximate from a nonzero starting point
		initialInUnit = +initial || 1;

		do {

			// If previous iteration zeroed out, double until we get *something*.
			// Use string for doubling so we don't accidentally see scale as unchanged below
			scale = scale || ".5";

			// Adjust and apply
			initialInUnit = initialInUnit / scale;
			jQuery.style( elem, prop, initialInUnit + unit );

		// Update scale, tolerating zero or NaN from tween.cur()
		// Break the loop if scale is unchanged or perfect, or if we've just had enough.
		} while (
			scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
		);
	}

	if ( valueParts ) {
		initialInUnit = +initialInUnit || +initial || 0;

		// Apply relative offset (+=/-=) if specified
		adjusted = valueParts[ 1 ] ?
			initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
			+valueParts[ 2 ];
		if ( tween ) {
			tween.unit = unit;
			tween.start = initialInUnit;
			tween.end = adjusted;
		}
	}
	return adjusted;
}


// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
	var i = 0,
		length = elems.length,
		bulk = key == null;

	// Sets many values
	if ( jQuery.type( key ) === "object" ) {
		chainable = true;
		for ( i in key ) {
			access( elems, fn, i, key[ i ], true, emptyGet, raw );
		}

	// Sets one value
	} else if ( value !== undefined ) {
		chainable = true;

		if ( !jQuery.isFunction( value ) ) {
			raw = true;
		}

		if ( bulk ) {

			// Bulk operations run against the entire set
			if ( raw ) {
				fn.call( elems, value );
				fn = null;

			// ...except when executing function values
			} else {
				bulk = fn;
				fn = function( elem, key, value ) {
					return bulk.call( jQuery( elem ), value );
				};
			}
		}

		if ( fn ) {
			for ( ; i < length; i++ ) {
				fn(
					elems[ i ],
					key,
					raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) )
				);
			}
		}
	}

	return chainable ?
		elems :

		// Gets
		bulk ?
			fn.call( elems ) :
			length ? fn( elems[ 0 ], key ) : emptyGet;
};
var rcheckableType = ( /^(?:checkbox|radio)$/i );

var rtagName = ( /<([\w:-]+)/ );

var rscriptType = ( /^$|\/(?:java|ecma)script/i );

var rleadingWhitespace = ( /^\s+/ );

var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|" +
		"details|dialog|figcaption|figure|footer|header|hgroup|main|" +
		"mark|meter|nav|output|picture|progress|section|summary|template|time|video";



function createSafeFragment( document ) {
	var list = nodeNames.split( "|" ),
		safeFrag = document.createDocumentFragment();

	if ( safeFrag.createElement ) {
		while ( list.length ) {
			safeFrag.createElement(
				list.pop()
			);
		}
	}
	return safeFrag;
}


( function() {
	var div = document.createElement( "div" ),
		fragment = document.createDocumentFragment(),
		input = document.createElement( "input" );

	// Setup
	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";

	// IE strips leading whitespace when .innerHTML is used
	support.leadingWhitespace = div.firstChild.nodeType === 3;

	// Make sure that tbody elements aren't automatically inserted
	// IE will insert them into empty tables
	support.tbody = !div.getElementsByTagName( "tbody" ).length;

	// Make sure that link elements get serialized correctly by innerHTML
	// This requires a wrapper element in IE
	support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;

	// Makes sure cloning an html5 element does not cause problems
	// Where outerHTML is undefined, this still works
	support.html5Clone =
		document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";

	// Check if a disconnected checkbox will retain its checked
	// value of true after appended to the DOM (IE6/7)
	input.type = "checkbox";
	input.checked = true;
	fragment.appendChild( input );
	support.appendChecked = input.checked;

	// Make sure textarea (and checkbox) defaultValue is properly cloned
	// Support: IE6-IE11+
	div.innerHTML = "<textarea>x</textarea>";
	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;

	// #11217 - WebKit loses check when the name is after the checked attribute
	fragment.appendChild( div );

	// Support: Windows Web Apps (WWA)
	// `name` and `type` must use .setAttribute for WWA (#14901)
	input = document.createElement( "input" );
	input.setAttribute( "type", "radio" );
	input.setAttribute( "checked", "checked" );
	input.setAttribute( "name", "t" );

	div.appendChild( input );

	// Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
	// old WebKit doesn't clone checked state correctly in fragments
	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;

	// Support: IE<9
	// Cloned elements keep attachEvent handlers, we use addEventListener on IE9+
	support.noCloneEvent = !!div.addEventListener;

	// Support: IE<9
	// Since attributes and properties are the same in IE,
	// cleanData must set properties to undefined rather than use removeAttribute
	div[ jQuery.expando ] = 1;
	support.attributes = !div.getAttribute( jQuery.expando );
} )();


// We have to close these tags to support XHTML (#13200)
var wrapMap = {
	option: [ 1, "<select multiple='multiple'>", "</select>" ],
	legend: [ 1, "<fieldset>", "</fieldset>" ],
	area: [ 1, "<map>", "</map>" ],

	// Support: IE8
	param: [ 1, "<object>", "</object>" ],
	thead: [ 1, "<table>", "</table>" ],
	tr: [ 2, "<table><tbody>", "</tbody></table>" ],
	col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
	td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],

	// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
	// unless wrapped in a div with non-breaking characters in front of it.
	_default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
};

// Support: IE8-IE9
wrapMap.optgroup = wrapMap.option;

wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;


function getAll( context, tag ) {
	var elems, elem,
		i = 0,
		found = typeof context.getElementsByTagName !== "undefined" ?
			context.getElementsByTagName( tag || "*" ) :
			typeof context.querySelectorAll !== "undefined" ?
				context.querySelectorAll( tag || "*" ) :
				undefined;

	if ( !found ) {
		for ( found = [], elems = context.childNodes || context;
			( elem = elems[ i ] ) != null;
			i++
		) {
			if ( !tag || jQuery.nodeName( elem, tag ) ) {
				found.push( elem );
			} else {
				jQuery.merge( found, getAll( elem, tag ) );
			}
		}
	}

	return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
		jQuery.merge( [ context ], found ) :
		found;
}


// Mark scripts as having already been evaluated
function setGlobalEval( elems, refElements ) {
	var elem,
		i = 0;
	for ( ; ( elem = elems[ i ] ) != null; i++ ) {
		jQuery._data(
			elem,
			"globalEval",
			!refElements || jQuery._data( refElements[ i ], "globalEval" )
		);
	}
}


var rhtml = /<|&#?\w+;/,
	rtbody = /<tbody/i;

function fixDefaultChecked( elem ) {
	if ( rcheckableType.test( elem.type ) ) {
		elem.defaultChecked = elem.checked;
	}
}

function buildFragment( elems, context, scripts, selection, ignored ) {
	var j, elem, contains,
		tmp, tag, tbody, wrap,
		l = elems.length,

		// Ensure a safe fragment
		safe = createSafeFragment( context ),

		nodes = [],
		i = 0;

	for ( ; i < l; i++ ) {
		elem = elems[ i ];

		if ( elem || elem === 0 ) {

			// Add nodes directly
			if ( jQuery.type( elem ) === "object" ) {
				jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );

			// Convert non-html into a text node
			} else if ( !rhtml.test( elem ) ) {
				nodes.push( context.createTextNode( elem ) );

			// Convert html into DOM nodes
			} else {
				tmp = tmp || safe.appendChild( context.createElement( "div" ) );

				// Deserialize a standard representation
				tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
				wrap = wrapMap[ tag ] || wrapMap._default;

				tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];

				// Descend through wrappers to the right content
				j = wrap[ 0 ];
				while ( j-- ) {
					tmp = tmp.lastChild;
				}

				// Manually add leading whitespace removed by IE
				if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
					nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[ 0 ] ) );
				}

				// Remove IE's autoinserted <tbody> from table fragments
				if ( !support.tbody ) {

					// String was a <table>, *may* have spurious <tbody>
					elem = tag === "table" && !rtbody.test( elem ) ?
						tmp.firstChild :

						// String was a bare <thead> or <tfoot>
						wrap[ 1 ] === "<table>" && !rtbody.test( elem ) ?
							tmp :
							0;

					j = elem && elem.childNodes.length;
					while ( j-- ) {
						if ( jQuery.nodeName( ( tbody = elem.childNodes[ j ] ), "tbody" ) &&
							!tbody.childNodes.length ) {

							elem.removeChild( tbody );
						}
					}
				}

				jQuery.merge( nodes, tmp.childNodes );

				// Fix #12392 for WebKit and IE > 9
				tmp.textContent = "";

				// Fix #12392 for oldIE
				while ( tmp.firstChild ) {
					tmp.removeChild( tmp.firstChild );
				}

				// Remember the top-level container for proper cleanup
				tmp = safe.lastChild;
			}
		}
	}

	// Fix #11356: Clear elements from fragment
	if ( tmp ) {
		safe.removeChild( tmp );
	}

	// Reset defaultChecked for any radios and checkboxes
	// about to be appended to the DOM in IE 6/7 (#8060)
	if ( !support.appendChecked ) {
		jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
	}

	i = 0;
	while ( ( elem = nodes[ i++ ] ) ) {

		// Skip elements already in the context collection (trac-4087)
		if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
			if ( ignored ) {
				ignored.push( elem );
			}

			continue;
		}

		contains = jQuery.contains( elem.ownerDocument, elem );

		// Append to fragment
		tmp = getAll( safe.appendChild( elem ), "script" );

		// Preserve script evaluation history
		if ( contains ) {
			setGlobalEval( tmp );
		}

		// Capture executables
		if ( scripts ) {
			j = 0;
			while ( ( elem = tmp[ j++ ] ) ) {
				if ( rscriptType.test( elem.type || "" ) ) {
					scripts.push( elem );
				}
			}
		}
	}

	tmp = null;

	return safe;
}


( function() {
	var i, eventName,
		div = document.createElement( "div" );

	// Support: IE<9 (lack submit/change bubble), Firefox (lack focus(in | out) events)
	for ( i in { submit: true, change: true, focusin: true } ) {
		eventName = "on" + i;

		if ( !( support[ i ] = eventName in window ) ) {

			// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
			div.setAttribute( eventName, "t" );
			support[ i ] = div.attributes[ eventName ].expando === false;
		}
	}

	// Null elements to avoid leaks in IE.
	div = null;
} )();


var rformElems = /^(?:input|select|textarea)$/i,
	rkeyEvent = /^key/,
	rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
	rtypenamespace = /^([^.]*)(?:\.(.+)|)/;

function returnTrue() {
	return true;
}

function returnFalse() {
	return false;
}

// Support: IE9
// See #13393 for more info
function safeActiveElement() {
	try {
		return document.activeElement;
	} catch ( err ) { }
}

function on( elem, types, selector, data, fn, one ) {
	var origFn, type;

	// Types can be a map of types/handlers
	if ( typeof types === "object" ) {

		// ( types-Object, selector, data )
		if ( typeof selector !== "string" ) {

			// ( types-Object, data )
			data = data || selector;
			selector = undefined;
		}
		for ( type in types ) {
			on( elem, type, selector, data, types[ type ], one );
		}
		return elem;
	}

	if ( data == null && fn == null ) {

		// ( types, fn )
		fn = selector;
		data = selector = undefined;
	} else if ( fn == null ) {
		if ( typeof selector === "string" ) {

			// ( types, selector, fn )
			fn = data;
			data = undefined;
		} else {

			// ( types, data, fn )
			fn = data;
			data = selector;
			selector = undefined;
		}
	}
	if ( fn === false ) {
		fn = returnFalse;
	} else if ( !fn ) {
		return elem;
	}

	if ( one === 1 ) {
		origFn = fn;
		fn = function( event ) {

			// Can use an empty set, since event contains the info
			jQuery().off( event );
			return origFn.apply( this, arguments );
		};

		// Use same guid so caller can remove using origFn
		fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
	}
	return elem.each( function() {
		jQuery.event.add( this, types, fn, data, selector );
	} );
}

/*
 * Helper functions for managing events -- not part of the public interface.
 * Props to Dean Edwards' addEvent library for many of the ideas.
 */
jQuery.event = {

	global: {},

	add: function( elem, types, handler, data, selector ) {
		var tmp, events, t, handleObjIn,
			special, eventHandle, handleObj,
			handlers, type, namespaces, origType,
			elemData = jQuery._data( elem );

		// Don't attach events to noData or text/comment nodes (but allow plain objects)
		if ( !elemData ) {
			return;
		}

		// Caller can pass in an object of custom data in lieu of the handler
		if ( handler.handler ) {
			handleObjIn = handler;
			handler = handleObjIn.handler;
			selector = handleObjIn.selector;
		}

		// Make sure that the handler has a unique ID, used to find/remove it later
		if ( !handler.guid ) {
			handler.guid = jQuery.guid++;
		}

		// Init the element's event structure and main handler, if this is the first
		if ( !( events = elemData.events ) ) {
			events = elemData.events = {};
		}
		if ( !( eventHandle = elemData.handle ) ) {
			eventHandle = elemData.handle = function( e ) {

				// Discard the second event of a jQuery.event.trigger() and
				// when an event is called after a page has unloaded
				return typeof jQuery !== "undefined" &&
					( !e || jQuery.event.triggered !== e.type ) ?
					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
					undefined;
			};

			// Add elem as a property of the handle fn to prevent a memory leak
			// with IE non-native events
			eventHandle.elem = elem;
		}

		// Handle multiple events separated by a space
		types = ( types || "" ).match( rnotwhite ) || [ "" ];
		t = types.length;
		while ( t-- ) {
			tmp = rtypenamespace.exec( types[ t ] ) || [];
			type = origType = tmp[ 1 ];
			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();

			// There *must* be a type, no attaching namespace-only handlers
			if ( !type ) {
				continue;
			}

			// If event changes its type, use the special event handlers for the changed type
			special = jQuery.event.special[ type ] || {};

			// If selector defined, determine special event api type, otherwise given type
			type = ( selector ? special.delegateType : special.bindType ) || type;

			// Update special based on newly reset type
			special = jQuery.event.special[ type ] || {};

			// handleObj is passed to all event handlers
			handleObj = jQuery.extend( {
				type: type,
				origType: origType,
				data: data,
				handler: handler,
				guid: handler.guid,
				selector: selector,
				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
				namespace: namespaces.join( "." )
			}, handleObjIn );

			// Init the event handler queue if we're the first
			if ( !( handlers = events[ type ] ) ) {
				handlers = events[ type ] = [];
				handlers.delegateCount = 0;

				// Only use addEventListener/attachEvent if the special events handler returns false
				if ( !special.setup ||
					special.setup.call( elem, data, namespaces, eventHandle ) === false ) {

					// Bind the global event handler to the element
					if ( elem.addEventListener ) {
						elem.addEventListener( type, eventHandle, false );

					} else if ( elem.attachEvent ) {
						elem.attachEvent( "on" + type, eventHandle );
					}
				}
			}

			if ( special.add ) {
				special.add.call( elem, handleObj );

				if ( !handleObj.handler.guid ) {
					handleObj.handler.guid = handler.guid;
				}
			}

			// Add to the element's handler list, delegates in front
			if ( selector ) {
				handlers.splice( handlers.delegateCount++, 0, handleObj );
			} else {
				handlers.push( handleObj );
			}

			// Keep track of which events have ever been used, for event optimization
			jQuery.event.global[ type ] = true;
		}

		// Nullify elem to prevent memory leaks in IE
		elem = null;
	},

	// Detach an event or set of events from an element
	remove: function( elem, types, handler, selector, mappedTypes ) {
		var j, handleObj, tmp,
			origCount, t, events,
			special, handlers, type,
			namespaces, origType,
			elemData = jQuery.hasData( elem ) && jQuery._data( elem );

		if ( !elemData || !( events = elemData.events ) ) {
			return;
		}

		// Once for each type.namespace in types; type may be omitted
		types = ( types || "" ).match( rnotwhite ) || [ "" ];
		t = types.length;
		while ( t-- ) {
			tmp = rtypenamespace.exec( types[ t ] ) || [];
			type = origType = tmp[ 1 ];
			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();

			// Unbind all events (on this namespace, if provided) for the element
			if ( !type ) {
				for ( type in events ) {
					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
				}
				continue;
			}

			special = jQuery.event.special[ type ] || {};
			type = ( selector ? special.delegateType : special.bindType ) || type;
			handlers = events[ type ] || [];
			tmp = tmp[ 2 ] &&
				new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );

			// Remove matching events
			origCount = j = handlers.length;
			while ( j-- ) {
				handleObj = handlers[ j ];

				if ( ( mappedTypes || origType === handleObj.origType ) &&
					( !handler || handler.guid === handleObj.guid ) &&
					( !tmp || tmp.test( handleObj.namespace ) ) &&
					( !selector || selector === handleObj.selector ||
						selector === "**" && handleObj.selector ) ) {
					handlers.splice( j, 1 );

					if ( handleObj.selector ) {
						handlers.delegateCount--;
					}
					if ( special.remove ) {
						special.remove.call( elem, handleObj );
					}
				}
			}

			// Remove generic event handler if we removed something and no more handlers exist
			// (avoids potential for endless recursion during removal of special event handlers)
			if ( origCount && !handlers.length ) {
				if ( !special.teardown ||
					special.teardown.call( elem, namespaces, elemData.handle ) === false ) {

					jQuery.removeEvent( elem, type, elemData.handle );
				}

				delete events[ type ];
			}
		}

		// Remove the expando if it's no longer used
		if ( jQuery.isEmptyObject( events ) ) {
			delete elemData.handle;

			// removeData also checks for emptiness and clears the expando if empty
			// so use it instead of delete
			jQuery._removeData( elem, "events" );
		}
	},

	trigger: function( event, data, elem, onlyHandlers ) {
		var handle, ontype, cur,
			bubbleType, special, tmp, i,
			eventPath = [ elem || document ],
			type = hasOwn.call( event, "type" ) ? event.type : event,
			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];

		cur = tmp = elem = elem || document;

		// Don't do events on text and comment nodes
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		// focus/blur morphs to focusin/out; ensure we're not firing them right now
		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
			return;
		}

		if ( type.indexOf( "." ) > -1 ) {

			// Namespaced trigger; create a regexp to match event type in handle()
			namespaces = type.split( "." );
			type = namespaces.shift();
			namespaces.sort();
		}
		ontype = type.indexOf( ":" ) < 0 && "on" + type;

		// Caller can pass in a jQuery.Event object, Object, or just an event type string
		event = event[ jQuery.expando ] ?
			event :
			new jQuery.Event( type, typeof event === "object" && event );

		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
		event.isTrigger = onlyHandlers ? 2 : 3;
		event.namespace = namespaces.join( "." );
		event.rnamespace = event.namespace ?
			new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
			null;

		// Clean up the event in case it is being reused
		event.result = undefined;
		if ( !event.target ) {
			event.target = elem;
		}

		// Clone any incoming data and prepend the event, creating the handler arg list
		data = data == null ?
			[ event ] :
			jQuery.makeArray( data, [ event ] );

		// Allow special events to draw outside the lines
		special = jQuery.event.special[ type ] || {};
		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
			return;
		}

		// Determine event propagation path in advance, per W3C events spec (#9951)
		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {

			bubbleType = special.delegateType || type;
			if ( !rfocusMorph.test( bubbleType + type ) ) {
				cur = cur.parentNode;
			}
			for ( ; cur; cur = cur.parentNode ) {
				eventPath.push( cur );
				tmp = cur;
			}

			// Only add window if we got to document (e.g., not plain obj or detached DOM)
			if ( tmp === ( elem.ownerDocument || document ) ) {
				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
			}
		}

		// Fire handlers on the event path
		i = 0;
		while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {

			event.type = i > 1 ?
				bubbleType :
				special.bindType || type;

			// jQuery handler
			handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] &&
				jQuery._data( cur, "handle" );

			if ( handle ) {
				handle.apply( cur, data );
			}

			// Native handler
			handle = ontype && cur[ ontype ];
			if ( handle && handle.apply && acceptData( cur ) ) {
				event.result = handle.apply( cur, data );
				if ( event.result === false ) {
					event.preventDefault();
				}
			}
		}
		event.type = type;

		// If nobody prevented the default action, do it now
		if ( !onlyHandlers && !event.isDefaultPrevented() ) {

			if (
				( !special._default ||
				 special._default.apply( eventPath.pop(), data ) === false
				) && acceptData( elem )
			) {

				// Call a native DOM method on the target with the same name name as the event.
				// Can't use an .isFunction() check here because IE6/7 fails that test.
				// Don't do default actions on window, that's where global variables be (#6170)
				if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {

					// Don't re-trigger an onFOO event when we call its FOO() method
					tmp = elem[ ontype ];

					if ( tmp ) {
						elem[ ontype ] = null;
					}

					// Prevent re-triggering of the same event, since we already bubbled it above
					jQuery.event.triggered = type;
					try {
						elem[ type ]();
					} catch ( e ) {

						// IE<9 dies on focus/blur to hidden element (#1486,#12518)
						// only reproducible on winXP IE8 native, not IE9 in IE8 mode
					}
					jQuery.event.triggered = undefined;

					if ( tmp ) {
						elem[ ontype ] = tmp;
					}
				}
			}
		}

		return event.result;
	},

	dispatch: function( event ) {

		// Make a writable jQuery.Event from the native event object
		event = jQuery.event.fix( event );

		var i, j, ret, matched, handleObj,
			handlerQueue = [],
			args = slice.call( arguments ),
			handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
			special = jQuery.event.special[ event.type ] || {};

		// Use the fix-ed jQuery.Event rather than the (read-only) native event
		args[ 0 ] = event;
		event.delegateTarget = this;

		// Call the preDispatch hook for the mapped type, and let it bail if desired
		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
			return;
		}

		// Determine handlers
		handlerQueue = jQuery.event.handlers.call( this, event, handlers );

		// Run delegates first; they may want to stop propagation beneath us
		i = 0;
		while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
			event.currentTarget = matched.elem;

			j = 0;
			while ( ( handleObj = matched.handlers[ j++ ] ) &&
				!event.isImmediatePropagationStopped() ) {

				// Triggered event must either 1) have no namespace, or 2) have namespace(s)
				// a subset or equal to those in the bound event (both can have no namespace).
				if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {

					event.handleObj = handleObj;
					event.data = handleObj.data;

					ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
						handleObj.handler ).apply( matched.elem, args );

					if ( ret !== undefined ) {
						if ( ( event.result = ret ) === false ) {
							event.preventDefault();
							event.stopPropagation();
						}
					}
				}
			}
		}

		// Call the postDispatch hook for the mapped type
		if ( special.postDispatch ) {
			special.postDispatch.call( this, event );
		}

		return event.result;
	},

	handlers: function( event, handlers ) {
		var i, matches, sel, handleObj,
			handlerQueue = [],
			delegateCount = handlers.delegateCount,
			cur = event.target;

		// Support (at least): Chrome, IE9
		// Find delegate handlers
		// Black-hole SVG <use> instance trees (#13180)
		//
		// Support: Firefox<=42+
		// Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)
		if ( delegateCount && cur.nodeType &&
			( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {

			/* jshint eqeqeq: false */
			for ( ; cur != this; cur = cur.parentNode || this ) {
				/* jshint eqeqeq: true */

				// Don't check non-elements (#13208)
				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
				if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) {
					matches = [];
					for ( i = 0; i < delegateCount; i++ ) {
						handleObj = handlers[ i ];

						// Don't conflict with Object.prototype properties (#13203)
						sel = handleObj.selector + " ";

						if ( matches[ sel ] === undefined ) {
							matches[ sel ] = handleObj.needsContext ?
								jQuery( sel, this ).index( cur ) > -1 :
								jQuery.find( sel, this, null, [ cur ] ).length;
						}
						if ( matches[ sel ] ) {
							matches.push( handleObj );
						}
					}
					if ( matches.length ) {
						handlerQueue.push( { elem: cur, handlers: matches } );
					}
				}
			}
		}

		// Add the remaining (directly-bound) handlers
		if ( delegateCount < handlers.length ) {
			handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } );
		}

		return handlerQueue;
	},

	fix: function( event ) {
		if ( event[ jQuery.expando ] ) {
			return event;
		}

		// Create a writable copy of the event object and normalize some properties
		var i, prop, copy,
			type = event.type,
			originalEvent = event,
			fixHook = this.fixHooks[ type ];

		if ( !fixHook ) {
			this.fixHooks[ type ] = fixHook =
				rmouseEvent.test( type ) ? this.mouseHooks :
				rkeyEvent.test( type ) ? this.keyHooks :
				{};
		}
		copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;

		event = new jQuery.Event( originalEvent );

		i = copy.length;
		while ( i-- ) {
			prop = copy[ i ];
			event[ prop ] = originalEvent[ prop ];
		}

		// Support: IE<9
		// Fix target property (#1925)
		if ( !event.target ) {
			event.target = originalEvent.srcElement || document;
		}

		// Support: Safari 6-8+
		// Target should not be a text node (#504, #13143)
		if ( event.target.nodeType === 3 ) {
			event.target = event.target.parentNode;
		}

		// Support: IE<9
		// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
		event.metaKey = !!event.metaKey;

		return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
	},

	// Includes some event props shared by KeyEvent and MouseEvent
	props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " +
		"metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ),

	fixHooks: {},

	keyHooks: {
		props: "char charCode key keyCode".split( " " ),
		filter: function( event, original ) {

			// Add which for key events
			if ( event.which == null ) {
				event.which = original.charCode != null ? original.charCode : original.keyCode;
			}

			return event;
		}
	},

	mouseHooks: {
		props: ( "button buttons clientX clientY fromElement offsetX offsetY " +
			"pageX pageY screenX screenY toElement" ).split( " " ),
		filter: function( event, original ) {
			var body, eventDoc, doc,
				button = original.button,
				fromElement = original.fromElement;

			// Calculate pageX/Y if missing and clientX/Y available
			if ( event.pageX == null && original.clientX != null ) {
				eventDoc = event.target.ownerDocument || document;
				doc = eventDoc.documentElement;
				body = eventDoc.body;

				event.pageX = original.clientX +
					( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
					( doc && doc.clientLeft || body && body.clientLeft || 0 );
				event.pageY = original.clientY +
					( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) -
					( doc && doc.clientTop  || body && body.clientTop  || 0 );
			}

			// Add relatedTarget, if necessary
			if ( !event.relatedTarget && fromElement ) {
				event.relatedTarget = fromElement === event.target ?
					original.toElement :
					fromElement;
			}

			// Add which for click: 1 === left; 2 === middle; 3 === right
			// Note: button is not normalized, so don't use it
			if ( !event.which && button !== undefined ) {
				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
			}

			return event;
		}
	},

	special: {
		load: {

			// Prevent triggered image.load events from bubbling to window.load
			noBubble: true
		},
		focus: {

			// Fire native event if possible so blur/focus sequence is correct
			trigger: function() {
				if ( this !== safeActiveElement() && this.focus ) {
					try {
						this.focus();
						return false;
					} catch ( e ) {

						// Support: IE<9
						// If we error on focus to hidden element (#1486, #12518),
						// let .trigger() run the handlers
					}
				}
			},
			delegateType: "focusin"
		},
		blur: {
			trigger: function() {
				if ( this === safeActiveElement() && this.blur ) {
					this.blur();
					return false;
				}
			},
			delegateType: "focusout"
		},
		click: {

			// For checkbox, fire native event so checked state will be right
			trigger: function() {
				if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
					this.click();
					return false;
				}
			},

			// For cross-browser consistency, don't fire native .click() on links
			_default: function( event ) {
				return jQuery.nodeName( event.target, "a" );
			}
		},

		beforeunload: {
			postDispatch: function( event ) {

				// Support: Firefox 20+
				// Firefox doesn't alert if the returnValue field is not set.
				if ( event.result !== undefined && event.originalEvent ) {
					event.originalEvent.returnValue = event.result;
				}
			}
		}
	},

	// Piggyback on a donor event to simulate a different one
	simulate: function( type, elem, event ) {
		var e = jQuery.extend(
			new jQuery.Event(),
			event,
			{
				type: type,
				isSimulated: true

				// Previously, `originalEvent: {}` was set here, so stopPropagation call
				// would not be triggered on donor event, since in our own
				// jQuery.event.stopPropagation function we had a check for existence of
				// originalEvent.stopPropagation method, so, consequently it would be a noop.
				//
				// Guard for simulated events was moved to jQuery.event.stopPropagation function
				// since `originalEvent` should point to the original event for the
				// constancy with other events and for more focused logic
			}
		);

		jQuery.event.trigger( e, null, elem );

		if ( e.isDefaultPrevented() ) {
			event.preventDefault();
		}
	}
};

jQuery.removeEvent = document.removeEventListener ?
	function( elem, type, handle ) {

		// This "if" is needed for plain objects
		if ( elem.removeEventListener ) {
			elem.removeEventListener( type, handle );
		}
	} :
	function( elem, type, handle ) {
		var name = "on" + type;

		if ( elem.detachEvent ) {

			// #8545, #7054, preventing memory leaks for custom events in IE6-8
			// detachEvent needed property on element, by name of that event,
			// to properly expose it to GC
			if ( typeof elem[ name ] === "undefined" ) {
				elem[ name ] = null;
			}

			elem.detachEvent( name, handle );
		}
	};

jQuery.Event = function( src, props ) {

	// Allow instantiation without the 'new' keyword
	if ( !( this instanceof jQuery.Event ) ) {
		return new jQuery.Event( src, props );
	}

	// Event object
	if ( src && src.type ) {
		this.originalEvent = src;
		this.type = src.type;

		// Events bubbling up the document may have been marked as prevented
		// by a handler lower down the tree; reflect the correct value.
		this.isDefaultPrevented = src.defaultPrevented ||
				src.defaultPrevented === undefined &&

				// Support: IE < 9, Android < 4.0
				src.returnValue === false ?
			returnTrue :
			returnFalse;

	// Event type
	} else {
		this.type = src;
	}

	// Put explicitly provided properties onto the event object
	if ( props ) {
		jQuery.extend( this, props );
	}

	// Create a timestamp if incoming event doesn't have one
	this.timeStamp = src && src.timeStamp || jQuery.now();

	// Mark it as fixed
	this[ jQuery.expando ] = true;
};

// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
	constructor: jQuery.Event,
	isDefaultPrevented: returnFalse,
	isPropagationStopped: returnFalse,
	isImmediatePropagationStopped: returnFalse,

	preventDefault: function() {
		var e = this.originalEvent;

		this.isDefaultPrevented = returnTrue;
		if ( !e ) {
			return;
		}

		// If preventDefault exists, run it on the original event
		if ( e.preventDefault ) {
			e.preventDefault();

		// Support: IE
		// Otherwise set the returnValue property of the original event to false
		} else {
			e.returnValue = false;
		}
	},
	stopPropagation: function() {
		var e = this.originalEvent;

		this.isPropagationStopped = returnTrue;

		if ( !e || this.isSimulated ) {
			return;
		}

		// If stopPropagation exists, run it on the original event
		if ( e.stopPropagation ) {
			e.stopPropagation();
		}

		// Support: IE
		// Set the cancelBubble property of the original event to true
		e.cancelBubble = true;
	},
	stopImmediatePropagation: function() {
		var e = this.originalEvent;

		this.isImmediatePropagationStopped = returnTrue;

		if ( e && e.stopImmediatePropagation ) {
			e.stopImmediatePropagation();
		}

		this.stopPropagation();
	}
};

// Create mouseenter/leave events using mouseover/out and event-time checks
// so that event delegation works in jQuery.
// Do the same for pointerenter/pointerleave and pointerover/pointerout
//
// Support: Safari 7 only
// Safari sends mouseenter too often; see:
// https://code.google.com/p/chromium/issues/detail?id=470258
// for the description of the bug (it existed in older Chrome versions as well).
jQuery.each( {
	mouseenter: "mouseover",
	mouseleave: "mouseout",
	pointerenter: "pointerover",
	pointerleave: "pointerout"
}, function( orig, fix ) {
	jQuery.event.special[ orig ] = {
		delegateType: fix,
		bindType: fix,

		handle: function( event ) {
			var ret,
				target = this,
				related = event.relatedTarget,
				handleObj = event.handleObj;

			// For mouseenter/leave call the handler if related is outside the target.
			// NB: No relatedTarget if the mouse left/entered the browser window
			if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
				event.type = handleObj.origType;
				ret = handleObj.handler.apply( this, arguments );
				event.type = fix;
			}
			return ret;
		}
	};
} );

// IE submit delegation
if ( !support.submit ) {

	jQuery.event.special.submit = {
		setup: function() {

			// Only need this for delegated form submit events
			if ( jQuery.nodeName( this, "form" ) ) {
				return false;
			}

			// Lazy-add a submit handler when a descendant form may potentially be submitted
			jQuery.event.add( this, "click._submit keypress._submit", function( e ) {

				// Node name check avoids a VML-related crash in IE (#9807)
				var elem = e.target,
					form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ?

						// Support: IE <=8
						// We use jQuery.prop instead of elem.form
						// to allow fixing the IE8 delegated submit issue (gh-2332)
						// by 3rd party polyfills/workarounds.
						jQuery.prop( elem, "form" ) :
						undefined;

				if ( form && !jQuery._data( form, "submit" ) ) {
					jQuery.event.add( form, "submit._submit", function( event ) {
						event._submitBubble = true;
					} );
					jQuery._data( form, "submit", true );
				}
			} );

			// return undefined since we don't need an event listener
		},

		postDispatch: function( event ) {

			// If form was submitted by the user, bubble the event up the tree
			if ( event._submitBubble ) {
				delete event._submitBubble;
				if ( this.parentNode && !event.isTrigger ) {
					jQuery.event.simulate( "submit", this.parentNode, event );
				}
			}
		},

		teardown: function() {

			// Only need this for delegated form submit events
			if ( jQuery.nodeName( this, "form" ) ) {
				return false;
			}

			// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
			jQuery.event.remove( this, "._submit" );
		}
	};
}

// IE change delegation and checkbox/radio fix
if ( !support.change ) {

	jQuery.event.special.change = {

		setup: function() {

			if ( rformElems.test( this.nodeName ) ) {

				// IE doesn't fire change on a check/radio until blur; trigger it on click
				// after a propertychange. Eat the blur-change in special.change.handle.
				// This still fires onchange a second time for check/radio after blur.
				if ( this.type === "checkbox" || this.type === "radio" ) {
					jQuery.event.add( this, "propertychange._change", function( event ) {
						if ( event.originalEvent.propertyName === "checked" ) {
							this._justChanged = true;
						}
					} );
					jQuery.event.add( this, "click._change", function( event ) {
						if ( this._justChanged && !event.isTrigger ) {
							this._justChanged = false;
						}

						// Allow triggered, simulated change events (#11500)
						jQuery.event.simulate( "change", this, event );
					} );
				}
				return false;
			}

			// Delegated event; lazy-add a change handler on descendant inputs
			jQuery.event.add( this, "beforeactivate._change", function( e ) {
				var elem = e.target;

				if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "change" ) ) {
					jQuery.event.add( elem, "change._change", function( event ) {
						if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
							jQuery.event.simulate( "change", this.parentNode, event );
						}
					} );
					jQuery._data( elem, "change", true );
				}
			} );
		},

		handle: function( event ) {
			var elem = event.target;

			// Swallow native change events from checkbox/radio, we already triggered them above
			if ( this !== elem || event.isSimulated || event.isTrigger ||
				( elem.type !== "radio" && elem.type !== "checkbox" ) ) {

				return event.handleObj.handler.apply( this, arguments );
			}
		},

		teardown: function() {
			jQuery.event.remove( this, "._change" );

			return !rformElems.test( this.nodeName );
		}
	};
}

// Support: Firefox
// Firefox doesn't have focus(in | out) events
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
//
// Support: Chrome, Safari
// focus(in | out) events fire after focus & blur events,
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857
if ( !support.focusin ) {
	jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {

		// Attach a single capturing handler on the document while someone wants focusin/focusout
		var handler = function( event ) {
			jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
		};

		jQuery.event.special[ fix ] = {
			setup: function() {
				var doc = this.ownerDocument || this,
					attaches = jQuery._data( doc, fix );

				if ( !attaches ) {
					doc.addEventListener( orig, handler, true );
				}
				jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
			},
			teardown: function() {
				var doc = this.ownerDocument || this,
					attaches = jQuery._data( doc, fix ) - 1;

				if ( !attaches ) {
					doc.removeEventListener( orig, handler, true );
					jQuery._removeData( doc, fix );
				} else {
					jQuery._data( doc, fix, attaches );
				}
			}
		};
	} );
}

jQuery.fn.extend( {

	on: function( types, selector, data, fn ) {
		return on( this, types, selector, data, fn );
	},
	one: function( types, selector, data, fn ) {
		return on( this, types, selector, data, fn, 1 );
	},
	off: function( types, selector, fn ) {
		var handleObj, type;
		if ( types && types.preventDefault && types.handleObj ) {

			// ( event )  dispatched jQuery.Event
			handleObj = types.handleObj;
			jQuery( types.delegateTarget ).off(
				handleObj.namespace ?
					handleObj.origType + "." + handleObj.namespace :
					handleObj.origType,
				handleObj.selector,
				handleObj.handler
			);
			return this;
		}
		if ( typeof types === "object" ) {

			// ( types-object [, selector] )
			for ( type in types ) {
				this.off( type, selector, types[ type ] );
			}
			return this;
		}
		if ( selector === false || typeof selector === "function" ) {

			// ( types [, fn] )
			fn = selector;
			selector = undefined;
		}
		if ( fn === false ) {
			fn = returnFalse;
		}
		return this.each( function() {
			jQuery.event.remove( this, types, fn, selector );
		} );
	},

	trigger: function( type, data ) {
		return this.each( function() {
			jQuery.event.trigger( type, data, this );
		} );
	},
	triggerHandler: function( type, data ) {
		var elem = this[ 0 ];
		if ( elem ) {
			return jQuery.event.trigger( type, data, elem, true );
		}
	}
} );


var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
	rnoshimcache = new RegExp( "<(?:" + nodeNames + ")[\\s/>]", "i" ),
	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,

	// Support: IE 10-11, Edge 10240+
	// In IE/Edge using regex groups here causes severe slowdowns.
	// See https://connect.microsoft.com/IE/feedback/details/1736512/
	rnoInnerhtml = /<script|<style|<link/i,

	// checked="checked" or checked
	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
	rscriptTypeMasked = /^true\/(.*)/,
	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
	safeFragment = createSafeFragment( document ),
	fragmentDiv = safeFragment.appendChild( document.createElement( "div" ) );

// Support: IE<8
// Manipulating tables requires a tbody
function manipulationTarget( elem, content ) {
	return jQuery.nodeName( elem, "table" ) &&
		jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?

		elem.getElementsByTagName( "tbody" )[ 0 ] ||
			elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) :
		elem;
}

// Replace/restore the type attribute of script elements for safe DOM manipulation
function disableScript( elem ) {
	elem.type = ( jQuery.find.attr( elem, "type" ) !== null ) + "/" + elem.type;
	return elem;
}
function restoreScript( elem ) {
	var match = rscriptTypeMasked.exec( elem.type );
	if ( match ) {
		elem.type = match[ 1 ];
	} else {
		elem.removeAttribute( "type" );
	}
	return elem;
}

function cloneCopyEvent( src, dest ) {
	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
		return;
	}

	var type, i, l,
		oldData = jQuery._data( src ),
		curData = jQuery._data( dest, oldData ),
		events = oldData.events;

	if ( events ) {
		delete curData.handle;
		curData.events = {};

		for ( type in events ) {
			for ( i = 0, l = events[ type ].length; i < l; i++ ) {
				jQuery.event.add( dest, type, events[ type ][ i ] );
			}
		}
	}

	// make the cloned public data object a copy from the original
	if ( curData.data ) {
		curData.data = jQuery.extend( {}, curData.data );
	}
}

function fixCloneNodeIssues( src, dest ) {
	var nodeName, e, data;

	// We do not need to do anything for non-Elements
	if ( dest.nodeType !== 1 ) {
		return;
	}

	nodeName = dest.nodeName.toLowerCase();

	// IE6-8 copies events bound via attachEvent when using cloneNode.
	if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
		data = jQuery._data( dest );

		for ( e in data.events ) {
			jQuery.removeEvent( dest, e, data.handle );
		}

		// Event data gets referenced instead of copied if the expando gets copied too
		dest.removeAttribute( jQuery.expando );
	}

	// IE blanks contents when cloning scripts, and tries to evaluate newly-set text
	if ( nodeName === "script" && dest.text !== src.text ) {
		disableScript( dest ).text = src.text;
		restoreScript( dest );

	// IE6-10 improperly clones children of object elements using classid.
	// IE10 throws NoModificationAllowedError if parent is null, #12132.
	} else if ( nodeName === "object" ) {
		if ( dest.parentNode ) {
			dest.outerHTML = src.outerHTML;
		}

		// This path appears unavoidable for IE9. When cloning an object
		// element in IE9, the outerHTML strategy above is not sufficient.
		// If the src has innerHTML and the destination does not,
		// copy the src.innerHTML into the dest.innerHTML. #10324
		if ( support.html5Clone && ( src.innerHTML && !jQuery.trim( dest.innerHTML ) ) ) {
			dest.innerHTML = src.innerHTML;
		}

	} else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {

		// IE6-8 fails to persist the checked state of a cloned checkbox
		// or radio button. Worse, IE6-7 fail to give the cloned element
		// a checked appearance if the defaultChecked value isn't also set

		dest.defaultChecked = dest.checked = src.checked;

		// IE6-7 get confused and end up setting the value of a cloned
		// checkbox/radio button to an empty string instead of "on"
		if ( dest.value !== src.value ) {
			dest.value = src.value;
		}

	// IE6-8 fails to return the selected option to the default selected
	// state when cloning options
	} else if ( nodeName === "option" ) {
		dest.defaultSelected = dest.selected = src.defaultSelected;

	// IE6-8 fails to set the defaultValue to the correct value when
	// cloning other types of input fields
	} else if ( nodeName === "input" || nodeName === "textarea" ) {
		dest.defaultValue = src.defaultValue;
	}
}

function domManip( collection, args, callback, ignored ) {

	// Flatten any nested arrays
	args = concat.apply( [], args );

	var first, node, hasScripts,
		scripts, doc, fragment,
		i = 0,
		l = collection.length,
		iNoClone = l - 1,
		value = args[ 0 ],
		isFunction = jQuery.isFunction( value );

	// We can't cloneNode fragments that contain checked, in WebKit
	if ( isFunction ||
			( l > 1 && typeof value === "string" &&
				!support.checkClone && rchecked.test( value ) ) ) {
		return collection.each( function( index ) {
			var self = collection.eq( index );
			if ( isFunction ) {
				args[ 0 ] = value.call( this, index, self.html() );
			}
			domManip( self, args, callback, ignored );
		} );
	}

	if ( l ) {
		fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
		first = fragment.firstChild;

		if ( fragment.childNodes.length === 1 ) {
			fragment = first;
		}

		// Require either new content or an interest in ignored elements to invoke the callback
		if ( first || ignored ) {
			scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
			hasScripts = scripts.length;

			// Use the original fragment for the last item
			// instead of the first because it can end up
			// being emptied incorrectly in certain situations (#8070).
			for ( ; i < l; i++ ) {
				node = fragment;

				if ( i !== iNoClone ) {
					node = jQuery.clone( node, true, true );

					// Keep references to cloned scripts for later restoration
					if ( hasScripts ) {

						// Support: Android<4.1, PhantomJS<2
						// push.apply(_, arraylike) throws on ancient WebKit
						jQuery.merge( scripts, getAll( node, "script" ) );
					}
				}

				callback.call( collection[ i ], node, i );
			}

			if ( hasScripts ) {
				doc = scripts[ scripts.length - 1 ].ownerDocument;

				// Reenable scripts
				jQuery.map( scripts, restoreScript );

				// Evaluate executable scripts on first document insertion
				for ( i = 0; i < hasScripts; i++ ) {
					node = scripts[ i ];
					if ( rscriptType.test( node.type || "" ) &&
						!jQuery._data( node, "globalEval" ) &&
						jQuery.contains( doc, node ) ) {

						if ( node.src ) {

							// Optional AJAX dependency, but won't run scripts if not present
							if ( jQuery._evalUrl ) {
								jQuery._evalUrl( node.src );
							}
						} else {
							jQuery.globalEval(
								( node.text || node.textContent || node.innerHTML || "" )
									.replace( rcleanScript, "" )
							);
						}
					}
				}
			}

			// Fix #11809: Avoid leaking memory
			fragment = first = null;
		}
	}

	return collection;
}

function remove( elem, selector, keepData ) {
	var node,
		elems = selector ? jQuery.filter( selector, elem ) : elem,
		i = 0;

	for ( ; ( node = elems[ i ] ) != null; i++ ) {

		if ( !keepData && node.nodeType === 1 ) {
			jQuery.cleanData( getAll( node ) );
		}

		if ( node.parentNode ) {
			if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
				setGlobalEval( getAll( node, "script" ) );
			}
			node.parentNode.removeChild( node );
		}
	}

	return elem;
}

jQuery.extend( {
	htmlPrefilter: function( html ) {
		return html.replace( rxhtmlTag, "<$1></$2>" );
	},

	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
		var destElements, node, clone, i, srcElements,
			inPage = jQuery.contains( elem.ownerDocument, elem );

		if ( support.html5Clone || jQuery.isXMLDoc( elem ) ||
			!rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {

			clone = elem.cloneNode( true );

		// IE<=8 does not properly clone detached, unknown element nodes
		} else {
			fragmentDiv.innerHTML = elem.outerHTML;
			fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
		}

		if ( ( !support.noCloneEvent || !support.noCloneChecked ) &&
				( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) {

			// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
			destElements = getAll( clone );
			srcElements = getAll( elem );

			// Fix all IE cloning issues
			for ( i = 0; ( node = srcElements[ i ] ) != null; ++i ) {

				// Ensure that the destination node is not null; Fixes #9587
				if ( destElements[ i ] ) {
					fixCloneNodeIssues( node, destElements[ i ] );
				}
			}
		}

		// Copy the events from the original to the clone
		if ( dataAndEvents ) {
			if ( deepDataAndEvents ) {
				srcElements = srcElements || getAll( elem );
				destElements = destElements || getAll( clone );

				for ( i = 0; ( node = srcElements[ i ] ) != null; i++ ) {
					cloneCopyEvent( node, destElements[ i ] );
				}
			} else {
				cloneCopyEvent( elem, clone );
			}
		}

		// Preserve script evaluation history
		destElements = getAll( clone, "script" );
		if ( destElements.length > 0 ) {
			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
		}

		destElements = srcElements = node = null;

		// Return the cloned set
		return clone;
	},

	cleanData: function( elems, /* internal */ forceAcceptData ) {
		var elem, type, id, data,
			i = 0,
			internalKey = jQuery.expando,
			cache = jQuery.cache,
			attributes = support.attributes,
			special = jQuery.event.special;

		for ( ; ( elem = elems[ i ] ) != null; i++ ) {
			if ( forceAcceptData || acceptData( elem ) ) {

				id = elem[ internalKey ];
				data = id && cache[ id ];

				if ( data ) {
					if ( data.events ) {
						for ( type in data.events ) {
							if ( special[ type ] ) {
								jQuery.event.remove( elem, type );

							// This is a shortcut to avoid jQuery.event.remove's overhead
							} else {
								jQuery.removeEvent( elem, type, data.handle );
							}
						}
					}

					// Remove cache only if it was not already removed by jQuery.event.remove
					if ( cache[ id ] ) {

						delete cache[ id ];

						// Support: IE<9
						// IE does not allow us to delete expando properties from nodes
						// IE creates expando attributes along with the property
						// IE does not have a removeAttribute function on Document nodes
						if ( !attributes && typeof elem.removeAttribute !== "undefined" ) {
							elem.removeAttribute( internalKey );

						// Webkit & Blink performance suffers when deleting properties
						// from DOM nodes, so set to undefined instead
						// https://code.google.com/p/chromium/issues/detail?id=378607
						} else {
							elem[ internalKey ] = undefined;
						}

						deletedIds.push( id );
					}
				}
			}
		}
	}
} );

jQuery.fn.extend( {

	// Keep domManip exposed until 3.0 (gh-2225)
	domManip: domManip,

	detach: function( selector ) {
		return remove( this, selector, true );
	},

	remove: function( selector ) {
		return remove( this, selector );
	},

	text: function( value ) {
		return access( this, function( value ) {
			return value === undefined ?
				jQuery.text( this ) :
				this.empty().append(
					( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value )
				);
		}, null, value, arguments.length );
	},

	append: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
				var target = manipulationTarget( this, elem );
				target.appendChild( elem );
			}
		} );
	},

	prepend: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
				var target = manipulationTarget( this, elem );
				target.insertBefore( elem, target.firstChild );
			}
		} );
	},

	before: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.parentNode ) {
				this.parentNode.insertBefore( elem, this );
			}
		} );
	},

	after: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.parentNode ) {
				this.parentNode.insertBefore( elem, this.nextSibling );
			}
		} );
	},

	empty: function() {
		var elem,
			i = 0;

		for ( ; ( elem = this[ i ] ) != null; i++ ) {

			// Remove element nodes and prevent memory leaks
			if ( elem.nodeType === 1 ) {
				jQuery.cleanData( getAll( elem, false ) );
			}

			// Remove any remaining nodes
			while ( elem.firstChild ) {
				elem.removeChild( elem.firstChild );
			}

			// If this is a select, ensure that it displays empty (#12336)
			// Support: IE<9
			if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
				elem.options.length = 0;
			}
		}

		return this;
	},

	clone: function( dataAndEvents, deepDataAndEvents ) {
		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;

		return this.map( function() {
			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
		} );
	},

	html: function( value ) {
		return access( this, function( value ) {
			var elem = this[ 0 ] || {},
				i = 0,
				l = this.length;

			if ( value === undefined ) {
				return elem.nodeType === 1 ?
					elem.innerHTML.replace( rinlinejQuery, "" ) :
					undefined;
			}

			// See if we can take a shortcut and just use innerHTML
			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
				( support.htmlSerialize || !rnoshimcache.test( value )  ) &&
				( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
				!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {

				value = jQuery.htmlPrefilter( value );

				try {
					for ( ; i < l; i++ ) {

						// Remove element nodes and prevent memory leaks
						elem = this[ i ] || {};
						if ( elem.nodeType === 1 ) {
							jQuery.cleanData( getAll( elem, false ) );
							elem.innerHTML = value;
						}
					}

					elem = 0;

				// If using innerHTML throws an exception, use the fallback method
				} catch ( e ) {}
			}

			if ( elem ) {
				this.empty().append( value );
			}
		}, null, value, arguments.length );
	},

	replaceWith: function() {
		var ignored = [];

		// Make the changes, replacing each non-ignored context element with the new content
		return domManip( this, arguments, function( elem ) {
			var parent = this.parentNode;

			if ( jQuery.inArray( this, ignored ) < 0 ) {
				jQuery.cleanData( getAll( this ) );
				if ( parent ) {
					parent.replaceChild( elem, this );
				}
			}

		// Force callback invocation
		}, ignored );
	}
} );

jQuery.each( {
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after",
	replaceAll: "replaceWith"
}, function( name, original ) {
	jQuery.fn[ name ] = function( selector ) {
		var elems,
			i = 0,
			ret = [],
			insert = jQuery( selector ),
			last = insert.length - 1;

		for ( ; i <= last; i++ ) {
			elems = i === last ? this : this.clone( true );
			jQuery( insert[ i ] )[ original ]( elems );

			// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
			push.apply( ret, elems.get() );
		}

		return this.pushStack( ret );
	};
} );


var iframe,
	elemdisplay = {

		// Support: Firefox
		// We have to pre-define these values for FF (#10227)
		HTML: "block",
		BODY: "block"
	};

/**
 * Retrieve the actual display of a element
 * @param {String} name nodeName of the element
 * @param {Object} doc Document object
 */

// Called only from within defaultDisplay
function actualDisplay( name, doc ) {
	var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),

		display = jQuery.css( elem[ 0 ], "display" );

	// We don't have any data stored on the element,
	// so use "detach" method as fast way to get rid of the element
	elem.detach();

	return display;
}

/**
 * Try to determine the default display value of an element
 * @param {String} nodeName
 */
function defaultDisplay( nodeName ) {
	var doc = document,
		display = elemdisplay[ nodeName ];

	if ( !display ) {
		display = actualDisplay( nodeName, doc );

		// If the simple way fails, read from inside an iframe
		if ( display === "none" || !display ) {

			// Use the already-created iframe if possible
			iframe = ( iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" ) )
				.appendTo( doc.documentElement );

			// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
			doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;

			// Support: IE
			doc.write();
			doc.close();

			display = actualDisplay( nodeName, doc );
			iframe.detach();
		}

		// Store the correct default display
		elemdisplay[ nodeName ] = display;
	}

	return display;
}
var rmargin = ( /^margin/ );

var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );

var swap = function( elem, options, callback, args ) {
	var ret, name,
		old = {};

	// Remember the old values, and insert the new ones
	for ( name in options ) {
		old[ name ] = elem.style[ name ];
		elem.style[ name ] = options[ name ];
	}

	ret = callback.apply( elem, args || [] );

	// Revert the old values
	for ( name in options ) {
		elem.style[ name ] = old[ name ];
	}

	return ret;
};


var documentElement = document.documentElement;



( function() {
	var pixelPositionVal, pixelMarginRightVal, boxSizingReliableVal,
		reliableHiddenOffsetsVal, reliableMarginRightVal, reliableMarginLeftVal,
		container = document.createElement( "div" ),
		div = document.createElement( "div" );

	// Finish early in limited (non-browser) environments
	if ( !div.style ) {
		return;
	}

	div.style.cssText = "float:left;opacity:.5";

	// Support: IE<9
	// Make sure that element opacity exists (as opposed to filter)
	support.opacity = div.style.opacity === "0.5";

	// Verify style float existence
	// (IE uses styleFloat instead of cssFloat)
	support.cssFloat = !!div.style.cssFloat;

	div.style.backgroundClip = "content-box";
	div.cloneNode( true ).style.backgroundClip = "";
	support.clearCloneStyle = div.style.backgroundClip === "content-box";

	container = document.createElement( "div" );
	container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
		"padding:0;margin-top:1px;position:absolute";
	div.innerHTML = "";
	container.appendChild( div );

	// Support: Firefox<29, Android 2.3
	// Vendor-prefix box-sizing
	support.boxSizing = div.style.boxSizing === "" || div.style.MozBoxSizing === "" ||
		div.style.WebkitBoxSizing === "";

	jQuery.extend( support, {
		reliableHiddenOffsets: function() {
			if ( pixelPositionVal == null ) {
				computeStyleTests();
			}
			return reliableHiddenOffsetsVal;
		},

		boxSizingReliable: function() {

			// We're checking for pixelPositionVal here instead of boxSizingReliableVal
			// since that compresses better and they're computed together anyway.
			if ( pixelPositionVal == null ) {
				computeStyleTests();
			}
			return boxSizingReliableVal;
		},

		pixelMarginRight: function() {

			// Support: Android 4.0-4.3
			if ( pixelPositionVal == null ) {
				computeStyleTests();
			}
			return pixelMarginRightVal;
		},

		pixelPosition: function() {
			if ( pixelPositionVal == null ) {
				computeStyleTests();
			}
			return pixelPositionVal;
		},

		reliableMarginRight: function() {

			// Support: Android 2.3
			if ( pixelPositionVal == null ) {
				computeStyleTests();
			}
			return reliableMarginRightVal;
		},

		reliableMarginLeft: function() {

			// Support: IE <=8 only, Android 4.0 - 4.3 only, Firefox <=3 - 37
			if ( pixelPositionVal == null ) {
				computeStyleTests();
			}
			return reliableMarginLeftVal;
		}
	} );

	function computeStyleTests() {
		var contents, divStyle,
			documentElement = document.documentElement;

		// Setup
		documentElement.appendChild( container );

		div.style.cssText =

			// Support: Android 2.3
			// Vendor-prefix box-sizing
			"-webkit-box-sizing:border-box;box-sizing:border-box;" +
			"position:relative;display:block;" +
			"margin:auto;border:1px;padding:1px;" +
			"top:1%;width:50%";

		// Support: IE<9
		// Assume reasonable values in the absence of getComputedStyle
		pixelPositionVal = boxSizingReliableVal = reliableMarginLeftVal = false;
		pixelMarginRightVal = reliableMarginRightVal = true;

		// Check for getComputedStyle so that this code is not run in IE<9.
		if ( window.getComputedStyle ) {
			divStyle = window.getComputedStyle( div );
			pixelPositionVal = ( divStyle || {} ).top !== "1%";
			reliableMarginLeftVal = ( divStyle || {} ).marginLeft === "2px";
			boxSizingReliableVal = ( divStyle || { width: "4px" } ).width === "4px";

			// Support: Android 4.0 - 4.3 only
			// Some styles come back with percentage values, even though they shouldn't
			div.style.marginRight = "50%";
			pixelMarginRightVal = ( divStyle || { marginRight: "4px" } ).marginRight === "4px";

			// Support: Android 2.3 only
			// Div with explicit width and no margin-right incorrectly
			// gets computed margin-right based on width of container (#3333)
			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
			contents = div.appendChild( document.createElement( "div" ) );

			// Reset CSS: box-sizing; display; margin; border; padding
			contents.style.cssText = div.style.cssText =

				// Support: Android 2.3
				// Vendor-prefix box-sizing
				"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
				"box-sizing:content-box;display:block;margin:0;border:0;padding:0";
			contents.style.marginRight = contents.style.width = "0";
			div.style.width = "1px";

			reliableMarginRightVal =
				!parseFloat( ( window.getComputedStyle( contents ) || {} ).marginRight );

			div.removeChild( contents );
		}

		// Support: IE6-8
		// First check that getClientRects works as expected
		// Check if table cells still have offsetWidth/Height when they are set
		// to display:none and there are still other visible table cells in a
		// table row; if so, offsetWidth/Height are not reliable for use when
		// determining if an element has been hidden directly using
		// display:none (it is still safe to use offsets if a parent element is
		// hidden; don safety goggles and see bug #4512 for more information).
		div.style.display = "none";
		reliableHiddenOffsetsVal = div.getClientRects().length === 0;
		if ( reliableHiddenOffsetsVal ) {
			div.style.display = "";
			div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
			contents = div.getElementsByTagName( "td" );
			contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
			reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
			if ( reliableHiddenOffsetsVal ) {
				contents[ 0 ].style.display = "";
				contents[ 1 ].style.display = "none";
				reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
			}
		}

		// Teardown
		documentElement.removeChild( container );
	}

} )();


var getStyles, curCSS,
	rposition = /^(top|right|bottom|left)$/;

if ( window.getComputedStyle ) {
	getStyles = function( elem ) {

		// Support: IE<=11+, Firefox<=30+ (#15098, #14150)
		// IE throws on elements created in popups
		// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
		var view = elem.ownerDocument.defaultView;

		if ( !view || !view.opener ) {
			view = window;
		}

		return view.getComputedStyle( elem );
	};

	curCSS = function( elem, name, computed ) {
		var width, minWidth, maxWidth, ret,
			style = elem.style;

		computed = computed || getStyles( elem );

		// getPropertyValue is only needed for .css('filter') in IE9, see #12537
		ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;

		// Support: Opera 12.1x only
		// Fall back to style even without computed
		// computed is undefined for elems on document fragments
		if ( ( ret === "" || ret === undefined ) && !jQuery.contains( elem.ownerDocument, elem ) ) {
			ret = jQuery.style( elem, name );
		}

		if ( computed ) {

			// A tribute to the "awesome hack by Dean Edwards"
			// Chrome < 17 and Safari 5.0 uses "computed value"
			// instead of "used value" for margin-right
			// Safari 5.1.7 (at least) returns percentage for a larger set of values,
			// but width seems to be reliably pixels
			// this is against the CSSOM draft spec:
			// http://dev.w3.org/csswg/cssom/#resolved-values
			if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {

				// Remember the original values
				width = style.width;
				minWidth = style.minWidth;
				maxWidth = style.maxWidth;

				// Put in the new values to get a computed value out
				style.minWidth = style.maxWidth = style.width = ret;
				ret = computed.width;

				// Revert the changed values
				style.width = width;
				style.minWidth = minWidth;
				style.maxWidth = maxWidth;
			}
		}

		// Support: IE
		// IE returns zIndex value as an integer.
		return ret === undefined ?
			ret :
			ret + "";
	};
} else if ( documentElement.currentStyle ) {
	getStyles = function( elem ) {
		return elem.currentStyle;
	};

	curCSS = function( elem, name, computed ) {
		var left, rs, rsLeft, ret,
			style = elem.style;

		computed = computed || getStyles( elem );
		ret = computed ? computed[ name ] : undefined;

		// Avoid setting ret to empty string here
		// so we don't default to auto
		if ( ret == null && style && style[ name ] ) {
			ret = style[ name ];
		}

		// From the awesome hack by Dean Edwards
		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

		// If we're not dealing with a regular pixel number
		// but a number that has a weird ending, we need to convert it to pixels
		// but not position css attributes, as those are
		// proportional to the parent element instead
		// and we can't measure the parent instead because it
		// might trigger a "stacking dolls" problem
		if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {

			// Remember the original values
			left = style.left;
			rs = elem.runtimeStyle;
			rsLeft = rs && rs.left;

			// Put in the new values to get a computed value out
			if ( rsLeft ) {
				rs.left = elem.currentStyle.left;
			}
			style.left = name === "fontSize" ? "1em" : ret;
			ret = style.pixelLeft + "px";

			// Revert the changed values
			style.left = left;
			if ( rsLeft ) {
				rs.left = rsLeft;
			}
		}

		// Support: IE
		// IE returns zIndex value as an integer.
		return ret === undefined ?
			ret :
			ret + "" || "auto";
	};
}




function addGetHookIf( conditionFn, hookFn ) {

	// Define the hook, we'll check on the first run if it's really needed.
	return {
		get: function() {
			if ( conditionFn() ) {

				// Hook not needed (or it's not possible to use it due
				// to missing dependency), remove it.
				delete this.get;
				return;
			}

			// Hook needed; redefine it so that the support test is not executed again.
			return ( this.get = hookFn ).apply( this, arguments );
		}
	};
}


var

		ralpha = /alpha\([^)]*\)/i,
	ropacity = /opacity\s*=\s*([^)]*)/i,

	// swappable if display is none or starts with table except
	// "table", "table-cell", or "table-caption"
	// see here for display values:
	// https://developer.mozilla.org/en-US/docs/CSS/display
	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
	rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),

	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
	cssNormalTransform = {
		letterSpacing: "0",
		fontWeight: "400"
	},

	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
	emptyStyle = document.createElement( "div" ).style;


// return a css property mapped to a potentially vendor prefixed property
function vendorPropName( name ) {

	// shortcut for names that are not vendor prefixed
	if ( name in emptyStyle ) {
		return name;
	}

	// check for vendor prefixed names
	var capName = name.charAt( 0 ).toUpperCase() + name.slice( 1 ),
		i = cssPrefixes.length;

	while ( i-- ) {
		name = cssPrefixes[ i ] + capName;
		if ( name in emptyStyle ) {
			return name;
		}
	}
}

function showHide( elements, show ) {
	var display, elem, hidden,
		values = [],
		index = 0,
		length = elements.length;

	for ( ; index < length; index++ ) {
		elem = elements[ index ];
		if ( !elem.style ) {
			continue;
		}

		values[ index ] = jQuery._data( elem, "olddisplay" );
		display = elem.style.display;
		if ( show ) {

			// Reset the inline display of this element to learn if it is
			// being hidden by cascaded rules or not
			if ( !values[ index ] && display === "none" ) {
				elem.style.display = "";
			}

			// Set elements which have been overridden with display: none
			// in a stylesheet to whatever the default browser style is
			// for such an element
			if ( elem.style.display === "" && isHidden( elem ) ) {
				values[ index ] =
					jQuery._data( elem, "olddisplay", defaultDisplay( elem.nodeName ) );
			}
		} else {
			hidden = isHidden( elem );

			if ( display && display !== "none" || !hidden ) {
				jQuery._data(
					elem,
					"olddisplay",
					hidden ? display : jQuery.css( elem, "display" )
				);
			}
		}
	}

	// Set the display of most of the elements in a second loop
	// to avoid the constant reflow
	for ( index = 0; index < length; index++ ) {
		elem = elements[ index ];
		if ( !elem.style ) {
			continue;
		}
		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
			elem.style.display = show ? values[ index ] || "" : "none";
		}
	}

	return elements;
}

function setPositiveNumber( elem, value, subtract ) {
	var matches = rnumsplit.exec( value );
	return matches ?

		// Guard against undefined "subtract", e.g., when used as in cssHooks
		Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
		value;
}

function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
	var i = extra === ( isBorderBox ? "border" : "content" ) ?

		// If we already have the right measurement, avoid augmentation
		4 :

		// Otherwise initialize for horizontal or vertical properties
		name === "width" ? 1 : 0,

		val = 0;

	for ( ; i < 4; i += 2 ) {

		// both box models exclude margin, so add it if we want it
		if ( extra === "margin" ) {
			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
		}

		if ( isBorderBox ) {

			// border-box includes padding, so remove it if we want content
			if ( extra === "content" ) {
				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
			}

			// at this point, extra isn't border nor margin, so remove border
			if ( extra !== "margin" ) {
				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
			}
		} else {

			// at this point, extra isn't content, so add padding
			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );

			// at this point, extra isn't content nor padding, so add border
			if ( extra !== "padding" ) {
				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
			}
		}
	}

	return val;
}

function getWidthOrHeight( elem, name, extra ) {

	// Start with offset property, which is equivalent to the border-box value
	var valueIsBorderBox = true,
		val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
		styles = getStyles( elem ),
		isBorderBox = support.boxSizing &&
			jQuery.css( elem, "boxSizing", false, styles ) === "border-box";

	// Support: IE11 only
	// In IE 11 fullscreen elements inside of an iframe have
	// 100x too small dimensions (gh-1764).
	if ( document.msFullscreenElement && window.top !== window ) {

		// Support: IE11 only
		// Running getBoundingClientRect on a disconnected node
		// in IE throws an error.
		if ( elem.getClientRects().length ) {
			val = Math.round( elem.getBoundingClientRect()[ name ] * 100 );
		}
	}

	// some non-html elements return undefined for offsetWidth, so check for null/undefined
	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
	if ( val <= 0 || val == null ) {

		// Fall back to computed then uncomputed css if necessary
		val = curCSS( elem, name, styles );
		if ( val < 0 || val == null ) {
			val = elem.style[ name ];
		}

		// Computed unit is not pixels. Stop here and return.
		if ( rnumnonpx.test( val ) ) {
			return val;
		}

		// we need the check for style in case a browser which returns unreliable values
		// for getComputedStyle silently falls back to the reliable elem.style
		valueIsBorderBox = isBorderBox &&
			( support.boxSizingReliable() || val === elem.style[ name ] );

		// Normalize "", auto, and prepare for extra
		val = parseFloat( val ) || 0;
	}

	// use the active box-sizing model to add/subtract irrelevant styles
	return ( val +
		augmentWidthOrHeight(
			elem,
			name,
			extra || ( isBorderBox ? "border" : "content" ),
			valueIsBorderBox,
			styles
		)
	) + "px";
}

jQuery.extend( {

	// Add in style property hooks for overriding the default
	// behavior of getting and setting a style property
	cssHooks: {
		opacity: {
			get: function( elem, computed ) {
				if ( computed ) {

					// We should always get a number back from opacity
					var ret = curCSS( elem, "opacity" );
					return ret === "" ? "1" : ret;
				}
			}
		}
	},

	// Don't automatically add "px" to these possibly-unitless properties
	cssNumber: {
		"animationIterationCount": true,
		"columnCount": true,
		"fillOpacity": true,
		"flexGrow": true,
		"flexShrink": true,
		"fontWeight": true,
		"lineHeight": true,
		"opacity": true,
		"order": true,
		"orphans": true,
		"widows": true,
		"zIndex": true,
		"zoom": true
	},

	// Add in properties whose names you wish to fix before
	// setting or getting the value
	cssProps: {

		// normalize float css property
		"float": support.cssFloat ? "cssFloat" : "styleFloat"
	},

	// Get and set the style property on a DOM Node
	style: function( elem, name, value, extra ) {

		// Don't set styles on text and comment nodes
		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
			return;
		}

		// Make sure that we're working with the right name
		var ret, type, hooks,
			origName = jQuery.camelCase( name ),
			style = elem.style;

		name = jQuery.cssProps[ origName ] ||
			( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );

		// gets hook for the prefixed version
		// followed by the unprefixed version
		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];

		// Check if we're setting a value
		if ( value !== undefined ) {
			type = typeof value;

			// Convert "+=" or "-=" to relative numbers (#7345)
			if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
				value = adjustCSS( elem, name, ret );

				// Fixes bug #9237
				type = "number";
			}

			// Make sure that null and NaN values aren't set. See: #7116
			if ( value == null || value !== value ) {
				return;
			}

			// If a number was passed in, add the unit (except for certain CSS properties)
			if ( type === "number" ) {
				value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
			}

			// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
			// but it would mean to define eight
			// (for every problematic property) identical functions
			if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
				style[ name ] = "inherit";
			}

			// If a hook was provided, use that value, otherwise just set the specified value
			if ( !hooks || !( "set" in hooks ) ||
				( value = hooks.set( elem, value, extra ) ) !== undefined ) {

				// Support: IE
				// Swallow errors from 'invalid' CSS values (#5509)
				try {
					style[ name ] = value;
				} catch ( e ) {}
			}

		} else {

			// If a hook was provided get the non-computed value from there
			if ( hooks && "get" in hooks &&
				( ret = hooks.get( elem, false, extra ) ) !== undefined ) {

				return ret;
			}

			// Otherwise just get the value from the style object
			return style[ name ];
		}
	},

	css: function( elem, name, extra, styles ) {
		var num, val, hooks,
			origName = jQuery.camelCase( name );

		// Make sure that we're working with the right name
		name = jQuery.cssProps[ origName ] ||
			( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );

		// gets hook for the prefixed version
		// followed by the unprefixed version
		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];

		// If a hook was provided get the computed value from there
		if ( hooks && "get" in hooks ) {
			val = hooks.get( elem, true, extra );
		}

		// Otherwise, if a way to get the computed value exists, use that
		if ( val === undefined ) {
			val = curCSS( elem, name, styles );
		}

		//convert "normal" to computed value
		if ( val === "normal" && name in cssNormalTransform ) {
			val = cssNormalTransform[ name ];
		}

		// Return, converting to number if forced or a qualifier was provided and val looks numeric
		if ( extra === "" || extra ) {
			num = parseFloat( val );
			return extra === true || isFinite( num ) ? num || 0 : val;
		}
		return val;
	}
} );

jQuery.each( [ "height", "width" ], function( i, name ) {
	jQuery.cssHooks[ name ] = {
		get: function( elem, computed, extra ) {
			if ( computed ) {

				// certain elements can have dimension info if we invisibly show them
				// however, it must have a current display style that would benefit from this
				return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
					elem.offsetWidth === 0 ?
						swap( elem, cssShow, function() {
							return getWidthOrHeight( elem, name, extra );
						} ) :
						getWidthOrHeight( elem, name, extra );
			}
		},

		set: function( elem, value, extra ) {
			var styles = extra && getStyles( elem );
			return setPositiveNumber( elem, value, extra ?
				augmentWidthOrHeight(
					elem,
					name,
					extra,
					support.boxSizing &&
						jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
					styles
				) : 0
			);
		}
	};
} );

if ( !support.opacity ) {
	jQuery.cssHooks.opacity = {
		get: function( elem, computed ) {

			// IE uses filters for opacity
			return ropacity.test( ( computed && elem.currentStyle ?
				elem.currentStyle.filter :
				elem.style.filter ) || "" ) ?
					( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
					computed ? "1" : "";
		},

		set: function( elem, value ) {
			var style = elem.style,
				currentStyle = elem.currentStyle,
				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
				filter = currentStyle && currentStyle.filter || style.filter || "";

			// IE has trouble with opacity if it does not have layout
			// Force it by setting the zoom level
			style.zoom = 1;

			// if setting opacity to 1, and no other filters exist -
			// attempt to remove filter attribute #6652
			// if value === "", then remove inline opacity #12685
			if ( ( value >= 1 || value === "" ) &&
					jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
					style.removeAttribute ) {

				// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
				// if "filter:" is present at all, clearType is disabled, we want to avoid this
				// style.removeAttribute is IE Only, but so apparently is this code path...
				style.removeAttribute( "filter" );

				// if there is no filter style applied in a css rule
				// or unset inline opacity, we are done
				if ( value === "" || currentStyle && !currentStyle.filter ) {
					return;
				}
			}

			// otherwise, set new filter values
			style.filter = ralpha.test( filter ) ?
				filter.replace( ralpha, opacity ) :
				filter + " " + opacity;
		}
	};
}

jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
	function( elem, computed ) {
		if ( computed ) {
			return swap( elem, { "display": "inline-block" },
				curCSS, [ elem, "marginRight" ] );
		}
	}
);

jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
	function( elem, computed ) {
		if ( computed ) {
			return (
				parseFloat( curCSS( elem, "marginLeft" ) ) ||

				// Support: IE<=11+
				// Running getBoundingClientRect on a disconnected node in IE throws an error
				// Support: IE8 only
				// getClientRects() errors on disconnected elems
				( jQuery.contains( elem.ownerDocument, elem ) ?
					elem.getBoundingClientRect().left -
						swap( elem, { marginLeft: 0 }, function() {
							return elem.getBoundingClientRect().left;
						} ) :
					0
				)
			) + "px";
		}
	}
);

// These hooks are used by animate to expand properties
jQuery.each( {
	margin: "",
	padding: "",
	border: "Width"
}, function( prefix, suffix ) {
	jQuery.cssHooks[ prefix + suffix ] = {
		expand: function( value ) {
			var i = 0,
				expanded = {},

				// assumes a single number if not a string
				parts = typeof value === "string" ? value.split( " " ) : [ value ];

			for ( ; i < 4; i++ ) {
				expanded[ prefix + cssExpand[ i ] + suffix ] =
					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
			}

			return expanded;
		}
	};

	if ( !rmargin.test( prefix ) ) {
		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
	}
} );

jQuery.fn.extend( {
	css: function( name, value ) {
		return access( this, function( elem, name, value ) {
			var styles, len,
				map = {},
				i = 0;

			if ( jQuery.isArray( name ) ) {
				styles = getStyles( elem );
				len = name.length;

				for ( ; i < len; i++ ) {
					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
				}

				return map;
			}

			return value !== undefined ?
				jQuery.style( elem, name, value ) :
				jQuery.css( elem, name );
		}, name, value, arguments.length > 1 );
	},
	show: function() {
		return showHide( this, true );
	},
	hide: function() {
		return showHide( this );
	},
	toggle: function( state ) {
		if ( typeof state === "boolean" ) {
			return state ? this.show() : this.hide();
		}

		return this.each( function() {
			if ( isHidden( this ) ) {
				jQuery( this ).show();
			} else {
				jQuery( this ).hide();
			}
		} );
	}
} );


function Tween( elem, options, prop, end, easing ) {
	return new Tween.prototype.init( elem, options, prop, end, easing );
}
jQuery.Tween = Tween;

Tween.prototype = {
	constructor: Tween,
	init: function( elem, options, prop, end, easing, unit ) {
		this.elem = elem;
		this.prop = prop;
		this.easing = easing || jQuery.easing._default;
		this.options = options;
		this.start = this.now = this.cur();
		this.end = end;
		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
	},
	cur: function() {
		var hooks = Tween.propHooks[ this.prop ];

		return hooks && hooks.get ?
			hooks.get( this ) :
			Tween.propHooks._default.get( this );
	},
	run: function( percent ) {
		var eased,
			hooks = Tween.propHooks[ this.prop ];

		if ( this.options.duration ) {
			this.pos = eased = jQuery.easing[ this.easing ](
				percent, this.options.duration * percent, 0, 1, this.options.duration
			);
		} else {
			this.pos = eased = percent;
		}
		this.now = ( this.end - this.start ) * eased + this.start;

		if ( this.options.step ) {
			this.options.step.call( this.elem, this.now, this );
		}

		if ( hooks && hooks.set ) {
			hooks.set( this );
		} else {
			Tween.propHooks._default.set( this );
		}
		return this;
	}
};

Tween.prototype.init.prototype = Tween.prototype;

Tween.propHooks = {
	_default: {
		get: function( tween ) {
			var result;

			// Use a property on the element directly when it is not a DOM element,
			// or when there is no matching style property that exists.
			if ( tween.elem.nodeType !== 1 ||
				tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
				return tween.elem[ tween.prop ];
			}

			// passing an empty string as a 3rd parameter to .css will automatically
			// attempt a parseFloat and fallback to a string if the parse fails
			// so, simple values such as "10px" are parsed to Float.
			// complex values such as "rotate(1rad)" are returned as is.
			result = jQuery.css( tween.elem, tween.prop, "" );

			// Empty strings, null, undefined and "auto" are converted to 0.
			return !result || result === "auto" ? 0 : result;
		},
		set: function( tween ) {

			// use step hook for back compat - use cssHook if its there - use .style if its
			// available and use plain properties where available
			if ( jQuery.fx.step[ tween.prop ] ) {
				jQuery.fx.step[ tween.prop ]( tween );
			} else if ( tween.elem.nodeType === 1 &&
				( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||
					jQuery.cssHooks[ tween.prop ] ) ) {
				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
			} else {
				tween.elem[ tween.prop ] = tween.now;
			}
		}
	}
};

// Support: IE <=9
// Panic based approach to setting things on disconnected nodes

Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
	set: function( tween ) {
		if ( tween.elem.nodeType && tween.elem.parentNode ) {
			tween.elem[ tween.prop ] = tween.now;
		}
	}
};

jQuery.easing = {
	linear: function( p ) {
		return p;
	},
	swing: function( p ) {
		return 0.5 - Math.cos( p * Math.PI ) / 2;
	},
	_default: "swing"
};

jQuery.fx = Tween.prototype.init;

// Back Compat <1.8 extension point
jQuery.fx.step = {};




var
	fxNow, timerId,
	rfxtypes = /^(?:toggle|show|hide)$/,
	rrun = /queueHooks$/;

// Animations created synchronously will run synchronously
function createFxNow() {
	window.setTimeout( function() {
		fxNow = undefined;
	} );
	return ( fxNow = jQuery.now() );
}

// Generate parameters to create a standard animation
function genFx( type, includeWidth ) {
	var which,
		attrs = { height: type },
		i = 0;

	// if we include width, step value is 1 to do all cssExpand values,
	// if we don't include width, step value is 2 to skip over Left and Right
	includeWidth = includeWidth ? 1 : 0;
	for ( ; i < 4 ; i += 2 - includeWidth ) {
		which = cssExpand[ i ];
		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
	}

	if ( includeWidth ) {
		attrs.opacity = attrs.width = type;
	}

	return attrs;
}

function createTween( value, prop, animation ) {
	var tween,
		collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
		index = 0,
		length = collection.length;
	for ( ; index < length; index++ ) {
		if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {

			// we're done with this property
			return tween;
		}
	}
}

function defaultPrefilter( elem, props, opts ) {
	/* jshint validthis: true */
	var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
		anim = this,
		orig = {},
		style = elem.style,
		hidden = elem.nodeType && isHidden( elem ),
		dataShow = jQuery._data( elem, "fxshow" );

	// handle queue: false promises
	if ( !opts.queue ) {
		hooks = jQuery._queueHooks( elem, "fx" );
		if ( hooks.unqueued == null ) {
			hooks.unqueued = 0;
			oldfire = hooks.empty.fire;
			hooks.empty.fire = function() {
				if ( !hooks.unqueued ) {
					oldfire();
				}
			};
		}
		hooks.unqueued++;

		anim.always( function() {

			// doing this makes sure that the complete handler will be called
			// before this completes
			anim.always( function() {
				hooks.unqueued--;
				if ( !jQuery.queue( elem, "fx" ).length ) {
					hooks.empty.fire();
				}
			} );
		} );
	}

	// height/width overflow pass
	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {

		// Make sure that nothing sneaks out
		// Record all 3 overflow attributes because IE does not
		// change the overflow attribute when overflowX and
		// overflowY are set to the same value
		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];

		// Set display property to inline-block for height/width
		// animations on inline elements that are having width/height animated
		display = jQuery.css( elem, "display" );

		// Test default display if display is currently "none"
		checkDisplay = display === "none" ?
			jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;

		if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {

			// inline-level elements accept inline-block;
			// block-level elements need to be inline with layout
			if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
				style.display = "inline-block";
			} else {
				style.zoom = 1;
			}
		}
	}

	if ( opts.overflow ) {
		style.overflow = "hidden";
		if ( !support.shrinkWrapBlocks() ) {
			anim.always( function() {
				style.overflow = opts.overflow[ 0 ];
				style.overflowX = opts.overflow[ 1 ];
				style.overflowY = opts.overflow[ 2 ];
			} );
		}
	}

	// show/hide pass
	for ( prop in props ) {
		value = props[ prop ];
		if ( rfxtypes.exec( value ) ) {
			delete props[ prop ];
			toggle = toggle || value === "toggle";
			if ( value === ( hidden ? "hide" : "show" ) ) {

				// If there is dataShow left over from a stopped hide or show
				// and we are going to proceed with show, we should pretend to be hidden
				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
					hidden = true;
				} else {
					continue;
				}
			}
			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );

		// Any non-fx value stops us from restoring the original display value
		} else {
			display = undefined;
		}
	}

	if ( !jQuery.isEmptyObject( orig ) ) {
		if ( dataShow ) {
			if ( "hidden" in dataShow ) {
				hidden = dataShow.hidden;
			}
		} else {
			dataShow = jQuery._data( elem, "fxshow", {} );
		}

		// store state if its toggle - enables .stop().toggle() to "reverse"
		if ( toggle ) {
			dataShow.hidden = !hidden;
		}
		if ( hidden ) {
			jQuery( elem ).show();
		} else {
			anim.done( function() {
				jQuery( elem ).hide();
			} );
		}
		anim.done( function() {
			var prop;
			jQuery._removeData( elem, "fxshow" );
			for ( prop in orig ) {
				jQuery.style( elem, prop, orig[ prop ] );
			}
		} );
		for ( prop in orig ) {
			tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );

			if ( !( prop in dataShow ) ) {
				dataShow[ prop ] = tween.start;
				if ( hidden ) {
					tween.end = tween.start;
					tween.start = prop === "width" || prop === "height" ? 1 : 0;
				}
			}
		}

	// If this is a noop like .hide().hide(), restore an overwritten display value
	} else if ( ( display === "none" ? defaultDisplay( elem.nodeName ) : display ) === "inline" ) {
		style.display = display;
	}
}

function propFilter( props, specialEasing ) {
	var index, name, easing, value, hooks;

	// camelCase, specialEasing and expand cssHook pass
	for ( index in props ) {
		name = jQuery.camelCase( index );
		easing = specialEasing[ name ];
		value = props[ index ];
		if ( jQuery.isArray( value ) ) {
			easing = value[ 1 ];
			value = props[ index ] = value[ 0 ];
		}

		if ( index !== name ) {
			props[ name ] = value;
			delete props[ index ];
		}

		hooks = jQuery.cssHooks[ name ];
		if ( hooks && "expand" in hooks ) {
			value = hooks.expand( value );
			delete props[ name ];

			// not quite $.extend, this wont overwrite keys already present.
			// also - reusing 'index' from above because we have the correct "name"
			for ( index in value ) {
				if ( !( index in props ) ) {
					props[ index ] = value[ index ];
					specialEasing[ index ] = easing;
				}
			}
		} else {
			specialEasing[ name ] = easing;
		}
	}
}

function Animation( elem, properties, options ) {
	var result,
		stopped,
		index = 0,
		length = Animation.prefilters.length,
		deferred = jQuery.Deferred().always( function() {

			// don't match elem in the :animated selector
			delete tick.elem;
		} ),
		tick = function() {
			if ( stopped ) {
				return false;
			}
			var currentTime = fxNow || createFxNow(),
				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),

				// Support: Android 2.3
				// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
				temp = remaining / animation.duration || 0,
				percent = 1 - temp,
				index = 0,
				length = animation.tweens.length;

			for ( ; index < length ; index++ ) {
				animation.tweens[ index ].run( percent );
			}

			deferred.notifyWith( elem, [ animation, percent, remaining ] );

			if ( percent < 1 && length ) {
				return remaining;
			} else {
				deferred.resolveWith( elem, [ animation ] );
				return false;
			}
		},
		animation = deferred.promise( {
			elem: elem,
			props: jQuery.extend( {}, properties ),
			opts: jQuery.extend( true, {
				specialEasing: {},
				easing: jQuery.easing._default
			}, options ),
			originalProperties: properties,
			originalOptions: options,
			startTime: fxNow || createFxNow(),
			duration: options.duration,
			tweens: [],
			createTween: function( prop, end ) {
				var tween = jQuery.Tween( elem, animation.opts, prop, end,
						animation.opts.specialEasing[ prop ] || animation.opts.easing );
				animation.tweens.push( tween );
				return tween;
			},
			stop: function( gotoEnd ) {
				var index = 0,

					// if we are going to the end, we want to run all the tweens
					// otherwise we skip this part
					length = gotoEnd ? animation.tweens.length : 0;
				if ( stopped ) {
					return this;
				}
				stopped = true;
				for ( ; index < length ; index++ ) {
					animation.tweens[ index ].run( 1 );
				}

				// resolve when we played the last frame
				// otherwise, reject
				if ( gotoEnd ) {
					deferred.notifyWith( elem, [ animation, 1, 0 ] );
					deferred.resolveWith( elem, [ animation, gotoEnd ] );
				} else {
					deferred.rejectWith( elem, [ animation, gotoEnd ] );
				}
				return this;
			}
		} ),
		props = animation.props;

	propFilter( props, animation.opts.specialEasing );

	for ( ; index < length ; index++ ) {
		result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
		if ( result ) {
			if ( jQuery.isFunction( result.stop ) ) {
				jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
					jQuery.proxy( result.stop, result );
			}
			return result;
		}
	}

	jQuery.map( props, createTween, animation );

	if ( jQuery.isFunction( animation.opts.start ) ) {
		animation.opts.start.call( elem, animation );
	}

	jQuery.fx.timer(
		jQuery.extend( tick, {
			elem: elem,
			anim: animation,
			queue: animation.opts.queue
		} )
	);

	// attach callbacks from options
	return animation.progress( animation.opts.progress )
		.done( animation.opts.done, animation.opts.complete )
		.fail( animation.opts.fail )
		.always( animation.opts.always );
}

jQuery.Animation = jQuery.extend( Animation, {

	tweeners: {
		"*": [ function( prop, value ) {
			var tween = this.createTween( prop, value );
			adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
			return tween;
		} ]
	},

	tweener: function( props, callback ) {
		if ( jQuery.isFunction( props ) ) {
			callback = props;
			props = [ "*" ];
		} else {
			props = props.match( rnotwhite );
		}

		var prop,
			index = 0,
			length = props.length;

		for ( ; index < length ; index++ ) {
			prop = props[ index ];
			Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
			Animation.tweeners[ prop ].unshift( callback );
		}
	},

	prefilters: [ defaultPrefilter ],

	prefilter: function( callback, prepend ) {
		if ( prepend ) {
			Animation.prefilters.unshift( callback );
		} else {
			Animation.prefilters.push( callback );
		}
	}
} );

jQuery.speed = function( speed, easing, fn ) {
	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
		complete: fn || !fn && easing ||
			jQuery.isFunction( speed ) && speed,
		duration: speed,
		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
	};

	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
		opt.duration in jQuery.fx.speeds ?
			jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;

	// normalize opt.queue - true/undefined/null -> "fx"
	if ( opt.queue == null || opt.queue === true ) {
		opt.queue = "fx";
	}

	// Queueing
	opt.old = opt.complete;

	opt.complete = function() {
		if ( jQuery.isFunction( opt.old ) ) {
			opt.old.call( this );
		}

		if ( opt.queue ) {
			jQuery.dequeue( this, opt.queue );
		}
	};

	return opt;
};

jQuery.fn.extend( {
	fadeTo: function( speed, to, easing, callback ) {

		// show any hidden elements after setting opacity to 0
		return this.filter( isHidden ).css( "opacity", 0 ).show()

			// animate to the value specified
			.end().animate( { opacity: to }, speed, easing, callback );
	},
	animate: function( prop, speed, easing, callback ) {
		var empty = jQuery.isEmptyObject( prop ),
			optall = jQuery.speed( speed, easing, callback ),
			doAnimation = function() {

				// Operate on a copy of prop so per-property easing won't be lost
				var anim = Animation( this, jQuery.extend( {}, prop ), optall );

				// Empty animations, or finishing resolves immediately
				if ( empty || jQuery._data( this, "finish" ) ) {
					anim.stop( true );
				}
			};
			doAnimation.finish = doAnimation;

		return empty || optall.queue === false ?
			this.each( doAnimation ) :
			this.queue( optall.queue, doAnimation );
	},
	stop: function( type, clearQueue, gotoEnd ) {
		var stopQueue = function( hooks ) {
			var stop = hooks.stop;
			delete hooks.stop;
			stop( gotoEnd );
		};

		if ( typeof type !== "string" ) {
			gotoEnd = clearQueue;
			clearQueue = type;
			type = undefined;
		}
		if ( clearQueue && type !== false ) {
			this.queue( type || "fx", [] );
		}

		return this.each( function() {
			var dequeue = true,
				index = type != null && type + "queueHooks",
				timers = jQuery.timers,
				data = jQuery._data( this );

			if ( index ) {
				if ( data[ index ] && data[ index ].stop ) {
					stopQueue( data[ index ] );
				}
			} else {
				for ( index in data ) {
					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
						stopQueue( data[ index ] );
					}
				}
			}

			for ( index = timers.length; index--; ) {
				if ( timers[ index ].elem === this &&
					( type == null || timers[ index ].queue === type ) ) {

					timers[ index ].anim.stop( gotoEnd );
					dequeue = false;
					timers.splice( index, 1 );
				}
			}

			// start the next in the queue if the last step wasn't forced
			// timers currently will call their complete callbacks, which will dequeue
			// but only if they were gotoEnd
			if ( dequeue || !gotoEnd ) {
				jQuery.dequeue( this, type );
			}
		} );
	},
	finish: function( type ) {
		if ( type !== false ) {
			type = type || "fx";
		}
		return this.each( function() {
			var index,
				data = jQuery._data( this ),
				queue = data[ type + "queue" ],
				hooks = data[ type + "queueHooks" ],
				timers = jQuery.timers,
				length = queue ? queue.length : 0;

			// enable finishing flag on private data
			data.finish = true;

			// empty the queue first
			jQuery.queue( this, type, [] );

			if ( hooks && hooks.stop ) {
				hooks.stop.call( this, true );
			}

			// look for any active animations, and finish them
			for ( index = timers.length; index--; ) {
				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
					timers[ index ].anim.stop( true );
					timers.splice( index, 1 );
				}
			}

			// look for any animations in the old queue and finish them
			for ( index = 0; index < length; index++ ) {
				if ( queue[ index ] && queue[ index ].finish ) {
					queue[ index ].finish.call( this );
				}
			}

			// turn off finishing flag
			delete data.finish;
		} );
	}
} );

jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
	var cssFn = jQuery.fn[ name ];
	jQuery.fn[ name ] = function( speed, easing, callback ) {
		return speed == null || typeof speed === "boolean" ?
			cssFn.apply( this, arguments ) :
			this.animate( genFx( name, true ), speed, easing, callback );
	};
} );

// Generate shortcuts for custom animations
jQuery.each( {
	slideDown: genFx( "show" ),
	slideUp: genFx( "hide" ),
	slideToggle: genFx( "toggle" ),
	fadeIn: { opacity: "show" },
	fadeOut: { opacity: "hide" },
	fadeToggle: { opacity: "toggle" }
}, function( name, props ) {
	jQuery.fn[ name ] = function( speed, easing, callback ) {
		return this.animate( props, speed, easing, callback );
	};
} );

jQuery.timers = [];
jQuery.fx.tick = function() {
	var timer,
		timers = jQuery.timers,
		i = 0;

	fxNow = jQuery.now();

	for ( ; i < timers.length; i++ ) {
		timer = timers[ i ];

		// Checks the timer has not already been removed
		if ( !timer() && timers[ i ] === timer ) {
			timers.splice( i--, 1 );
		}
	}

	if ( !timers.length ) {
		jQuery.fx.stop();
	}
	fxNow = undefined;
};

jQuery.fx.timer = function( timer ) {
	jQuery.timers.push( timer );
	if ( timer() ) {
		jQuery.fx.start();
	} else {
		jQuery.timers.pop();
	}
};

jQuery.fx.interval = 13;

jQuery.fx.start = function() {
	if ( !timerId ) {
		timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
	}
};

jQuery.fx.stop = function() {
	window.clearInterval( timerId );
	timerId = null;
};

jQuery.fx.speeds = {
	slow: 600,
	fast: 200,

	// Default speed
	_default: 400
};


// Based off of the plugin by Clint Helfers, with permission.
// http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
jQuery.fn.delay = function( time, type ) {
	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
	type = type || "fx";

	return this.queue( type, function( next, hooks ) {
		var timeout = window.setTimeout( next, time );
		hooks.stop = function() {
			window.clearTimeout( timeout );
		};
	} );
};


( function() {
	var a,
		input = document.createElement( "input" ),
		div = document.createElement( "div" ),
		select = document.createElement( "select" ),
		opt = select.appendChild( document.createElement( "option" ) );

	// Setup
	div = document.createElement( "div" );
	div.setAttribute( "className", "t" );
	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
	a = div.getElementsByTagName( "a" )[ 0 ];

	// Support: Windows Web Apps (WWA)
	// `type` must use .setAttribute for WWA (#14901)
	input.setAttribute( "type", "checkbox" );
	div.appendChild( input );

	a = div.getElementsByTagName( "a" )[ 0 ];

	// First batch of tests.
	a.style.cssText = "top:1px";

	// Test setAttribute on camelCase class.
	// If it works, we need attrFixes when doing get/setAttribute (ie6/7)
	support.getSetAttribute = div.className !== "t";

	// Get the style information from getAttribute
	// (IE uses .cssText instead)
	support.style = /top/.test( a.getAttribute( "style" ) );

	// Make sure that URLs aren't manipulated
	// (IE normalizes it by default)
	support.hrefNormalized = a.getAttribute( "href" ) === "/a";

	// Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
	support.checkOn = !!input.value;

	// Make sure that a selected-by-default option has a working selected property.
	// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
	support.optSelected = opt.selected;

	// Tests for enctype support on a form (#6743)
	support.enctype = !!document.createElement( "form" ).enctype;

	// Make sure that the options inside disabled selects aren't marked as disabled
	// (WebKit marks them as disabled)
	select.disabled = true;
	support.optDisabled = !opt.disabled;

	// Support: IE8 only
	// Check if we can trust getAttribute("value")
	input = document.createElement( "input" );
	input.setAttribute( "value", "" );
	support.input = input.getAttribute( "value" ) === "";

	// Check if an input maintains its value after becoming a radio
	input.value = "t";
	input.setAttribute( "type", "radio" );
	support.radioValue = input.value === "t";
} )();


var rreturn = /\r/g,
	rspaces = /[\x20\t\r\n\f]+/g;

jQuery.fn.extend( {
	val: function( value ) {
		var hooks, ret, isFunction,
			elem = this[ 0 ];

		if ( !arguments.length ) {
			if ( elem ) {
				hooks = jQuery.valHooks[ elem.type ] ||
					jQuery.valHooks[ elem.nodeName.toLowerCase() ];

				if (
					hooks &&
					"get" in hooks &&
					( ret = hooks.get( elem, "value" ) ) !== undefined
				) {
					return ret;
				}

				ret = elem.value;

				return typeof ret === "string" ?

					// handle most common string cases
					ret.replace( rreturn, "" ) :

					// handle cases where value is null/undef or number
					ret == null ? "" : ret;
			}

			return;
		}

		isFunction = jQuery.isFunction( value );

		return this.each( function( i ) {
			var val;

			if ( this.nodeType !== 1 ) {
				return;
			}

			if ( isFunction ) {
				val = value.call( this, i, jQuery( this ).val() );
			} else {
				val = value;
			}

			// Treat null/undefined as ""; convert numbers to string
			if ( val == null ) {
				val = "";
			} else if ( typeof val === "number" ) {
				val += "";
			} else if ( jQuery.isArray( val ) ) {
				val = jQuery.map( val, function( value ) {
					return value == null ? "" : value + "";
				} );
			}

			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];

			// If set returns undefined, fall back to normal setting
			if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
				this.value = val;
			}
		} );
	}
} );

jQuery.extend( {
	valHooks: {
		option: {
			get: function( elem ) {
				var val = jQuery.find.attr( elem, "value" );
				return val != null ?
					val :

					// Support: IE10-11+
					// option.text throws exceptions (#14686, #14858)
					// Strip and collapse whitespace
					// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
					jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " );
			}
		},
		select: {
			get: function( elem ) {
				var value, option,
					options = elem.options,
					index = elem.selectedIndex,
					one = elem.type === "select-one" || index < 0,
					values = one ? null : [],
					max = one ? index + 1 : options.length,
					i = index < 0 ?
						max :
						one ? index : 0;

				// Loop through all the selected options
				for ( ; i < max; i++ ) {
					option = options[ i ];

					// oldIE doesn't update selected after form reset (#2551)
					if ( ( option.selected || i === index ) &&

							// Don't return options that are disabled or in a disabled optgroup
							( support.optDisabled ?
								!option.disabled :
								option.getAttribute( "disabled" ) === null ) &&
							( !option.parentNode.disabled ||
								!jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {

						// Get the specific value for the option
						value = jQuery( option ).val();

						// We don't need an array for one selects
						if ( one ) {
							return value;
						}

						// Multi-Selects return an array
						values.push( value );
					}
				}

				return values;
			},

			set: function( elem, value ) {
				var optionSet, option,
					options = elem.options,
					values = jQuery.makeArray( value ),
					i = options.length;

				while ( i-- ) {
					option = options[ i ];

					if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 ) {

						// Support: IE6
						// When new option element is added to select box we need to
						// force reflow of newly added node in order to workaround delay
						// of initialization properties
						try {
							option.selected = optionSet = true;

						} catch ( _ ) {

							// Will be executed only in IE6
							option.scrollHeight;
						}

					} else {
						option.selected = false;
					}
				}

				// Force browsers to behave consistently when non-matching value is set
				if ( !optionSet ) {
					elem.selectedIndex = -1;
				}

				return options;
			}
		}
	}
} );

// Radios and checkboxes getter/setter
jQuery.each( [ "radio", "checkbox" ], function() {
	jQuery.valHooks[ this ] = {
		set: function( elem, value ) {
			if ( jQuery.isArray( value ) ) {
				return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
			}
		}
	};
	if ( !support.checkOn ) {
		jQuery.valHooks[ this ].get = function( elem ) {
			return elem.getAttribute( "value" ) === null ? "on" : elem.value;
		};
	}
} );




var nodeHook, boolHook,
	attrHandle = jQuery.expr.attrHandle,
	ruseDefault = /^(?:checked|selected)$/i,
	getSetAttribute = support.getSetAttribute,
	getSetInput = support.input;

jQuery.fn.extend( {
	attr: function( name, value ) {
		return access( this, jQuery.attr, name, value, arguments.length > 1 );
	},

	removeAttr: function( name ) {
		return this.each( function() {
			jQuery.removeAttr( this, name );
		} );
	}
} );

jQuery.extend( {
	attr: function( elem, name, value ) {
		var ret, hooks,
			nType = elem.nodeType;

		// Don't get/set attributes on text, comment and attribute nodes
		if ( nType === 3 || nType === 8 || nType === 2 ) {
			return;
		}

		// Fallback to prop when attributes are not supported
		if ( typeof elem.getAttribute === "undefined" ) {
			return jQuery.prop( elem, name, value );
		}

		// All attributes are lowercase
		// Grab necessary hook if one is defined
		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
			name = name.toLowerCase();
			hooks = jQuery.attrHooks[ name ] ||
				( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
		}

		if ( value !== undefined ) {
			if ( value === null ) {
				jQuery.removeAttr( elem, name );
				return;
			}

			if ( hooks && "set" in hooks &&
				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
				return ret;
			}

			elem.setAttribute( name, value + "" );
			return value;
		}

		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
			return ret;
		}

		ret = jQuery.find.attr( elem, name );

		// Non-existent attributes return null, we normalize to undefined
		return ret == null ? undefined : ret;
	},

	attrHooks: {
		type: {
			set: function( elem, value ) {
				if ( !support.radioValue && value === "radio" &&
					jQuery.nodeName( elem, "input" ) ) {

					// Setting the type on a radio button after the value resets the value in IE8-9
					// Reset value to default in case type is set after value during creation
					var val = elem.value;
					elem.setAttribute( "type", value );
					if ( val ) {
						elem.value = val;
					}
					return value;
				}
			}
		}
	},

	removeAttr: function( elem, value ) {
		var name, propName,
			i = 0,
			attrNames = value && value.match( rnotwhite );

		if ( attrNames && elem.nodeType === 1 ) {
			while ( ( name = attrNames[ i++ ] ) ) {
				propName = jQuery.propFix[ name ] || name;

				// Boolean attributes get special treatment (#10870)
				if ( jQuery.expr.match.bool.test( name ) ) {

					// Set corresponding property to false
					if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
						elem[ propName ] = false;

					// Support: IE<9
					// Also clear defaultChecked/defaultSelected (if appropriate)
					} else {
						elem[ jQuery.camelCase( "default-" + name ) ] =
							elem[ propName ] = false;
					}

				// See #9699 for explanation of this approach (setting first, then removal)
				} else {
					jQuery.attr( elem, name, "" );
				}

				elem.removeAttribute( getSetAttribute ? name : propName );
			}
		}
	}
} );

// Hooks for boolean attributes
boolHook = {
	set: function( elem, value, name ) {
		if ( value === false ) {

			// Remove boolean attributes when set to false
			jQuery.removeAttr( elem, name );
		} else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {

			// IE<8 needs the *property* name
			elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );

		} else {

			// Support: IE<9
			// Use defaultChecked and defaultSelected for oldIE
			elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
		}
		return name;
	}
};

jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
	var getter = attrHandle[ name ] || jQuery.find.attr;

	if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
		attrHandle[ name ] = function( elem, name, isXML ) {
			var ret, handle;
			if ( !isXML ) {

				// Avoid an infinite loop by temporarily removing this function from the getter
				handle = attrHandle[ name ];
				attrHandle[ name ] = ret;
				ret = getter( elem, name, isXML ) != null ?
					name.toLowerCase() :
					null;
				attrHandle[ name ] = handle;
			}
			return ret;
		};
	} else {
		attrHandle[ name ] = function( elem, name, isXML ) {
			if ( !isXML ) {
				return elem[ jQuery.camelCase( "default-" + name ) ] ?
					name.toLowerCase() :
					null;
			}
		};
	}
} );

// fix oldIE attroperties
if ( !getSetInput || !getSetAttribute ) {
	jQuery.attrHooks.value = {
		set: function( elem, value, name ) {
			if ( jQuery.nodeName( elem, "input" ) ) {

				// Does not return so that setAttribute is also used
				elem.defaultValue = value;
			} else {

				// Use nodeHook if defined (#1954); otherwise setAttribute is fine
				return nodeHook && nodeHook.set( elem, value, name );
			}
		}
	};
}

// IE6/7 do not support getting/setting some attributes with get/setAttribute
if ( !getSetAttribute ) {

	// Use this for any attribute in IE6/7
	// This fixes almost every IE6/7 issue
	nodeHook = {
		set: function( elem, value, name ) {

			// Set the existing or create a new attribute node
			var ret = elem.getAttributeNode( name );
			if ( !ret ) {
				elem.setAttributeNode(
					( ret = elem.ownerDocument.createAttribute( name ) )
				);
			}

			ret.value = value += "";

			// Break association with cloned elements by also using setAttribute (#9646)
			if ( name === "value" || value === elem.getAttribute( name ) ) {
				return value;
			}
		}
	};

	// Some attributes are constructed with empty-string values when not defined
	attrHandle.id = attrHandle.name = attrHandle.coords =
		function( elem, name, isXML ) {
			var ret;
			if ( !isXML ) {
				return ( ret = elem.getAttributeNode( name ) ) && ret.value !== "" ?
					ret.value :
					null;
			}
		};

	// Fixing value retrieval on a button requires this module
	jQuery.valHooks.button = {
		get: function( elem, name ) {
			var ret = elem.getAttributeNode( name );
			if ( ret && ret.specified ) {
				return ret.value;
			}
		},
		set: nodeHook.set
	};

	// Set contenteditable to false on removals(#10429)
	// Setting to empty string throws an error as an invalid value
	jQuery.attrHooks.contenteditable = {
		set: function( elem, value, name ) {
			nodeHook.set( elem, value === "" ? false : value, name );
		}
	};

	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
	// This is for removals
	jQuery.each( [ "width", "height" ], function( i, name ) {
		jQuery.attrHooks[ name ] = {
			set: function( elem, value ) {
				if ( value === "" ) {
					elem.setAttribute( name, "auto" );
					return value;
				}
			}
		};
	} );
}

if ( !support.style ) {
	jQuery.attrHooks.style = {
		get: function( elem ) {

			// Return undefined in the case of empty string
			// Note: IE uppercases css property names, but if we were to .toLowerCase()
			// .cssText, that would destroy case sensitivity in URL's, like in "background"
			return elem.style.cssText || undefined;
		},
		set: function( elem, value ) {
			return ( elem.style.cssText = value + "" );
		}
	};
}




var rfocusable = /^(?:input|select|textarea|button|object)$/i,
	rclickable = /^(?:a|area)$/i;

jQuery.fn.extend( {
	prop: function( name, value ) {
		return access( this, jQuery.prop, name, value, arguments.length > 1 );
	},

	removeProp: function( name ) {
		name = jQuery.propFix[ name ] || name;
		return this.each( function() {

			// try/catch handles cases where IE balks (such as removing a property on window)
			try {
				this[ name ] = undefined;
				delete this[ name ];
			} catch ( e ) {}
		} );
	}
} );

jQuery.extend( {
	prop: function( elem, name, value ) {
		var ret, hooks,
			nType = elem.nodeType;

		// Don't get/set properties on text, comment and attribute nodes
		if ( nType === 3 || nType === 8 || nType === 2 ) {
			return;
		}

		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {

			// Fix name and attach hooks
			name = jQuery.propFix[ name ] || name;
			hooks = jQuery.propHooks[ name ];
		}

		if ( value !== undefined ) {
			if ( hooks && "set" in hooks &&
				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
				return ret;
			}

			return ( elem[ name ] = value );
		}

		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
			return ret;
		}

		return elem[ name ];
	},

	propHooks: {
		tabIndex: {
			get: function( elem ) {

				// elem.tabIndex doesn't always return the
				// correct value when it hasn't been explicitly set
				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
				// Use proper attribute retrieval(#12072)
				var tabindex = jQuery.find.attr( elem, "tabindex" );

				return tabindex ?
					parseInt( tabindex, 10 ) :
					rfocusable.test( elem.nodeName ) ||
						rclickable.test( elem.nodeName ) && elem.href ?
							0 :
							-1;
			}
		}
	},

	propFix: {
		"for": "htmlFor",
		"class": "className"
	}
} );

// Some attributes require a special call on IE
// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
if ( !support.hrefNormalized ) {

	// href/src property should get the full normalized URL (#10299/#12915)
	jQuery.each( [ "href", "src" ], function( i, name ) {
		jQuery.propHooks[ name ] = {
			get: function( elem ) {
				return elem.getAttribute( name, 4 );
			}
		};
	} );
}

// Support: Safari, IE9+
// Accessing the selectedIndex property
// forces the browser to respect setting selected
// on the option
// The getter ensures a default option is selected
// when in an optgroup
if ( !support.optSelected ) {
	jQuery.propHooks.selected = {
		get: function( elem ) {
			var parent = elem.parentNode;

			if ( parent ) {
				parent.selectedIndex;

				// Make sure that it also works with optgroups, see #5701
				if ( parent.parentNode ) {
					parent.parentNode.selectedIndex;
				}
			}
			return null;
		},
		set: function( elem ) {
			var parent = elem.parentNode;
			if ( parent ) {
				parent.selectedIndex;

				if ( parent.parentNode ) {
					parent.parentNode.selectedIndex;
				}
			}
		}
	};
}

jQuery.each( [
	"tabIndex",
	"readOnly",
	"maxLength",
	"cellSpacing",
	"cellPadding",
	"rowSpan",
	"colSpan",
	"useMap",
	"frameBorder",
	"contentEditable"
], function() {
	jQuery.propFix[ this.toLowerCase() ] = this;
} );

// IE6/7 call enctype encoding
if ( !support.enctype ) {
	jQuery.propFix.enctype = "encoding";
}




var rclass = /[\t\r\n\f]/g;

function getClass( elem ) {
	return jQuery.attr( elem, "class" ) || "";
}

jQuery.fn.extend( {
	addClass: function( value ) {
		var classes, elem, cur, curValue, clazz, j, finalValue,
			i = 0;

		if ( jQuery.isFunction( value ) ) {
			return this.each( function( j ) {
				jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
			} );
		}

		if ( typeof value === "string" && value ) {
			classes = value.match( rnotwhite ) || [];

			while ( ( elem = this[ i++ ] ) ) {
				curValue = getClass( elem );
				cur = elem.nodeType === 1 &&
					( " " + curValue + " " ).replace( rclass, " " );

				if ( cur ) {
					j = 0;
					while ( ( clazz = classes[ j++ ] ) ) {
						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
							cur += clazz + " ";
						}
					}

					// only assign if different to avoid unneeded rendering.
					finalValue = jQuery.trim( cur );
					if ( curValue !== finalValue ) {
						jQuery.attr( elem, "class", finalValue );
					}
				}
			}
		}

		return this;
	},

	removeClass: function( value ) {
		var classes, elem, cur, curValue, clazz, j, finalValue,
			i = 0;

		if ( jQuery.isFunction( value ) ) {
			return this.each( function( j ) {
				jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
			} );
		}

		if ( !arguments.length ) {
			return this.attr( "class", "" );
		}

		if ( typeof value === "string" && value ) {
			classes = value.match( rnotwhite ) || [];

			while ( ( elem = this[ i++ ] ) ) {
				curValue = getClass( elem );

				// This expression is here for better compressibility (see addClass)
				cur = elem.nodeType === 1 &&
					( " " + curValue + " " ).replace( rclass, " " );

				if ( cur ) {
					j = 0;
					while ( ( clazz = classes[ j++ ] ) ) {

						// Remove *all* instances
						while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
							cur = cur.replace( " " + clazz + " ", " " );
						}
					}

					// Only assign if different to avoid unneeded rendering.
					finalValue = jQuery.trim( cur );
					if ( curValue !== finalValue ) {
						jQuery.attr( elem, "class", finalValue );
					}
				}
			}
		}

		return this;
	},

	toggleClass: function( value, stateVal ) {
		var type = typeof value;

		if ( typeof stateVal === "boolean" && type === "string" ) {
			return stateVal ? this.addClass( value ) : this.removeClass( value );
		}

		if ( jQuery.isFunction( value ) ) {
			return this.each( function( i ) {
				jQuery( this ).toggleClass(
					value.call( this, i, getClass( this ), stateVal ),
					stateVal
				);
			} );
		}

		return this.each( function() {
			var className, i, self, classNames;

			if ( type === "string" ) {

				// Toggle individual class names
				i = 0;
				self = jQuery( this );
				classNames = value.match( rnotwhite ) || [];

				while ( ( className = classNames[ i++ ] ) ) {

					// Check each className given, space separated list
					if ( self.hasClass( className ) ) {
						self.removeClass( className );
					} else {
						self.addClass( className );
					}
				}

			// Toggle whole class name
			} else if ( value === undefined || type === "boolean" ) {
				className = getClass( this );
				if ( className ) {

					// store className if set
					jQuery._data( this, "__className__", className );
				}

				// If the element has a class name or if we're passed "false",
				// then remove the whole classname (if there was one, the above saved it).
				// Otherwise bring back whatever was previously saved (if anything),
				// falling back to the empty string if nothing was stored.
				jQuery.attr( this, "class",
					className || value === false ?
					"" :
					jQuery._data( this, "__className__" ) || ""
				);
			}
		} );
	},

	hasClass: function( selector ) {
		var className, elem,
			i = 0;

		className = " " + selector + " ";
		while ( ( elem = this[ i++ ] ) ) {
			if ( elem.nodeType === 1 &&
				( " " + getClass( elem ) + " " ).replace( rclass, " " )
					.indexOf( className ) > -1
			) {
				return true;
			}
		}

		return false;
	}
} );




// Return jQuery for attributes-only inclusion


jQuery.each( ( "blur focus focusin focusout load resize scroll unload click dblclick " +
	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
	"change select submit keydown keypress keyup error contextmenu" ).split( " " ),
	function( i, name ) {

	// Handle event binding
	jQuery.fn[ name ] = function( data, fn ) {
		return arguments.length > 0 ?
			this.on( name, null, data, fn ) :
			this.trigger( name );
	};
} );

jQuery.fn.extend( {
	hover: function( fnOver, fnOut ) {
		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
	}
} );


var location = window.location;

var nonce = jQuery.now();

var rquery = ( /\?/ );



var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;

jQuery.parseJSON = function( data ) {

	// Attempt to parse using the native JSON parser first
	if ( window.JSON && window.JSON.parse ) {

		// Support: Android 2.3
		// Workaround failure to string-cast null input
		return window.JSON.parse( data + "" );
	}

	var requireNonComma,
		depth = null,
		str = jQuery.trim( data + "" );

	// Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
	// after removing valid tokens
	return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {

		// Force termination if we see a misplaced comma
		if ( requireNonComma && comma ) {
			depth = 0;
		}

		// Perform no more replacements after returning to outermost depth
		if ( depth === 0 ) {
			return token;
		}

		// Commas must not follow "[", "{", or ","
		requireNonComma = open || comma;

		// Determine new depth
		// array/object open ("[" or "{"): depth += true - false (increment)
		// array/object close ("]" or "}"): depth += false - true (decrement)
		// other cases ("," or primitive): depth += true - true (numeric cast)
		depth += !close - !open;

		// Remove this token
		return "";
	} ) ) ?
		( Function( "return " + str ) )() :
		jQuery.error( "Invalid JSON: " + data );
};


// Cross-browser xml parsing
jQuery.parseXML = function( data ) {
	var xml, tmp;
	if ( !data || typeof data !== "string" ) {
		return null;
	}
	try {
		if ( window.DOMParser ) { // Standard
			tmp = new window.DOMParser();
			xml = tmp.parseFromString( data, "text/xml" );
		} else { // IE
			xml = new window.ActiveXObject( "Microsoft.XMLDOM" );
			xml.async = "false";
			xml.loadXML( data );
		}
	} catch ( e ) {
		xml = undefined;
	}
	if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
		jQuery.error( "Invalid XML: " + data );
	}
	return xml;
};


var
	rhash = /#.*$/,
	rts = /([?&])_=[^&]*/,

	// IE leaves an \r character at EOL
	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg,

	// #7653, #8125, #8152: local protocol detection
	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
	rnoContent = /^(?:GET|HEAD)$/,
	rprotocol = /^\/\//,
	rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,

	/* Prefilters
	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
	 * 2) These are called:
	 *    - BEFORE asking for a transport
	 *    - AFTER param serialization (s.data is a string if s.processData is true)
	 * 3) key is the dataType
	 * 4) the catchall symbol "*" can be used
	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
	 */
	prefilters = {},

	/* Transports bindings
	 * 1) key is the dataType
	 * 2) the catchall symbol "*" can be used
	 * 3) selection will start with transport dataType and THEN go to "*" if needed
	 */
	transports = {},

	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
	allTypes = "*/".concat( "*" ),

	// Document location
	ajaxLocation = location.href,

	// Segment location into parts
	ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];

// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {

	// dataTypeExpression is optional and defaults to "*"
	return function( dataTypeExpression, func ) {

		if ( typeof dataTypeExpression !== "string" ) {
			func = dataTypeExpression;
			dataTypeExpression = "*";
		}

		var dataType,
			i = 0,
			dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];

		if ( jQuery.isFunction( func ) ) {

			// For each dataType in the dataTypeExpression
			while ( ( dataType = dataTypes[ i++ ] ) ) {

				// Prepend if requested
				if ( dataType.charAt( 0 ) === "+" ) {
					dataType = dataType.slice( 1 ) || "*";
					( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );

				// Otherwise append
				} else {
					( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
				}
			}
		}
	};
}

// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {

	var inspected = {},
		seekingTransport = ( structure === transports );

	function inspect( dataType ) {
		var selected;
		inspected[ dataType ] = true;
		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
			if ( typeof dataTypeOrTransport === "string" &&
				!seekingTransport && !inspected[ dataTypeOrTransport ] ) {

				options.dataTypes.unshift( dataTypeOrTransport );
				inspect( dataTypeOrTransport );
				return false;
			} else if ( seekingTransport ) {
				return !( selected = dataTypeOrTransport );
			}
		} );
		return selected;
	}

	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
}

// A special extend for ajax options
// that takes "flat" options (not to be deep extended)
// Fixes #9887
function ajaxExtend( target, src ) {
	var deep, key,
		flatOptions = jQuery.ajaxSettings.flatOptions || {};

	for ( key in src ) {
		if ( src[ key ] !== undefined ) {
			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
		}
	}
	if ( deep ) {
		jQuery.extend( true, target, deep );
	}

	return target;
}

/* Handles responses to an ajax request:
 * - finds the right dataType (mediates between content-type and expected dataType)
 * - returns the corresponding response
 */
function ajaxHandleResponses( s, jqXHR, responses ) {
	var firstDataType, ct, finalDataType, type,
		contents = s.contents,
		dataTypes = s.dataTypes;

	// Remove auto dataType and get content-type in the process
	while ( dataTypes[ 0 ] === "*" ) {
		dataTypes.shift();
		if ( ct === undefined ) {
			ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
		}
	}

	// Check if we're dealing with a known content-type
	if ( ct ) {
		for ( type in contents ) {
			if ( contents[ type ] && contents[ type ].test( ct ) ) {
				dataTypes.unshift( type );
				break;
			}
		}
	}

	// Check to see if we have a response for the expected dataType
	if ( dataTypes[ 0 ] in responses ) {
		finalDataType = dataTypes[ 0 ];
	} else {

		// Try convertible dataTypes
		for ( type in responses ) {
			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
				finalDataType = type;
				break;
			}
			if ( !firstDataType ) {
				firstDataType = type;
			}
		}

		// Or just use first one
		finalDataType = finalDataType || firstDataType;
	}

	// If we found a dataType
	// We add the dataType to the list if needed
	// and return the corresponding response
	if ( finalDataType ) {
		if ( finalDataType !== dataTypes[ 0 ] ) {
			dataTypes.unshift( finalDataType );
		}
		return responses[ finalDataType ];
	}
}

/* Chain conversions given the request and the original response
 * Also sets the responseXXX fields on the jqXHR instance
 */
function ajaxConvert( s, response, jqXHR, isSuccess ) {
	var conv2, current, conv, tmp, prev,
		converters = {},

		// Work with a copy of dataTypes in case we need to modify it for conversion
		dataTypes = s.dataTypes.slice();

	// Create converters map with lowercased keys
	if ( dataTypes[ 1 ] ) {
		for ( conv in s.converters ) {
			converters[ conv.toLowerCase() ] = s.converters[ conv ];
		}
	}

	current = dataTypes.shift();

	// Convert to each sequential dataType
	while ( current ) {

		if ( s.responseFields[ current ] ) {
			jqXHR[ s.responseFields[ current ] ] = response;
		}

		// Apply the dataFilter if provided
		if ( !prev && isSuccess && s.dataFilter ) {
			response = s.dataFilter( response, s.dataType );
		}

		prev = current;
		current = dataTypes.shift();

		if ( current ) {

			// There's only work to do if current dataType is non-auto
			if ( current === "*" ) {

				current = prev;

			// Convert response if prev dataType is non-auto and differs from current
			} else if ( prev !== "*" && prev !== current ) {

				// Seek a direct converter
				conv = converters[ prev + " " + current ] || converters[ "* " + current ];

				// If none found, seek a pair
				if ( !conv ) {
					for ( conv2 in converters ) {

						// If conv2 outputs current
						tmp = conv2.split( " " );
						if ( tmp[ 1 ] === current ) {

							// If prev can be converted to accepted input
							conv = converters[ prev + " " + tmp[ 0 ] ] ||
								converters[ "* " + tmp[ 0 ] ];
							if ( conv ) {

								// Condense equivalence converters
								if ( conv === true ) {
									conv = converters[ conv2 ];

								// Otherwise, insert the intermediate dataType
								} else if ( converters[ conv2 ] !== true ) {
									current = tmp[ 0 ];
									dataTypes.unshift( tmp[ 1 ] );
								}
								break;
							}
						}
					}
				}

				// Apply converter (if not an equivalence)
				if ( conv !== true ) {

					// Unless errors are allowed to bubble, catch and return them
					if ( conv && s[ "throws" ] ) { // jscs:ignore requireDotNotation
						response = conv( response );
					} else {
						try {
							response = conv( response );
						} catch ( e ) {
							return {
								state: "parsererror",
								error: conv ? e : "No conversion from " + prev + " to " + current
							};
						}
					}
				}
			}
		}
	}

	return { state: "success", data: response };
}

jQuery.extend( {

	// Counter for holding the number of active queries
	active: 0,

	// Last-Modified header cache for next request
	lastModified: {},
	etag: {},

	ajaxSettings: {
		url: ajaxLocation,
		type: "GET",
		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
		global: true,
		processData: true,
		async: true,
		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
		/*
		timeout: 0,
		data: null,
		dataType: null,
		username: null,
		password: null,
		cache: null,
		throws: false,
		traditional: false,
		headers: {},
		*/

		accepts: {
			"*": allTypes,
			text: "text/plain",
			html: "text/html",
			xml: "application/xml, text/xml",
			json: "application/json, text/javascript"
		},

		contents: {
			xml: /\bxml\b/,
			html: /\bhtml/,
			json: /\bjson\b/
		},

		responseFields: {
			xml: "responseXML",
			text: "responseText",
			json: "responseJSON"
		},

		// Data converters
		// Keys separate source (or catchall "*") and destination types with a single space
		converters: {

			// Convert anything to text
			"* text": String,

			// Text to html (true = no transformation)
			"text html": true,

			// Evaluate text as a json expression
			"text json": jQuery.parseJSON,

			// Parse text as xml
			"text xml": jQuery.parseXML
		},

		// For options that shouldn't be deep extended:
		// you can add your own custom options here if
		// and when you create one that shouldn't be
		// deep extended (see ajaxExtend)
		flatOptions: {
			url: true,
			context: true
		}
	},

	// Creates a full fledged settings object into target
	// with both ajaxSettings and settings fields.
	// If target is omitted, writes into ajaxSettings.
	ajaxSetup: function( target, settings ) {
		return settings ?

			// Building a settings object
			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :

			// Extending ajaxSettings
			ajaxExtend( jQuery.ajaxSettings, target );
	},

	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
	ajaxTransport: addToPrefiltersOrTransports( transports ),

	// Main method
	ajax: function( url, options ) {

		// If url is an object, simulate pre-1.5 signature
		if ( typeof url === "object" ) {
			options = url;
			url = undefined;
		}

		// Force options to be an object
		options = options || {};

		var

			// Cross-domain detection vars
			parts,

			// Loop variable
			i,

			// URL without anti-cache param
			cacheURL,

			// Response headers as string
			responseHeadersString,

			// timeout handle
			timeoutTimer,

			// To know if global events are to be dispatched
			fireGlobals,

			transport,

			// Response headers
			responseHeaders,

			// Create the final options object
			s = jQuery.ajaxSetup( {}, options ),

			// Callbacks context
			callbackContext = s.context || s,

			// Context for global events is callbackContext if it is a DOM node or jQuery collection
			globalEventContext = s.context &&
				( callbackContext.nodeType || callbackContext.jquery ) ?
					jQuery( callbackContext ) :
					jQuery.event,

			// Deferreds
			deferred = jQuery.Deferred(),
			completeDeferred = jQuery.Callbacks( "once memory" ),

			// Status-dependent callbacks
			statusCode = s.statusCode || {},

			// Headers (they are sent all at once)
			requestHeaders = {},
			requestHeadersNames = {},

			// The jqXHR state
			state = 0,

			// Default abort message
			strAbort = "canceled",

			// Fake xhr
			jqXHR = {
				readyState: 0,

				// Builds headers hashtable if needed
				getResponseHeader: function( key ) {
					var match;
					if ( state === 2 ) {
						if ( !responseHeaders ) {
							responseHeaders = {};
							while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
								responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
							}
						}
						match = responseHeaders[ key.toLowerCase() ];
					}
					return match == null ? null : match;
				},

				// Raw string
				getAllResponseHeaders: function() {
					return state === 2 ? responseHeadersString : null;
				},

				// Caches the header
				setRequestHeader: function( name, value ) {
					var lname = name.toLowerCase();
					if ( !state ) {
						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
						requestHeaders[ name ] = value;
					}
					return this;
				},

				// Overrides response content-type header
				overrideMimeType: function( type ) {
					if ( !state ) {
						s.mimeType = type;
					}
					return this;
				},

				// Status-dependent callbacks
				statusCode: function( map ) {
					var code;
					if ( map ) {
						if ( state < 2 ) {
							for ( code in map ) {

								// Lazy-add the new callback in a way that preserves old ones
								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
							}
						} else {

							// Execute the appropriate callbacks
							jqXHR.always( map[ jqXHR.status ] );
						}
					}
					return this;
				},

				// Cancel the request
				abort: function( statusText ) {
					var finalText = statusText || strAbort;
					if ( transport ) {
						transport.abort( finalText );
					}
					done( 0, finalText );
					return this;
				}
			};

		// Attach deferreds
		deferred.promise( jqXHR ).complete = completeDeferred.add;
		jqXHR.success = jqXHR.done;
		jqXHR.error = jqXHR.fail;

		// Remove hash character (#7531: and string promotion)
		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
		// Handle falsy url in the settings object (#10093: consistency with old signature)
		// We also use the url parameter if available
		s.url = ( ( url || s.url || ajaxLocation ) + "" )
			.replace( rhash, "" )
			.replace( rprotocol, ajaxLocParts[ 1 ] + "//" );

		// Alias method option to type as per ticket #12004
		s.type = options.method || options.type || s.method || s.type;

		// Extract dataTypes list
		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];

		// A cross-domain request is in order when we have a protocol:host:port mismatch
		if ( s.crossDomain == null ) {
			parts = rurl.exec( s.url.toLowerCase() );
			s.crossDomain = !!( parts &&
				( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
			);
		}

		// Convert data if not already a string
		if ( s.data && s.processData && typeof s.data !== "string" ) {
			s.data = jQuery.param( s.data, s.traditional );
		}

		// Apply prefilters
		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );

		// If request was aborted inside a prefilter, stop there
		if ( state === 2 ) {
			return jqXHR;
		}

		// We can fire global events as of now if asked to
		// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
		fireGlobals = jQuery.event && s.global;

		// Watch for a new set of requests
		if ( fireGlobals && jQuery.active++ === 0 ) {
			jQuery.event.trigger( "ajaxStart" );
		}

		// Uppercase the type
		s.type = s.type.toUpperCase();

		// Determine if request has content
		s.hasContent = !rnoContent.test( s.type );

		// Save the URL in case we're toying with the If-Modified-Since
		// and/or If-None-Match header later on
		cacheURL = s.url;

		// More options handling for requests with no content
		if ( !s.hasContent ) {

			// If data is available, append data to url
			if ( s.data ) {
				cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );

				// #9682: remove data so that it's not used in an eventual retry
				delete s.data;
			}

			// Add anti-cache in url if needed
			if ( s.cache === false ) {
				s.url = rts.test( cacheURL ) ?

					// If there is already a '_' parameter, set its value
					cacheURL.replace( rts, "$1_=" + nonce++ ) :

					// Otherwise add one to the end
					cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
			}
		}

		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
		if ( s.ifModified ) {
			if ( jQuery.lastModified[ cacheURL ] ) {
				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
			}
			if ( jQuery.etag[ cacheURL ] ) {
				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
			}
		}

		// Set the correct header, if data is being sent
		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
			jqXHR.setRequestHeader( "Content-Type", s.contentType );
		}

		// Set the Accepts header for the server, depending on the dataType
		jqXHR.setRequestHeader(
			"Accept",
			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
				s.accepts[ s.dataTypes[ 0 ] ] +
					( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
				s.accepts[ "*" ]
		);

		// Check for headers option
		for ( i in s.headers ) {
			jqXHR.setRequestHeader( i, s.headers[ i ] );
		}

		// Allow custom headers/mimetypes and early abort
		if ( s.beforeSend &&
			( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {

			// Abort if not done already and return
			return jqXHR.abort();
		}

		// aborting is no longer a cancellation
		strAbort = "abort";

		// Install callbacks on deferreds
		for ( i in { success: 1, error: 1, complete: 1 } ) {
			jqXHR[ i ]( s[ i ] );
		}

		// Get transport
		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );

		// If no transport, we auto-abort
		if ( !transport ) {
			done( -1, "No Transport" );
		} else {
			jqXHR.readyState = 1;

			// Send global event
			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
			}

			// If request was aborted inside ajaxSend, stop there
			if ( state === 2 ) {
				return jqXHR;
			}

			// Timeout
			if ( s.async && s.timeout > 0 ) {
				timeoutTimer = window.setTimeout( function() {
					jqXHR.abort( "timeout" );
				}, s.timeout );
			}

			try {
				state = 1;
				transport.send( requestHeaders, done );
			} catch ( e ) {

				// Propagate exception as error if not done
				if ( state < 2 ) {
					done( -1, e );

				// Simply rethrow otherwise
				} else {
					throw e;
				}
			}
		}

		// Callback for when everything is done
		function done( status, nativeStatusText, responses, headers ) {
			var isSuccess, success, error, response, modified,
				statusText = nativeStatusText;

			// Called once
			if ( state === 2 ) {
				return;
			}

			// State is "done" now
			state = 2;

			// Clear timeout if it exists
			if ( timeoutTimer ) {
				window.clearTimeout( timeoutTimer );
			}

			// Dereference transport for early garbage collection
			// (no matter how long the jqXHR object will be used)
			transport = undefined;

			// Cache response headers
			responseHeadersString = headers || "";

			// Set readyState
			jqXHR.readyState = status > 0 ? 4 : 0;

			// Determine if successful
			isSuccess = status >= 200 && status < 300 || status === 304;

			// Get response data
			if ( responses ) {
				response = ajaxHandleResponses( s, jqXHR, responses );
			}

			// Convert no matter what (that way responseXXX fields are always set)
			response = ajaxConvert( s, response, jqXHR, isSuccess );

			// If successful, handle type chaining
			if ( isSuccess ) {

				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
				if ( s.ifModified ) {
					modified = jqXHR.getResponseHeader( "Last-Modified" );
					if ( modified ) {
						jQuery.lastModified[ cacheURL ] = modified;
					}
					modified = jqXHR.getResponseHeader( "etag" );
					if ( modified ) {
						jQuery.etag[ cacheURL ] = modified;
					}
				}

				// if no content
				if ( status === 204 || s.type === "HEAD" ) {
					statusText = "nocontent";

				// if not modified
				} else if ( status === 304 ) {
					statusText = "notmodified";

				// If we have data, let's convert it
				} else {
					statusText = response.state;
					success = response.data;
					error = response.error;
					isSuccess = !error;
				}
			} else {

				// We extract error from statusText
				// then normalize statusText and status for non-aborts
				error = statusText;
				if ( status || !statusText ) {
					statusText = "error";
					if ( status < 0 ) {
						status = 0;
					}
				}
			}

			// Set data for the fake xhr object
			jqXHR.status = status;
			jqXHR.statusText = ( nativeStatusText || statusText ) + "";

			// Success/Error
			if ( isSuccess ) {
				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
			} else {
				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
			}

			// Status-dependent callbacks
			jqXHR.statusCode( statusCode );
			statusCode = undefined;

			if ( fireGlobals ) {
				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
					[ jqXHR, s, isSuccess ? success : error ] );
			}

			// Complete
			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );

			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );

				// Handle the global AJAX counter
				if ( !( --jQuery.active ) ) {
					jQuery.event.trigger( "ajaxStop" );
				}
			}
		}

		return jqXHR;
	},

	getJSON: function( url, data, callback ) {
		return jQuery.get( url, data, callback, "json" );
	},

	getScript: function( url, callback ) {
		return jQuery.get( url, undefined, callback, "script" );
	}
} );

jQuery.each( [ "get", "post" ], function( i, method ) {
	jQuery[ method ] = function( url, data, callback, type ) {

		// shift arguments if data argument was omitted
		if ( jQuery.isFunction( data ) ) {
			type = type || callback;
			callback = data;
			data = undefined;
		}

		// The url can be an options object (which then must have .url)
		return jQuery.ajax( jQuery.extend( {
			url: url,
			type: method,
			dataType: type,
			data: data,
			success: callback
		}, jQuery.isPlainObject( url ) && url ) );
	};
} );


jQuery._evalUrl = function( url ) {
	return jQuery.ajax( {
		url: url,

		// Make this explicit, since user can override this through ajaxSetup (#11264)
		type: "GET",
		dataType: "script",
		cache: true,
		async: false,
		global: false,
		"throws": true
	} );
};


jQuery.fn.extend( {
	wrapAll: function( html ) {
		if ( jQuery.isFunction( html ) ) {
			return this.each( function( i ) {
				jQuery( this ).wrapAll( html.call( this, i ) );
			} );
		}

		if ( this[ 0 ] ) {

			// The elements to wrap the target around
			var wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );

			if ( this[ 0 ].parentNode ) {
				wrap.insertBefore( this[ 0 ] );
			}

			wrap.map( function() {
				var elem = this;

				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
					elem = elem.firstChild;
				}

				return elem;
			} ).append( this );
		}

		return this;
	},

	wrapInner: function( html ) {
		if ( jQuery.isFunction( html ) ) {
			return this.each( function( i ) {
				jQuery( this ).wrapInner( html.call( this, i ) );
			} );
		}

		return this.each( function() {
			var self = jQuery( this ),
				contents = self.contents();

			if ( contents.length ) {
				contents.wrapAll( html );

			} else {
				self.append( html );
			}
		} );
	},

	wrap: function( html ) {
		var isFunction = jQuery.isFunction( html );

		return this.each( function( i ) {
			jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );
		} );
	},

	unwrap: function() {
		return this.parent().each( function() {
			if ( !jQuery.nodeName( this, "body" ) ) {
				jQuery( this ).replaceWith( this.childNodes );
			}
		} ).end();
	}
} );


function getDisplay( elem ) {
	return elem.style && elem.style.display || jQuery.css( elem, "display" );
}

function filterHidden( elem ) {
	while ( elem && elem.nodeType === 1 ) {
		if ( getDisplay( elem ) === "none" || elem.type === "hidden" ) {
			return true;
		}
		elem = elem.parentNode;
	}
	return false;
}

jQuery.expr.filters.hidden = function( elem ) {

	// Support: Opera <= 12.12
	// Opera reports offsetWidths and offsetHeights less than zero on some elements
	return support.reliableHiddenOffsets() ?
		( elem.offsetWidth <= 0 && elem.offsetHeight <= 0 &&
			!elem.getClientRects().length ) :
			filterHidden( elem );
};

jQuery.expr.filters.visible = function( elem ) {
	return !jQuery.expr.filters.hidden( elem );
};




var r20 = /%20/g,
	rbracket = /\[\]$/,
	rCRLF = /\r?\n/g,
	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
	rsubmittable = /^(?:input|select|textarea|keygen)/i;

function buildParams( prefix, obj, traditional, add ) {
	var name;

	if ( jQuery.isArray( obj ) ) {

		// Serialize array item.
		jQuery.each( obj, function( i, v ) {
			if ( traditional || rbracket.test( prefix ) ) {

				// Treat each array item as a scalar.
				add( prefix, v );

			} else {

				// Item is non-scalar (array or object), encode its numeric index.
				buildParams(
					prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
					v,
					traditional,
					add
				);
			}
		} );

	} else if ( !traditional && jQuery.type( obj ) === "object" ) {

		// Serialize object item.
		for ( name in obj ) {
			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
		}

	} else {

		// Serialize scalar item.
		add( prefix, obj );
	}
}

// Serialize an array of form elements or a set of
// key/values into a query string
jQuery.param = function( a, traditional ) {
	var prefix,
		s = [],
		add = function( key, value ) {

			// If value is a function, invoke it and return its value
			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
		};

	// Set traditional to true for jQuery <= 1.3.2 behavior.
	if ( traditional === undefined ) {
		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
	}

	// If an array was passed in, assume that it is an array of form elements.
	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {

		// Serialize the form elements
		jQuery.each( a, function() {
			add( this.name, this.value );
		} );

	} else {

		// If traditional, encode the "old" way (the way 1.3.2 or older
		// did it), otherwise encode params recursively.
		for ( prefix in a ) {
			buildParams( prefix, a[ prefix ], traditional, add );
		}
	}

	// Return the resulting serialization
	return s.join( "&" ).replace( r20, "+" );
};

jQuery.fn.extend( {
	serialize: function() {
		return jQuery.param( this.serializeArray() );
	},
	serializeArray: function() {
		return this.map( function() {

			// Can add propHook for "elements" to filter or add form elements
			var elements = jQuery.prop( this, "elements" );
			return elements ? jQuery.makeArray( elements ) : this;
		} )
		.filter( function() {
			var type = this.type;

			// Use .is(":disabled") so that fieldset[disabled] works
			return this.name && !jQuery( this ).is( ":disabled" ) &&
				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
				( this.checked || !rcheckableType.test( type ) );
		} )
		.map( function( i, elem ) {
			var val = jQuery( this ).val();

			return val == null ?
				null :
				jQuery.isArray( val ) ?
					jQuery.map( val, function( val ) {
						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
					} ) :
					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
		} ).get();
	}
} );


// Create the request object
// (This is still attached to ajaxSettings for backward compatibility)
jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?

	// Support: IE6-IE8
	function() {

		// XHR cannot access local files, always use ActiveX for that case
		if ( this.isLocal ) {
			return createActiveXHR();
		}

		// Support: IE 9-11
		// IE seems to error on cross-domain PATCH requests when ActiveX XHR
		// is used. In IE 9+ always use the native XHR.
		// Note: this condition won't catch Edge as it doesn't define
		// document.documentMode but it also doesn't support ActiveX so it won't
		// reach this code.
		if ( document.documentMode > 8 ) {
			return createStandardXHR();
		}

		// Support: IE<9
		// oldIE XHR does not support non-RFC2616 methods (#13240)
		// See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
		// and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
		// Although this check for six methods instead of eight
		// since IE also does not support "trace" and "connect"
		return /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
			createStandardXHR() || createActiveXHR();
	} :

	// For all other browsers, use the standard XMLHttpRequest object
	createStandardXHR;

var xhrId = 0,
	xhrCallbacks = {},
	xhrSupported = jQuery.ajaxSettings.xhr();

// Support: IE<10
// Open requests must be manually aborted on unload (#5280)
// See https://support.microsoft.com/kb/2856746 for more info
if ( window.attachEvent ) {
	window.attachEvent( "onunload", function() {
		for ( var key in xhrCallbacks ) {
			xhrCallbacks[ key ]( undefined, true );
		}
	} );
}

// Determine support properties
support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
xhrSupported = support.ajax = !!xhrSupported;

// Create transport if the browser can provide an xhr
if ( xhrSupported ) {

	jQuery.ajaxTransport( function( options ) {

		// Cross domain only allowed if supported through XMLHttpRequest
		if ( !options.crossDomain || support.cors ) {

			var callback;

			return {
				send: function( headers, complete ) {
					var i,
						xhr = options.xhr(),
						id = ++xhrId;

					// Open the socket
					xhr.open(
						options.type,
						options.url,
						options.async,
						options.username,
						options.password
					);

					// Apply custom fields if provided
					if ( options.xhrFields ) {
						for ( i in options.xhrFields ) {
							xhr[ i ] = options.xhrFields[ i ];
						}
					}

					// Override mime type if needed
					if ( options.mimeType && xhr.overrideMimeType ) {
						xhr.overrideMimeType( options.mimeType );
					}

					// X-Requested-With header
					// For cross-domain requests, seeing as conditions for a preflight are
					// akin to a jigsaw puzzle, we simply never set it to be sure.
					// (it can always be set on a per-request basis or even using ajaxSetup)
					// For same-domain requests, won't change header if already provided.
					if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
						headers[ "X-Requested-With" ] = "XMLHttpRequest";
					}

					// Set headers
					for ( i in headers ) {

						// Support: IE<9
						// IE's ActiveXObject throws a 'Type Mismatch' exception when setting
						// request header to a null-value.
						//
						// To keep consistent with other XHR implementations, cast the value
						// to string and ignore `undefined`.
						if ( headers[ i ] !== undefined ) {
							xhr.setRequestHeader( i, headers[ i ] + "" );
						}
					}

					// Do send the request
					// This may raise an exception which is actually
					// handled in jQuery.ajax (so no try/catch here)
					xhr.send( ( options.hasContent && options.data ) || null );

					// Listener
					callback = function( _, isAbort ) {
						var status, statusText, responses;

						// Was never called and is aborted or complete
						if ( callback && ( isAbort || xhr.readyState === 4 ) ) {

							// Clean up
							delete xhrCallbacks[ id ];
							callback = undefined;
							xhr.onreadystatechange = jQuery.noop;

							// Abort manually if needed
							if ( isAbort ) {
								if ( xhr.readyState !== 4 ) {
									xhr.abort();
								}
							} else {
								responses = {};
								status = xhr.status;

								// Support: IE<10
								// Accessing binary-data responseText throws an exception
								// (#11426)
								if ( typeof xhr.responseText === "string" ) {
									responses.text = xhr.responseText;
								}

								// Firefox throws an exception when accessing
								// statusText for faulty cross-domain requests
								try {
									statusText = xhr.statusText;
								} catch ( e ) {

									// We normalize with Webkit giving an empty statusText
									statusText = "";
								}

								// Filter status for non standard behaviors

								// If the request is local and we have data: assume a success
								// (success with no data won't get notified, that's the best we
								// can do given current implementations)
								if ( !status && options.isLocal && !options.crossDomain ) {
									status = responses.text ? 200 : 404;

								// IE - #1450: sometimes returns 1223 when it should be 204
								} else if ( status === 1223 ) {
									status = 204;
								}
							}
						}

						// Call complete if needed
						if ( responses ) {
							complete( status, statusText, responses, xhr.getAllResponseHeaders() );
						}
					};

					// Do send the request
					// `xhr.send` may raise an exception, but it will be
					// handled in jQuery.ajax (so no try/catch here)
					if ( !options.async ) {

						// If we're in sync mode we fire the callback
						callback();
					} else if ( xhr.readyState === 4 ) {

						// (IE6 & IE7) if it's in cache and has been
						// retrieved directly we need to fire the callback
						window.setTimeout( callback );
					} else {

						// Register the callback, but delay it in case `xhr.send` throws
						// Add to the list of active xhr callbacks
						xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
					}
				},

				abort: function() {
					if ( callback ) {
						callback( undefined, true );
					}
				}
			};
		}
	} );
}

// Functions to create xhrs
function createStandardXHR() {
	try {
		return new window.XMLHttpRequest();
	} catch ( e ) {}
}

function createActiveXHR() {
	try {
		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
	} catch ( e ) {}
}




// Install script dataType
jQuery.ajaxSetup( {
	accepts: {
		script: "text/javascript, application/javascript, " +
			"application/ecmascript, application/x-ecmascript"
	},
	contents: {
		script: /\b(?:java|ecma)script\b/
	},
	converters: {
		"text script": function( text ) {
			jQuery.globalEval( text );
			return text;
		}
	}
} );

// Handle cache's special case and global
jQuery.ajaxPrefilter( "script", function( s ) {
	if ( s.cache === undefined ) {
		s.cache = false;
	}
	if ( s.crossDomain ) {
		s.type = "GET";
		s.global = false;
	}
} );

// Bind script tag hack transport
jQuery.ajaxTransport( "script", function( s ) {

	// This transport only deals with cross domain requests
	if ( s.crossDomain ) {

		var script,
			head = document.head || jQuery( "head" )[ 0 ] || document.documentElement;

		return {

			send: function( _, callback ) {

				script = document.createElement( "script" );

				script.async = true;

				if ( s.scriptCharset ) {
					script.charset = s.scriptCharset;
				}

				script.src = s.url;

				// Attach handlers for all browsers
				script.onload = script.onreadystatechange = function( _, isAbort ) {

					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {

						// Handle memory leak in IE
						script.onload = script.onreadystatechange = null;

						// Remove the script
						if ( script.parentNode ) {
							script.parentNode.removeChild( script );
						}

						// Dereference the script
						script = null;

						// Callback if not abort
						if ( !isAbort ) {
							callback( 200, "success" );
						}
					}
				};

				// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
				// Use native DOM manipulation to avoid our domManip AJAX trickery
				head.insertBefore( script, head.firstChild );
			},

			abort: function() {
				if ( script ) {
					script.onload( undefined, true );
				}
			}
		};
	}
} );




var oldCallbacks = [],
	rjsonp = /(=)\?(?=&|$)|\?\?/;

// Default jsonp settings
jQuery.ajaxSetup( {
	jsonp: "callback",
	jsonpCallback: function() {
		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
		this[ callback ] = true;
		return callback;
	}
} );

// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {

	var callbackName, overwritten, responseContainer,
		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
			"url" :
			typeof s.data === "string" &&
				( s.contentType || "" )
					.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
				rjsonp.test( s.data ) && "data"
		);

	// Handle iff the expected data type is "jsonp" or we have a parameter to set
	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {

		// Get callback name, remembering preexisting value associated with it
		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
			s.jsonpCallback() :
			s.jsonpCallback;

		// Insert callback into url or form data
		if ( jsonProp ) {
			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
		} else if ( s.jsonp !== false ) {
			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
		}

		// Use data converter to retrieve json after script execution
		s.converters[ "script json" ] = function() {
			if ( !responseContainer ) {
				jQuery.error( callbackName + " was not called" );
			}
			return responseContainer[ 0 ];
		};

		// force json dataType
		s.dataTypes[ 0 ] = "json";

		// Install callback
		overwritten = window[ callbackName ];
		window[ callbackName ] = function() {
			responseContainer = arguments;
		};

		// Clean-up function (fires after converters)
		jqXHR.always( function() {

			// If previous value didn't exist - remove it
			if ( overwritten === undefined ) {
				jQuery( window ).removeProp( callbackName );

			// Otherwise restore preexisting value
			} else {
				window[ callbackName ] = overwritten;
			}

			// Save back as free
			if ( s[ callbackName ] ) {

				// make sure that re-using the options doesn't screw things around
				s.jsonpCallback = originalSettings.jsonpCallback;

				// save the callback name for future use
				oldCallbacks.push( callbackName );
			}

			// Call if it was a function and we have a response
			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
				overwritten( responseContainer[ 0 ] );
			}

			responseContainer = overwritten = undefined;
		} );

		// Delegate to script
		return "script";
	}
} );




// data: string of html
// context (optional): If specified, the fragment will be created in this context,
// defaults to document
// keepScripts (optional): If true, will include scripts passed in the html string
jQuery.parseHTML = function( data, context, keepScripts ) {
	if ( !data || typeof data !== "string" ) {
		return null;
	}
	if ( typeof context === "boolean" ) {
		keepScripts = context;
		context = false;
	}
	context = context || document;

	var parsed = rsingleTag.exec( data ),
		scripts = !keepScripts && [];

	// Single tag
	if ( parsed ) {
		return [ context.createElement( parsed[ 1 ] ) ];
	}

	parsed = buildFragment( [ data ], context, scripts );

	if ( scripts && scripts.length ) {
		jQuery( scripts ).remove();
	}

	return jQuery.merge( [], parsed.childNodes );
};


// Keep a copy of the old load method
var _load = jQuery.fn.load;

/**
 * Load a url into a page
 */
jQuery.fn.load = function( url, params, callback ) {
	if ( typeof url !== "string" && _load ) {
		return _load.apply( this, arguments );
	}

	var selector, type, response,
		self = this,
		off = url.indexOf( " " );

	if ( off > -1 ) {
		selector = jQuery.trim( url.slice( off, url.length ) );
		url = url.slice( 0, off );
	}

	// If it's a function
	if ( jQuery.isFunction( params ) ) {

		// We assume that it's the callback
		callback = params;
		params = undefined;

	// Otherwise, build a param string
	} else if ( params && typeof params === "object" ) {
		type = "POST";
	}

	// If we have elements to modify, make the request
	if ( self.length > 0 ) {
		jQuery.ajax( {
			url: url,

			// If "type" variable is undefined, then "GET" method will be used.
			// Make value of this field explicit since
			// user can override it through ajaxSetup method
			type: type || "GET",
			dataType: "html",
			data: params
		} ).done( function( responseText ) {

			// Save response for use in complete callback
			response = arguments;

			self.html( selector ?

				// If a selector was specified, locate the right elements in a dummy div
				// Exclude scripts to avoid IE 'Permission Denied' errors
				jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :

				// Otherwise use the full result
				responseText );

		// If the request succeeds, this function gets "data", "status", "jqXHR"
		// but they are ignored because response was set above.
		// If it fails, this function gets "jqXHR", "status", "error"
		} ).always( callback && function( jqXHR, status ) {
			self.each( function() {
				callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
			} );
		} );
	}

	return this;
};




// Attach a bunch of functions for handling common AJAX events
jQuery.each( [
	"ajaxStart",
	"ajaxStop",
	"ajaxComplete",
	"ajaxError",
	"ajaxSuccess",
	"ajaxSend"
], function( i, type ) {
	jQuery.fn[ type ] = function( fn ) {
		return this.on( type, fn );
	};
} );




jQuery.expr.filters.animated = function( elem ) {
	return jQuery.grep( jQuery.timers, function( fn ) {
		return elem === fn.elem;
	} ).length;
};





/**
 * Gets a window from an element
 */
function getWindow( elem ) {
	return jQuery.isWindow( elem ) ?
		elem :
		elem.nodeType === 9 ?
			elem.defaultView || elem.parentWindow :
			false;
}

jQuery.offset = {
	setOffset: function( elem, options, i ) {
		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
			position = jQuery.css( elem, "position" ),
			curElem = jQuery( elem ),
			props = {};

		// set position first, in-case top/left are set even on static elem
		if ( position === "static" ) {
			elem.style.position = "relative";
		}

		curOffset = curElem.offset();
		curCSSTop = jQuery.css( elem, "top" );
		curCSSLeft = jQuery.css( elem, "left" );
		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
			jQuery.inArray( "auto", [ curCSSTop, curCSSLeft ] ) > -1;

		// need to be able to calculate position if either top or left
		// is auto and position is either absolute or fixed
		if ( calculatePosition ) {
			curPosition = curElem.position();
			curTop = curPosition.top;
			curLeft = curPosition.left;
		} else {
			curTop = parseFloat( curCSSTop ) || 0;
			curLeft = parseFloat( curCSSLeft ) || 0;
		}

		if ( jQuery.isFunction( options ) ) {

			// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
			options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
		}

		if ( options.top != null ) {
			props.top = ( options.top - curOffset.top ) + curTop;
		}
		if ( options.left != null ) {
			props.left = ( options.left - curOffset.left ) + curLeft;
		}

		if ( "using" in options ) {
			options.using.call( elem, props );
		} else {
			curElem.css( props );
		}
	}
};

jQuery.fn.extend( {
	offset: function( options ) {
		if ( arguments.length ) {
			return options === undefined ?
				this :
				this.each( function( i ) {
					jQuery.offset.setOffset( this, options, i );
				} );
		}

		var docElem, win,
			box = { top: 0, left: 0 },
			elem = this[ 0 ],
			doc = elem && elem.ownerDocument;

		if ( !doc ) {
			return;
		}

		docElem = doc.documentElement;

		// Make sure it's not a disconnected DOM node
		if ( !jQuery.contains( docElem, elem ) ) {
			return box;
		}

		// If we don't have gBCR, just use 0,0 rather than error
		// BlackBerry 5, iOS 3 (original iPhone)
		if ( typeof elem.getBoundingClientRect !== "undefined" ) {
			box = elem.getBoundingClientRect();
		}
		win = getWindow( doc );
		return {
			top: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),
			left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
		};
	},

	position: function() {
		if ( !this[ 0 ] ) {
			return;
		}

		var offsetParent, offset,
			parentOffset = { top: 0, left: 0 },
			elem = this[ 0 ];

		// Fixed elements are offset from window (parentOffset = {top:0, left: 0},
		// because it is its only offset parent
		if ( jQuery.css( elem, "position" ) === "fixed" ) {

			// we assume that getBoundingClientRect is available when computed position is fixed
			offset = elem.getBoundingClientRect();
		} else {

			// Get *real* offsetParent
			offsetParent = this.offsetParent();

			// Get correct offsets
			offset = this.offset();
			if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
				parentOffset = offsetParent.offset();
			}

			// Add offsetParent borders
			parentOffset.top  += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
			parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
		}

		// Subtract parent offsets and element margins
		// note: when an element has margin: auto the offsetLeft and marginLeft
		// are the same in Safari causing offset.left to incorrectly be 0
		return {
			top:  offset.top  - parentOffset.top - jQuery.css( elem, "marginTop", true ),
			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
		};
	},

	offsetParent: function() {
		return this.map( function() {
			var offsetParent = this.offsetParent;

			while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) &&
				jQuery.css( offsetParent, "position" ) === "static" ) ) {
				offsetParent = offsetParent.offsetParent;
			}
			return offsetParent || documentElement;
		} );
	}
} );

// Create scrollLeft and scrollTop methods
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
	var top = /Y/.test( prop );

	jQuery.fn[ method ] = function( val ) {
		return access( this, function( elem, method, val ) {
			var win = getWindow( elem );

			if ( val === undefined ) {
				return win ? ( prop in win ) ? win[ prop ] :
					win.document.documentElement[ method ] :
					elem[ method ];
			}

			if ( win ) {
				win.scrollTo(
					!top ? val : jQuery( win ).scrollLeft(),
					top ? val : jQuery( win ).scrollTop()
				);

			} else {
				elem[ method ] = val;
			}
		}, method, val, arguments.length, null );
	};
} );

// Support: Safari<7-8+, Chrome<37-44+
// Add the top/left cssHooks using jQuery.fn.position
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
// getComputedStyle returns percent when specified for top/left/bottom/right
// rather than make the css module depend on the offset module, we just check for it here
jQuery.each( [ "top", "left" ], function( i, prop ) {
	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
		function( elem, computed ) {
			if ( computed ) {
				computed = curCSS( elem, prop );

				// if curCSS returns percentage, fallback to offset
				return rnumnonpx.test( computed ) ?
					jQuery( elem ).position()[ prop ] + "px" :
					computed;
			}
		}
	);
} );


// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
	function( defaultExtra, funcName ) {

		// margin is only for outerHeight, outerWidth
		jQuery.fn[ funcName ] = function( margin, value ) {
			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );

			return access( this, function( elem, type, value ) {
				var doc;

				if ( jQuery.isWindow( elem ) ) {

					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
					// isn't a whole lot we can do. See pull request at this URL for discussion:
					// https://github.com/jquery/jquery/pull/764
					return elem.document.documentElement[ "client" + name ];
				}

				// Get document width or height
				if ( elem.nodeType === 9 ) {
					doc = elem.documentElement;

					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
					// whichever is greatest
					// unfortunately, this causes bug #3838 in IE6/8 only,
					// but there is currently no good, small way to fix it.
					return Math.max(
						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
						elem.body[ "offset" + name ], doc[ "offset" + name ],
						doc[ "client" + name ]
					);
				}

				return value === undefined ?

					// Get width or height on the element, requesting but not forcing parseFloat
					jQuery.css( elem, type, extra ) :

					// Set width or height on the element
					jQuery.style( elem, type, value, extra );
			}, type, chainable ? margin : undefined, chainable, null );
		};
	} );
} );


jQuery.fn.extend( {

	bind: function( types, data, fn ) {
		return this.on( types, null, data, fn );
	},
	unbind: function( types, fn ) {
		return this.off( types, null, fn );
	},

	delegate: function( selector, types, data, fn ) {
		return this.on( types, selector, data, fn );
	},
	undelegate: function( selector, types, fn ) {

		// ( namespace ) or ( selector, types [, fn] )
		return arguments.length === 1 ?
			this.off( selector, "**" ) :
			this.off( types, selector || "**", fn );
	}
} );

// The number of elements contained in the matched element set
jQuery.fn.size = function() {
	return this.length;
};

jQuery.fn.andSelf = jQuery.fn.addBack;




// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.

// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon

if ( typeof define === "function" && define.amd ) {
	define( "jquery", [], function() {
		return jQuery;
	} );
}



var

	// Map over jQuery in case of overwrite
	_jQuery = window.jQuery,

	// Map over the $ in case of overwrite
	_$ = window.$;

jQuery.noConflict = function( deep ) {
	if ( window.$ === jQuery ) {
		window.$ = _$;
	}

	if ( deep && window.jQuery === jQuery ) {
		window.jQuery = _jQuery;
	}

	return jQuery;
};

// Expose jQuery and $ identifiers, even in
// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
// and CommonJS for browser emulators (#13566)
if ( !noGlobal ) {
	window.jQuery = window.$ = jQuery;
}

return jQuery;
}));
;/*! jQuery UI - v1.12.1 - 2016-09-14
* http://jqueryui.com
* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
* Copyright jQuery Foundation and other contributors; Licensed MIT */

(function( factory ) {
	if ( typeof define === "function" && define.amd ) {

		// AMD. Register as an anonymous module.
		define([ "jquery" ], factory );
	} else {

		// Browser globals
		factory( jQuery );
	}
}(function( $ ) {

$.ui = $.ui || {};

var version = $.ui.version = "1.12.1";


/*!
 * jQuery UI Widget 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Widget
//>>group: Core
//>>description: Provides a factory for creating stateful widgets with a common API.
//>>docs: http://api.jqueryui.com/jQuery.widget/
//>>demos: http://jqueryui.com/widget/



var widgetUuid = 0;
var widgetSlice = Array.prototype.slice;

$.cleanData = ( function( orig ) {
	return function( elems ) {
		var events, elem, i;
		for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
			try {

				// Only trigger remove when necessary to save time
				events = $._data( elem, "events" );
				if ( events && events.remove ) {
					$( elem ).triggerHandler( "remove" );
				}

			// Http://bugs.jquery.com/ticket/8235
			} catch ( e ) {}
		}
		orig( elems );
	};
} )( $.cleanData );

$.widget = function( name, base, prototype ) {
	var existingConstructor, constructor, basePrototype;

	// ProxiedPrototype allows the provided prototype to remain unmodified
	// so that it can be used as a mixin for multiple widgets (#8876)
	var proxiedPrototype = {};

	var namespace = name.split( "." )[ 0 ];
	name = name.split( "." )[ 1 ];
	var fullName = namespace + "-" + name;

	if ( !prototype ) {
		prototype = base;
		base = $.Widget;
	}

	if ( $.isArray( prototype ) ) {
		prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
	}

	// Create selector for plugin
	$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
		return !!$.data( elem, fullName );
	};

	$[ namespace ] = $[ namespace ] || {};
	existingConstructor = $[ namespace ][ name ];
	constructor = $[ namespace ][ name ] = function( options, element ) {

		// Allow instantiation without "new" keyword
		if ( !this._createWidget ) {
			return new constructor( options, element );
		}

		// Allow instantiation without initializing for simple inheritance
		// must use "new" keyword (the code above always passes args)
		if ( arguments.length ) {
			this._createWidget( options, element );
		}
	};

	// Extend with the existing constructor to carry over any static properties
	$.extend( constructor, existingConstructor, {
		version: prototype.version,

		// Copy the object used to create the prototype in case we need to
		// redefine the widget later
		_proto: $.extend( {}, prototype ),

		// Track widgets that inherit from this widget in case this widget is
		// redefined after a widget inherits from it
		_childConstructors: []
	} );

	basePrototype = new base();

	// We need to make the options hash a property directly on the new instance
	// otherwise we'll modify the options hash on the prototype that we're
	// inheriting from
	basePrototype.options = $.widget.extend( {}, basePrototype.options );
	$.each( prototype, function( prop, value ) {
		if ( !$.isFunction( value ) ) {
			proxiedPrototype[ prop ] = value;
			return;
		}
		proxiedPrototype[ prop ] = ( function() {
			function _super() {
				return base.prototype[ prop ].apply( this, arguments );
			}

			function _superApply( args ) {
				return base.prototype[ prop ].apply( this, args );
			}

			return function() {
				var __super = this._super;
				var __superApply = this._superApply;
				var returnValue;

				this._super = _super;
				this._superApply = _superApply;

				returnValue = value.apply( this, arguments );

				this._super = __super;
				this._superApply = __superApply;

				return returnValue;
			};
		} )();
	} );
	constructor.prototype = $.widget.extend( basePrototype, {

		// TODO: remove support for widgetEventPrefix
		// always use the name + a colon as the prefix, e.g., draggable:start
		// don't prefix for widgets that aren't DOM-based
		widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
	}, proxiedPrototype, {
		constructor: constructor,
		namespace: namespace,
		widgetName: name,
		widgetFullName: fullName
	} );

	// If this widget is being redefined then we need to find all widgets that
	// are inheriting from it and redefine all of them so that they inherit from
	// the new version of this widget. We're essentially trying to replace one
	// level in the prototype chain.
	if ( existingConstructor ) {
		$.each( existingConstructor._childConstructors, function( i, child ) {
			var childPrototype = child.prototype;

			// Redefine the child widget using the same prototype that was
			// originally used, but inherit from the new version of the base
			$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
				child._proto );
		} );

		// Remove the list of existing child constructors from the old constructor
		// so the old child constructors can be garbage collected
		delete existingConstructor._childConstructors;
	} else {
		base._childConstructors.push( constructor );
	}

	$.widget.bridge( name, constructor );

	return constructor;
};

$.widget.extend = function( target ) {
	var input = widgetSlice.call( arguments, 1 );
	var inputIndex = 0;
	var inputLength = input.length;
	var key;
	var value;

	for ( ; inputIndex < inputLength; inputIndex++ ) {
		for ( key in input[ inputIndex ] ) {
			value = input[ inputIndex ][ key ];
			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {

				// Clone objects
				if ( $.isPlainObject( value ) ) {
					target[ key ] = $.isPlainObject( target[ key ] ) ?
						$.widget.extend( {}, target[ key ], value ) :

						// Don't extend strings, arrays, etc. with objects
						$.widget.extend( {}, value );

				// Copy everything else by reference
				} else {
					target[ key ] = value;
				}
			}
		}
	}
	return target;
};

$.widget.bridge = function( name, object ) {
	var fullName = object.prototype.widgetFullName || name;
	$.fn[ name ] = function( options ) {
		var isMethodCall = typeof options === "string";
		var args = widgetSlice.call( arguments, 1 );
		var returnValue = this;

		if ( isMethodCall ) {

			// If this is an empty collection, we need to have the instance method
			// return undefined instead of the jQuery instance
			if ( !this.length && options === "instance" ) {
				returnValue = undefined;
			} else {
				this.each( function() {
					var methodValue;
					var instance = $.data( this, fullName );

					if ( options === "instance" ) {
						returnValue = instance;
						return false;
					}

					if ( !instance ) {
						return $.error( "cannot call methods on " + name +
							" prior to initialization; " +
							"attempted to call method '" + options + "'" );
					}

					if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
						return $.error( "no such method '" + options + "' for " + name +
							" widget instance" );
					}

					methodValue = instance[ options ].apply( instance, args );

					if ( methodValue !== instance && methodValue !== undefined ) {
						returnValue = methodValue && methodValue.jquery ?
							returnValue.pushStack( methodValue.get() ) :
							methodValue;
						return false;
					}
				} );
			}
		} else {

			// Allow multiple hashes to be passed on init
			if ( args.length ) {
				options = $.widget.extend.apply( null, [ options ].concat( args ) );
			}

			this.each( function() {
				var instance = $.data( this, fullName );
				if ( instance ) {
					instance.option( options || {} );
					if ( instance._init ) {
						instance._init();
					}
				} else {
					$.data( this, fullName, new object( options, this ) );
				}
			} );
		}

		return returnValue;
	};
};

$.Widget = function( /* options, element */ ) {};
$.Widget._childConstructors = [];

$.Widget.prototype = {
	widgetName: "widget",
	widgetEventPrefix: "",
	defaultElement: "<div>",

	options: {
		classes: {},
		disabled: false,

		// Callbacks
		create: null
	},

	_createWidget: function( options, element ) {
		element = $( element || this.defaultElement || this )[ 0 ];
		this.element = $( element );
		this.uuid = widgetUuid++;
		this.eventNamespace = "." + this.widgetName + this.uuid;

		this.bindings = $();
		this.hoverable = $();
		this.focusable = $();
		this.classesElementLookup = {};

		if ( element !== this ) {
			$.data( element, this.widgetFullName, this );
			this._on( true, this.element, {
				remove: function( event ) {
					if ( event.target === element ) {
						this.destroy();
					}
				}
			} );
			this.document = $( element.style ?

				// Element within the document
				element.ownerDocument :

				// Element is window or document
				element.document || element );
			this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
		}

		this.options = $.widget.extend( {},
			this.options,
			this._getCreateOptions(),
			options );

		this._create();

		if ( this.options.disabled ) {
			this._setOptionDisabled( this.options.disabled );
		}

		this._trigger( "create", null, this._getCreateEventData() );
		this._init();
	},

	_getCreateOptions: function() {
		return {};
	},

	_getCreateEventData: $.noop,

	_create: $.noop,

	_init: $.noop,

	destroy: function() {
		var that = this;

		this._destroy();
		$.each( this.classesElementLookup, function( key, value ) {
			that._removeClass( value, key );
		} );

		// We can probably remove the unbind calls in 2.0
		// all event bindings should go through this._on()
		this.element
			.off( this.eventNamespace )
			.removeData( this.widgetFullName );
		this.widget()
			.off( this.eventNamespace )
			.removeAttr( "aria-disabled" );

		// Clean up events and states
		this.bindings.off( this.eventNamespace );
	},

	_destroy: $.noop,

	widget: function() {
		return this.element;
	},

	option: function( key, value ) {
		var options = key;
		var parts;
		var curOption;
		var i;

		if ( arguments.length === 0 ) {

			// Don't return a reference to the internal hash
			return $.widget.extend( {}, this.options );
		}

		if ( typeof key === "string" ) {

			// Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
			options = {};
			parts = key.split( "." );
			key = parts.shift();
			if ( parts.length ) {
				curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
				for ( i = 0; i < parts.length - 1; i++ ) {
					curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
					curOption = curOption[ parts[ i ] ];
				}
				key = parts.pop();
				if ( arguments.length === 1 ) {
					return curOption[ key ] === undefined ? null : curOption[ key ];
				}
				curOption[ key ] = value;
			} else {
				if ( arguments.length === 1 ) {
					return this.options[ key ] === undefined ? null : this.options[ key ];
				}
				options[ key ] = value;
			}
		}

		this._setOptions( options );

		return this;
	},

	_setOptions: function( options ) {
		var key;

		for ( key in options ) {
			this._setOption( key, options[ key ] );
		}

		return this;
	},

	_setOption: function( key, value ) {
		if ( key === "classes" ) {
			this._setOptionClasses( value );
		}

		this.options[ key ] = value;

		if ( key === "disabled" ) {
			this._setOptionDisabled( value );
		}

		return this;
	},

	_setOptionClasses: function( value ) {
		var classKey, elements, currentElements;

		for ( classKey in value ) {
			currentElements = this.classesElementLookup[ classKey ];
			if ( value[ classKey ] === this.options.classes[ classKey ] ||
					!currentElements ||
					!currentElements.length ) {
				continue;
			}

			// We are doing this to create a new jQuery object because the _removeClass() call
			// on the next line is going to destroy the reference to the current elements being
			// tracked. We need to save a copy of this collection so that we can add the new classes
			// below.
			elements = $( currentElements.get() );
			this._removeClass( currentElements, classKey );

			// We don't use _addClass() here, because that uses this.options.classes
			// for generating the string of classes. We want to use the value passed in from
			// _setOption(), this is the new value of the classes option which was passed to
			// _setOption(). We pass this value directly to _classes().
			elements.addClass( this._classes( {
				element: elements,
				keys: classKey,
				classes: value,
				add: true
			} ) );
		}
	},

	_setOptionDisabled: function( value ) {
		this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );

		// If the widget is becoming disabled, then nothing is interactive
		if ( value ) {
			this._removeClass( this.hoverable, null, "ui-state-hover" );
			this._removeClass( this.focusable, null, "ui-state-focus" );
		}
	},

	enable: function() {
		return this._setOptions( { disabled: false } );
	},

	disable: function() {
		return this._setOptions( { disabled: true } );
	},

	_classes: function( options ) {
		var full = [];
		var that = this;

		options = $.extend( {
			element: this.element,
			classes: this.options.classes || {}
		}, options );

		function processClassString( classes, checkOption ) {
			var current, i;
			for ( i = 0; i < classes.length; i++ ) {
				current = that.classesElementLookup[ classes[ i ] ] || $();
				if ( options.add ) {
					current = $( $.unique( current.get().concat( options.element.get() ) ) );
				} else {
					current = $( current.not( options.element ).get() );
				}
				that.classesElementLookup[ classes[ i ] ] = current;
				full.push( classes[ i ] );
				if ( checkOption && options.classes[ classes[ i ] ] ) {
					full.push( options.classes[ classes[ i ] ] );
				}
			}
		}

		this._on( options.element, {
			"remove": "_untrackClassesElement"
		} );

		if ( options.keys ) {
			processClassString( options.keys.match( /\S+/g ) || [], true );
		}
		if ( options.extra ) {
			processClassString( options.extra.match( /\S+/g ) || [] );
		}

		return full.join( " " );
	},

	_untrackClassesElement: function( event ) {
		var that = this;
		$.each( that.classesElementLookup, function( key, value ) {
			if ( $.inArray( event.target, value ) !== -1 ) {
				that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
			}
		} );
	},

	_removeClass: function( element, keys, extra ) {
		return this._toggleClass( element, keys, extra, false );
	},

	_addClass: function( element, keys, extra ) {
		return this._toggleClass( element, keys, extra, true );
	},

	_toggleClass: function( element, keys, extra, add ) {
		add = ( typeof add === "boolean" ) ? add : extra;
		var shift = ( typeof element === "string" || element === null ),
			options = {
				extra: shift ? keys : extra,
				keys: shift ? element : keys,
				element: shift ? this.element : element,
				add: add
			};
		options.element.toggleClass( this._classes( options ), add );
		return this;
	},

	_on: function( suppressDisabledCheck, element, handlers ) {
		var delegateElement;
		var instance = this;

		// No suppressDisabledCheck flag, shuffle arguments
		if ( typeof suppressDisabledCheck !== "boolean" ) {
			handlers = element;
			element = suppressDisabledCheck;
			suppressDisabledCheck = false;
		}

		// No element argument, shuffle and use this.element
		if ( !handlers ) {
			handlers = element;
			element = this.element;
			delegateElement = this.widget();
		} else {
			element = delegateElement = $( element );
			this.bindings = this.bindings.add( element );
		}

		$.each( handlers, function( event, handler ) {
			function handlerProxy() {

				// Allow widgets to customize the disabled handling
				// - disabled as an array instead of boolean
				// - disabled class as method for disabling individual parts
				if ( !suppressDisabledCheck &&
						( instance.options.disabled === true ||
						$( this ).hasClass( "ui-state-disabled" ) ) ) {
					return;
				}
				return ( typeof handler === "string" ? instance[ handler ] : handler )
					.apply( instance, arguments );
			}

			// Copy the guid so direct unbinding works
			if ( typeof handler !== "string" ) {
				handlerProxy.guid = handler.guid =
					handler.guid || handlerProxy.guid || $.guid++;
			}

			var match = event.match( /^([\w:-]*)\s*(.*)$/ );
			var eventName = match[ 1 ] + instance.eventNamespace;
			var selector = match[ 2 ];

			if ( selector ) {
				delegateElement.on( eventName, selector, handlerProxy );
			} else {
				element.on( eventName, handlerProxy );
			}
		} );
	},

	_off: function( element, eventName ) {
		eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
			this.eventNamespace;
		element.off( eventName ).off( eventName );

		// Clear the stack to avoid memory leaks (#10056)
		this.bindings = $( this.bindings.not( element ).get() );
		this.focusable = $( this.focusable.not( element ).get() );
		this.hoverable = $( this.hoverable.not( element ).get() );
	},

	_delay: function( handler, delay ) {
		function handlerProxy() {
			return ( typeof handler === "string" ? instance[ handler ] : handler )
				.apply( instance, arguments );
		}
		var instance = this;
		return setTimeout( handlerProxy, delay || 0 );
	},

	_hoverable: function( element ) {
		this.hoverable = this.hoverable.add( element );
		this._on( element, {
			mouseenter: function( event ) {
				this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
			},
			mouseleave: function( event ) {
				this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
			}
		} );
	},

	_focusable: function( element ) {
		this.focusable = this.focusable.add( element );
		this._on( element, {
			focusin: function( event ) {
				this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
			},
			focusout: function( event ) {
				this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
			}
		} );
	},

	_trigger: function( type, event, data ) {
		var prop, orig;
		var callback = this.options[ type ];

		data = data || {};
		event = $.Event( event );
		event.type = ( type === this.widgetEventPrefix ?
			type :
			this.widgetEventPrefix + type ).toLowerCase();

		// The original event may come from any element
		// so we need to reset the target on the new event
		event.target = this.element[ 0 ];

		// Copy original event properties over to the new event
		orig = event.originalEvent;
		if ( orig ) {
			for ( prop in orig ) {
				if ( !( prop in event ) ) {
					event[ prop ] = orig[ prop ];
				}
			}
		}

		this.element.trigger( event, data );
		return !( $.isFunction( callback ) &&
			callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
			event.isDefaultPrevented() );
	}
};

$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
	$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
		if ( typeof options === "string" ) {
			options = { effect: options };
		}

		var hasOptions;
		var effectName = !options ?
			method :
			options === true || typeof options === "number" ?
				defaultEffect :
				options.effect || defaultEffect;

		options = options || {};
		if ( typeof options === "number" ) {
			options = { duration: options };
		}

		hasOptions = !$.isEmptyObject( options );
		options.complete = callback;

		if ( options.delay ) {
			element.delay( options.delay );
		}

		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
			element[ method ]( options );
		} else if ( effectName !== method && element[ effectName ] ) {
			element[ effectName ]( options.duration, options.easing, callback );
		} else {
			element.queue( function( next ) {
				$( this )[ method ]();
				if ( callback ) {
					callback.call( element[ 0 ] );
				}
				next();
			} );
		}
	};
} );

var widget = $.widget;


/*!
 * jQuery UI Position 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/position/
 */

//>>label: Position
//>>group: Core
//>>description: Positions elements relative to other elements.
//>>docs: http://api.jqueryui.com/position/
//>>demos: http://jqueryui.com/position/


( function() {
var cachedScrollbarWidth,
	max = Math.max,
	abs = Math.abs,
	rhorizontal = /left|center|right/,
	rvertical = /top|center|bottom/,
	roffset = /[\+\-]\d+(\.[\d]+)?%?/,
	rposition = /^\w+/,
	rpercent = /%$/,
	_position = $.fn.position;

function getOffsets( offsets, width, height ) {
	return [
		parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
		parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
	];
}

function parseCss( element, property ) {
	return parseInt( $.css( element, property ), 10 ) || 0;
}

function getDimensions( elem ) {
	var raw = elem[ 0 ];
	if ( raw.nodeType === 9 ) {
		return {
			width: elem.width(),
			height: elem.height(),
			offset: { top: 0, left: 0 }
		};
	}
	if ( $.isWindow( raw ) ) {
		return {
			width: elem.width(),
			height: elem.height(),
			offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
		};
	}
	if ( raw.preventDefault ) {
		return {
			width: 0,
			height: 0,
			offset: { top: raw.pageY, left: raw.pageX }
		};
	}
	return {
		width: elem.outerWidth(),
		height: elem.outerHeight(),
		offset: elem.offset()
	};
}

$.position = {
	scrollbarWidth: function() {
		if ( cachedScrollbarWidth !== undefined ) {
			return cachedScrollbarWidth;
		}
		var w1, w2,
			div = $( "<div " +
				"style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
				"<div style='height:100px;width:auto;'></div></div>" ),
			innerDiv = div.children()[ 0 ];

		$( "body" ).append( div );
		w1 = innerDiv.offsetWidth;
		div.css( "overflow", "scroll" );

		w2 = innerDiv.offsetWidth;

		if ( w1 === w2 ) {
			w2 = div[ 0 ].clientWidth;
		}

		div.remove();

		return ( cachedScrollbarWidth = w1 - w2 );
	},
	getScrollInfo: function( within ) {
		var overflowX = within.isWindow || within.isDocument ? "" :
				within.element.css( "overflow-x" ),
			overflowY = within.isWindow || within.isDocument ? "" :
				within.element.css( "overflow-y" ),
			hasOverflowX = overflowX === "scroll" ||
				( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
			hasOverflowY = overflowY === "scroll" ||
				( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
		return {
			width: hasOverflowY ? $.position.scrollbarWidth() : 0,
			height: hasOverflowX ? $.position.scrollbarWidth() : 0
		};
	},
	getWithinInfo: function( element ) {
		var withinElement = $( element || window ),
			isWindow = $.isWindow( withinElement[ 0 ] ),
			isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
			hasOffset = !isWindow && !isDocument;
		return {
			element: withinElement,
			isWindow: isWindow,
			isDocument: isDocument,
			offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
			scrollLeft: withinElement.scrollLeft(),
			scrollTop: withinElement.scrollTop(),
			width: withinElement.outerWidth(),
			height: withinElement.outerHeight()
		};
	}
};

$.fn.position = function( options ) {
	if ( !options || !options.of ) {
		return _position.apply( this, arguments );
	}

	// Make a copy, we don't want to modify arguments
	options = $.extend( {}, options );

	var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
		target = $( options.of ),
		within = $.position.getWithinInfo( options.within ),
		scrollInfo = $.position.getScrollInfo( within ),
		collision = ( options.collision || "flip" ).split( " " ),
		offsets = {};

	dimensions = getDimensions( target );
	if ( target[ 0 ].preventDefault ) {

		// Force left top to allow flipping
		options.at = "left top";
	}
	targetWidth = dimensions.width;
	targetHeight = dimensions.height;
	targetOffset = dimensions.offset;

	// Clone to reuse original targetOffset later
	basePosition = $.extend( {}, targetOffset );

	// Force my and at to have valid horizontal and vertical positions
	// if a value is missing or invalid, it will be converted to center
	$.each( [ "my", "at" ], function() {
		var pos = ( options[ this ] || "" ).split( " " ),
			horizontalOffset,
			verticalOffset;

		if ( pos.length === 1 ) {
			pos = rhorizontal.test( pos[ 0 ] ) ?
				pos.concat( [ "center" ] ) :
				rvertical.test( pos[ 0 ] ) ?
					[ "center" ].concat( pos ) :
					[ "center", "center" ];
		}
		pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
		pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";

		// Calculate offsets
		horizontalOffset = roffset.exec( pos[ 0 ] );
		verticalOffset = roffset.exec( pos[ 1 ] );
		offsets[ this ] = [
			horizontalOffset ? horizontalOffset[ 0 ] : 0,
			verticalOffset ? verticalOffset[ 0 ] : 0
		];

		// Reduce to just the positions without the offsets
		options[ this ] = [
			rposition.exec( pos[ 0 ] )[ 0 ],
			rposition.exec( pos[ 1 ] )[ 0 ]
		];
	} );

	// Normalize collision option
	if ( collision.length === 1 ) {
		collision[ 1 ] = collision[ 0 ];
	}

	if ( options.at[ 0 ] === "right" ) {
		basePosition.left += targetWidth;
	} else if ( options.at[ 0 ] === "center" ) {
		basePosition.left += targetWidth / 2;
	}

	if ( options.at[ 1 ] === "bottom" ) {
		basePosition.top += targetHeight;
	} else if ( options.at[ 1 ] === "center" ) {
		basePosition.top += targetHeight / 2;
	}

	atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
	basePosition.left += atOffset[ 0 ];
	basePosition.top += atOffset[ 1 ];

	return this.each( function() {
		var collisionPosition, using,
			elem = $( this ),
			elemWidth = elem.outerWidth(),
			elemHeight = elem.outerHeight(),
			marginLeft = parseCss( this, "marginLeft" ),
			marginTop = parseCss( this, "marginTop" ),
			collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
				scrollInfo.width,
			collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
				scrollInfo.height,
			position = $.extend( {}, basePosition ),
			myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );

		if ( options.my[ 0 ] === "right" ) {
			position.left -= elemWidth;
		} else if ( options.my[ 0 ] === "center" ) {
			position.left -= elemWidth / 2;
		}

		if ( options.my[ 1 ] === "bottom" ) {
			position.top -= elemHeight;
		} else if ( options.my[ 1 ] === "center" ) {
			position.top -= elemHeight / 2;
		}

		position.left += myOffset[ 0 ];
		position.top += myOffset[ 1 ];

		collisionPosition = {
			marginLeft: marginLeft,
			marginTop: marginTop
		};

		$.each( [ "left", "top" ], function( i, dir ) {
			if ( $.ui.position[ collision[ i ] ] ) {
				$.ui.position[ collision[ i ] ][ dir ]( position, {
					targetWidth: targetWidth,
					targetHeight: targetHeight,
					elemWidth: elemWidth,
					elemHeight: elemHeight,
					collisionPosition: collisionPosition,
					collisionWidth: collisionWidth,
					collisionHeight: collisionHeight,
					offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
					my: options.my,
					at: options.at,
					within: within,
					elem: elem
				} );
			}
		} );

		if ( options.using ) {

			// Adds feedback as second argument to using callback, if present
			using = function( props ) {
				var left = targetOffset.left - position.left,
					right = left + targetWidth - elemWidth,
					top = targetOffset.top - position.top,
					bottom = top + targetHeight - elemHeight,
					feedback = {
						target: {
							element: target,
							left: targetOffset.left,
							top: targetOffset.top,
							width: targetWidth,
							height: targetHeight
						},
						element: {
							element: elem,
							left: position.left,
							top: position.top,
							width: elemWidth,
							height: elemHeight
						},
						horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
						vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
					};
				if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
					feedback.horizontal = "center";
				}
				if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
					feedback.vertical = "middle";
				}
				if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
					feedback.important = "horizontal";
				} else {
					feedback.important = "vertical";
				}
				options.using.call( this, props, feedback );
			};
		}

		elem.offset( $.extend( position, { using: using } ) );
	} );
};

$.ui.position = {
	fit: {
		left: function( position, data ) {
			var within = data.within,
				withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
				outerWidth = within.width,
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
				overLeft = withinOffset - collisionPosLeft,
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
				newOverRight;

			// Element is wider than within
			if ( data.collisionWidth > outerWidth ) {

				// Element is initially over the left side of within
				if ( overLeft > 0 && overRight <= 0 ) {
					newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
						withinOffset;
					position.left += overLeft - newOverRight;

				// Element is initially over right side of within
				} else if ( overRight > 0 && overLeft <= 0 ) {
					position.left = withinOffset;

				// Element is initially over both left and right sides of within
				} else {
					if ( overLeft > overRight ) {
						position.left = withinOffset + outerWidth - data.collisionWidth;
					} else {
						position.left = withinOffset;
					}
				}

			// Too far left -> align with left edge
			} else if ( overLeft > 0 ) {
				position.left += overLeft;

			// Too far right -> align with right edge
			} else if ( overRight > 0 ) {
				position.left -= overRight;

			// Adjust based on position and margin
			} else {
				position.left = max( position.left - collisionPosLeft, position.left );
			}
		},
		top: function( position, data ) {
			var within = data.within,
				withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
				outerHeight = data.within.height,
				collisionPosTop = position.top - data.collisionPosition.marginTop,
				overTop = withinOffset - collisionPosTop,
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
				newOverBottom;

			// Element is taller than within
			if ( data.collisionHeight > outerHeight ) {

				// Element is initially over the top of within
				if ( overTop > 0 && overBottom <= 0 ) {
					newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
						withinOffset;
					position.top += overTop - newOverBottom;

				// Element is initially over bottom of within
				} else if ( overBottom > 0 && overTop <= 0 ) {
					position.top = withinOffset;

				// Element is initially over both top and bottom of within
				} else {
					if ( overTop > overBottom ) {
						position.top = withinOffset + outerHeight - data.collisionHeight;
					} else {
						position.top = withinOffset;
					}
				}

			// Too far up -> align with top
			} else if ( overTop > 0 ) {
				position.top += overTop;

			// Too far down -> align with bottom edge
			} else if ( overBottom > 0 ) {
				position.top -= overBottom;

			// Adjust based on position and margin
			} else {
				position.top = max( position.top - collisionPosTop, position.top );
			}
		}
	},
	flip: {
		left: function( position, data ) {
			var within = data.within,
				withinOffset = within.offset.left + within.scrollLeft,
				outerWidth = within.width,
				offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
				overLeft = collisionPosLeft - offsetLeft,
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
				myOffset = data.my[ 0 ] === "left" ?
					-data.elemWidth :
					data.my[ 0 ] === "right" ?
						data.elemWidth :
						0,
				atOffset = data.at[ 0 ] === "left" ?
					data.targetWidth :
					data.at[ 0 ] === "right" ?
						-data.targetWidth :
						0,
				offset = -2 * data.offset[ 0 ],
				newOverRight,
				newOverLeft;

			if ( overLeft < 0 ) {
				newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
					outerWidth - withinOffset;
				if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
					position.left += myOffset + atOffset + offset;
				}
			} else if ( overRight > 0 ) {
				newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
					atOffset + offset - offsetLeft;
				if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
					position.left += myOffset + atOffset + offset;
				}
			}
		},
		top: function( position, data ) {
			var within = data.within,
				withinOffset = within.offset.top + within.scrollTop,
				outerHeight = within.height,
				offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
				collisionPosTop = position.top - data.collisionPosition.marginTop,
				overTop = collisionPosTop - offsetTop,
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
				top = data.my[ 1 ] === "top",
				myOffset = top ?
					-data.elemHeight :
					data.my[ 1 ] === "bottom" ?
						data.elemHeight :
						0,
				atOffset = data.at[ 1 ] === "top" ?
					data.targetHeight :
					data.at[ 1 ] === "bottom" ?
						-data.targetHeight :
						0,
				offset = -2 * data.offset[ 1 ],
				newOverTop,
				newOverBottom;
			if ( overTop < 0 ) {
				newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
					outerHeight - withinOffset;
				if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
					position.top += myOffset + atOffset + offset;
				}
			} else if ( overBottom > 0 ) {
				newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
					offset - offsetTop;
				if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
					position.top += myOffset + atOffset + offset;
				}
			}
		}
	},
	flipfit: {
		left: function() {
			$.ui.position.flip.left.apply( this, arguments );
			$.ui.position.fit.left.apply( this, arguments );
		},
		top: function() {
			$.ui.position.flip.top.apply( this, arguments );
			$.ui.position.fit.top.apply( this, arguments );
		}
	}
};

} )();

var position = $.ui.position;


/*!
 * jQuery UI :data 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: :data Selector
//>>group: Core
//>>description: Selects elements which have data stored under the specified key.
//>>docs: http://api.jqueryui.com/data-selector/


var data = $.extend( $.expr[ ":" ], {
	data: $.expr.createPseudo ?
		$.expr.createPseudo( function( dataName ) {
			return function( elem ) {
				return !!$.data( elem, dataName );
			};
		} ) :

		// Support: jQuery <1.8
		function( elem, i, match ) {
			return !!$.data( elem, match[ 3 ] );
		}
} );

/*!
 * jQuery UI Disable Selection 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: disableSelection
//>>group: Core
//>>description: Disable selection of text content within the set of matched elements.
//>>docs: http://api.jqueryui.com/disableSelection/

// This file is deprecated


var disableSelection = $.fn.extend( {
	disableSelection: ( function() {
		var eventType = "onselectstart" in document.createElement( "div" ) ?
			"selectstart" :
			"mousedown";

		return function() {
			return this.on( eventType + ".ui-disableSelection", function( event ) {
				event.preventDefault();
			} );
		};
	} )(),

	enableSelection: function() {
		return this.off( ".ui-disableSelection" );
	}
} );


/*!
 * jQuery UI Effects 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Effects Core
//>>group: Effects
// jscs:disable maximumLineLength
//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/category/effects-core/
//>>demos: http://jqueryui.com/effect/



var dataSpace = "ui-effects-",
	dataSpaceStyle = "ui-effects-style",
	dataSpaceAnimated = "ui-effects-animated",

	// Create a local jQuery because jQuery Color relies on it and the
	// global may not exist with AMD and a custom build (#10199)
	jQuery = $;

$.effects = {
	effect: {}
};

/*!
 * jQuery Color Animations v2.1.2
 * https://github.com/jquery/jquery-color
 *
 * Copyright 2014 jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * Date: Wed Jan 16 08:47:09 2013 -0600
 */
( function( jQuery, undefined ) {

	var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
		"borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",

	// Plusequals test for += 100 -= 100
	rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,

	// A set of RE's that can match strings and generate color tuples.
	stringParsers = [ {
			re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
			parse: function( execResult ) {
				return [
					execResult[ 1 ],
					execResult[ 2 ],
					execResult[ 3 ],
					execResult[ 4 ]
				];
			}
		}, {
			re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
			parse: function( execResult ) {
				return [
					execResult[ 1 ] * 2.55,
					execResult[ 2 ] * 2.55,
					execResult[ 3 ] * 2.55,
					execResult[ 4 ]
				];
			}
		}, {

			// This regex ignores A-F because it's compared against an already lowercased string
			re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
			parse: function( execResult ) {
				return [
					parseInt( execResult[ 1 ], 16 ),
					parseInt( execResult[ 2 ], 16 ),
					parseInt( execResult[ 3 ], 16 )
				];
			}
		}, {

			// This regex ignores A-F because it's compared against an already lowercased string
			re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
			parse: function( execResult ) {
				return [
					parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
					parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
					parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
				];
			}
		}, {
			re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
			space: "hsla",
			parse: function( execResult ) {
				return [
					execResult[ 1 ],
					execResult[ 2 ] / 100,
					execResult[ 3 ] / 100,
					execResult[ 4 ]
				];
			}
		} ],

	// JQuery.Color( )
	color = jQuery.Color = function( color, green, blue, alpha ) {
		return new jQuery.Color.fn.parse( color, green, blue, alpha );
	},
	spaces = {
		rgba: {
			props: {
				red: {
					idx: 0,
					type: "byte"
				},
				green: {
					idx: 1,
					type: "byte"
				},
				blue: {
					idx: 2,
					type: "byte"
				}
			}
		},

		hsla: {
			props: {
				hue: {
					idx: 0,
					type: "degrees"
				},
				saturation: {
					idx: 1,
					type: "percent"
				},
				lightness: {
					idx: 2,
					type: "percent"
				}
			}
		}
	},
	propTypes = {
		"byte": {
			floor: true,
			max: 255
		},
		"percent": {
			max: 1
		},
		"degrees": {
			mod: 360,
			floor: true
		}
	},
	support = color.support = {},

	// Element for support tests
	supportElem = jQuery( "<p>" )[ 0 ],

	// Colors = jQuery.Color.names
	colors,

	// Local aliases of functions called often
	each = jQuery.each;

// Determine rgba support immediately
supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;

// Define cache name and alpha properties
// for rgba and hsla spaces
each( spaces, function( spaceName, space ) {
	space.cache = "_" + spaceName;
	space.props.alpha = {
		idx: 3,
		type: "percent",
		def: 1
	};
} );

function clamp( value, prop, allowEmpty ) {
	var type = propTypes[ prop.type ] || {};

	if ( value == null ) {
		return ( allowEmpty || !prop.def ) ? null : prop.def;
	}

	// ~~ is an short way of doing floor for positive numbers
	value = type.floor ? ~~value : parseFloat( value );

	// IE will pass in empty strings as value for alpha,
	// which will hit this case
	if ( isNaN( value ) ) {
		return prop.def;
	}

	if ( type.mod ) {

		// We add mod before modding to make sure that negatives values
		// get converted properly: -10 -> 350
		return ( value + type.mod ) % type.mod;
	}

	// For now all property types without mod have min and max
	return 0 > value ? 0 : type.max < value ? type.max : value;
}

function stringParse( string ) {
	var inst = color(),
		rgba = inst._rgba = [];

	string = string.toLowerCase();

	each( stringParsers, function( i, parser ) {
		var parsed,
			match = parser.re.exec( string ),
			values = match && parser.parse( match ),
			spaceName = parser.space || "rgba";

		if ( values ) {
			parsed = inst[ spaceName ]( values );

			// If this was an rgba parse the assignment might happen twice
			// oh well....
			inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
			rgba = inst._rgba = parsed._rgba;

			// Exit each( stringParsers ) here because we matched
			return false;
		}
	} );

	// Found a stringParser that handled it
	if ( rgba.length ) {

		// If this came from a parsed string, force "transparent" when alpha is 0
		// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
		if ( rgba.join() === "0,0,0,0" ) {
			jQuery.extend( rgba, colors.transparent );
		}
		return inst;
	}

	// Named colors
	return colors[ string ];
}

color.fn = jQuery.extend( color.prototype, {
	parse: function( red, green, blue, alpha ) {
		if ( red === undefined ) {
			this._rgba = [ null, null, null, null ];
			return this;
		}
		if ( red.jquery || red.nodeType ) {
			red = jQuery( red ).css( green );
			green = undefined;
		}

		var inst = this,
			type = jQuery.type( red ),
			rgba = this._rgba = [];

		// More than 1 argument specified - assume ( red, green, blue, alpha )
		if ( green !== undefined ) {
			red = [ red, green, blue, alpha ];
			type = "array";
		}

		if ( type === "string" ) {
			return this.parse( stringParse( red ) || colors._default );
		}

		if ( type === "array" ) {
			each( spaces.rgba.props, function( key, prop ) {
				rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
			} );
			return this;
		}

		if ( type === "object" ) {
			if ( red instanceof color ) {
				each( spaces, function( spaceName, space ) {
					if ( red[ space.cache ] ) {
						inst[ space.cache ] = red[ space.cache ].slice();
					}
				} );
			} else {
				each( spaces, function( spaceName, space ) {
					var cache = space.cache;
					each( space.props, function( key, prop ) {

						// If the cache doesn't exist, and we know how to convert
						if ( !inst[ cache ] && space.to ) {

							// If the value was null, we don't need to copy it
							// if the key was alpha, we don't need to copy it either
							if ( key === "alpha" || red[ key ] == null ) {
								return;
							}
							inst[ cache ] = space.to( inst._rgba );
						}

						// This is the only case where we allow nulls for ALL properties.
						// call clamp with alwaysAllowEmpty
						inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
					} );

					// Everything defined but alpha?
					if ( inst[ cache ] &&
							jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {

						// Use the default of 1
						inst[ cache ][ 3 ] = 1;
						if ( space.from ) {
							inst._rgba = space.from( inst[ cache ] );
						}
					}
				} );
			}
			return this;
		}
	},
	is: function( compare ) {
		var is = color( compare ),
			same = true,
			inst = this;

		each( spaces, function( _, space ) {
			var localCache,
				isCache = is[ space.cache ];
			if ( isCache ) {
				localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
				each( space.props, function( _, prop ) {
					if ( isCache[ prop.idx ] != null ) {
						same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
						return same;
					}
				} );
			}
			return same;
		} );
		return same;
	},
	_space: function() {
		var used = [],
			inst = this;
		each( spaces, function( spaceName, space ) {
			if ( inst[ space.cache ] ) {
				used.push( spaceName );
			}
		} );
		return used.pop();
	},
	transition: function( other, distance ) {
		var end = color( other ),
			spaceName = end._space(),
			space = spaces[ spaceName ],
			startColor = this.alpha() === 0 ? color( "transparent" ) : this,
			start = startColor[ space.cache ] || space.to( startColor._rgba ),
			result = start.slice();

		end = end[ space.cache ];
		each( space.props, function( key, prop ) {
			var index = prop.idx,
				startValue = start[ index ],
				endValue = end[ index ],
				type = propTypes[ prop.type ] || {};

			// If null, don't override start value
			if ( endValue === null ) {
				return;
			}

			// If null - use end
			if ( startValue === null ) {
				result[ index ] = endValue;
			} else {
				if ( type.mod ) {
					if ( endValue - startValue > type.mod / 2 ) {
						startValue += type.mod;
					} else if ( startValue - endValue > type.mod / 2 ) {
						startValue -= type.mod;
					}
				}
				result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
			}
		} );
		return this[ spaceName ]( result );
	},
	blend: function( opaque ) {

		// If we are already opaque - return ourself
		if ( this._rgba[ 3 ] === 1 ) {
			return this;
		}

		var rgb = this._rgba.slice(),
			a = rgb.pop(),
			blend = color( opaque )._rgba;

		return color( jQuery.map( rgb, function( v, i ) {
			return ( 1 - a ) * blend[ i ] + a * v;
		} ) );
	},
	toRgbaString: function() {
		var prefix = "rgba(",
			rgba = jQuery.map( this._rgba, function( v, i ) {
				return v == null ? ( i > 2 ? 1 : 0 ) : v;
			} );

		if ( rgba[ 3 ] === 1 ) {
			rgba.pop();
			prefix = "rgb(";
		}

		return prefix + rgba.join() + ")";
	},
	toHslaString: function() {
		var prefix = "hsla(",
			hsla = jQuery.map( this.hsla(), function( v, i ) {
				if ( v == null ) {
					v = i > 2 ? 1 : 0;
				}

				// Catch 1 and 2
				if ( i && i < 3 ) {
					v = Math.round( v * 100 ) + "%";
				}
				return v;
			} );

		if ( hsla[ 3 ] === 1 ) {
			hsla.pop();
			prefix = "hsl(";
		}
		return prefix + hsla.join() + ")";
	},
	toHexString: function( includeAlpha ) {
		var rgba = this._rgba.slice(),
			alpha = rgba.pop();

		if ( includeAlpha ) {
			rgba.push( ~~( alpha * 255 ) );
		}

		return "#" + jQuery.map( rgba, function( v ) {

			// Default to 0 when nulls exist
			v = ( v || 0 ).toString( 16 );
			return v.length === 1 ? "0" + v : v;
		} ).join( "" );
	},
	toString: function() {
		return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
	}
} );
color.fn.parse.prototype = color.fn;

// Hsla conversions adapted from:
// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021

function hue2rgb( p, q, h ) {
	h = ( h + 1 ) % 1;
	if ( h * 6 < 1 ) {
		return p + ( q - p ) * h * 6;
	}
	if ( h * 2 < 1 ) {
		return q;
	}
	if ( h * 3 < 2 ) {
		return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
	}
	return p;
}

spaces.hsla.to = function( rgba ) {
	if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
		return [ null, null, null, rgba[ 3 ] ];
	}
	var r = rgba[ 0 ] / 255,
		g = rgba[ 1 ] / 255,
		b = rgba[ 2 ] / 255,
		a = rgba[ 3 ],
		max = Math.max( r, g, b ),
		min = Math.min( r, g, b ),
		diff = max - min,
		add = max + min,
		l = add * 0.5,
		h, s;

	if ( min === max ) {
		h = 0;
	} else if ( r === max ) {
		h = ( 60 * ( g - b ) / diff ) + 360;
	} else if ( g === max ) {
		h = ( 60 * ( b - r ) / diff ) + 120;
	} else {
		h = ( 60 * ( r - g ) / diff ) + 240;
	}

	// Chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
	// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
	if ( diff === 0 ) {
		s = 0;
	} else if ( l <= 0.5 ) {
		s = diff / add;
	} else {
		s = diff / ( 2 - add );
	}
	return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
};

spaces.hsla.from = function( hsla ) {
	if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
		return [ null, null, null, hsla[ 3 ] ];
	}
	var h = hsla[ 0 ] / 360,
		s = hsla[ 1 ],
		l = hsla[ 2 ],
		a = hsla[ 3 ],
		q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
		p = 2 * l - q;

	return [
		Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
		Math.round( hue2rgb( p, q, h ) * 255 ),
		Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
		a
	];
};

each( spaces, function( spaceName, space ) {
	var props = space.props,
		cache = space.cache,
		to = space.to,
		from = space.from;

	// Makes rgba() and hsla()
	color.fn[ spaceName ] = function( value ) {

		// Generate a cache for this space if it doesn't exist
		if ( to && !this[ cache ] ) {
			this[ cache ] = to( this._rgba );
		}
		if ( value === undefined ) {
			return this[ cache ].slice();
		}

		var ret,
			type = jQuery.type( value ),
			arr = ( type === "array" || type === "object" ) ? value : arguments,
			local = this[ cache ].slice();

		each( props, function( key, prop ) {
			var val = arr[ type === "object" ? key : prop.idx ];
			if ( val == null ) {
				val = local[ prop.idx ];
			}
			local[ prop.idx ] = clamp( val, prop );
		} );

		if ( from ) {
			ret = color( from( local ) );
			ret[ cache ] = local;
			return ret;
		} else {
			return color( local );
		}
	};

	// Makes red() green() blue() alpha() hue() saturation() lightness()
	each( props, function( key, prop ) {

		// Alpha is included in more than one space
		if ( color.fn[ key ] ) {
			return;
		}
		color.fn[ key ] = function( value ) {
			var vtype = jQuery.type( value ),
				fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
				local = this[ fn ](),
				cur = local[ prop.idx ],
				match;

			if ( vtype === "undefined" ) {
				return cur;
			}

			if ( vtype === "function" ) {
				value = value.call( this, cur );
				vtype = jQuery.type( value );
			}
			if ( value == null && prop.empty ) {
				return this;
			}
			if ( vtype === "string" ) {
				match = rplusequals.exec( value );
				if ( match ) {
					value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
				}
			}
			local[ prop.idx ] = value;
			return this[ fn ]( local );
		};
	} );
} );

// Add cssHook and .fx.step function for each named hook.
// accept a space separated string of properties
color.hook = function( hook ) {
	var hooks = hook.split( " " );
	each( hooks, function( i, hook ) {
		jQuery.cssHooks[ hook ] = {
			set: function( elem, value ) {
				var parsed, curElem,
					backgroundColor = "";

				if ( value !== "transparent" && ( jQuery.type( value ) !== "string" ||
						( parsed = stringParse( value ) ) ) ) {
					value = color( parsed || value );
					if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
						curElem = hook === "backgroundColor" ? elem.parentNode : elem;
						while (
							( backgroundColor === "" || backgroundColor === "transparent" ) &&
							curElem && curElem.style
						) {
							try {
								backgroundColor = jQuery.css( curElem, "backgroundColor" );
								curElem = curElem.parentNode;
							} catch ( e ) {
							}
						}

						value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
							backgroundColor :
							"_default" );
					}

					value = value.toRgbaString();
				}
				try {
					elem.style[ hook ] = value;
				} catch ( e ) {

					// Wrapped to prevent IE from throwing errors on "invalid" values like
					// 'auto' or 'inherit'
				}
			}
		};
		jQuery.fx.step[ hook ] = function( fx ) {
			if ( !fx.colorInit ) {
				fx.start = color( fx.elem, hook );
				fx.end = color( fx.end );
				fx.colorInit = true;
			}
			jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
		};
	} );

};

color.hook( stepHooks );

jQuery.cssHooks.borderColor = {
	expand: function( value ) {
		var expanded = {};

		each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
			expanded[ "border" + part + "Color" ] = value;
		} );
		return expanded;
	}
};

// Basic color names only.
// Usage of any of the other color names requires adding yourself or including
// jquery.color.svg-names.js.
colors = jQuery.Color.names = {

	// 4.1. Basic color keywords
	aqua: "#00ffff",
	black: "#000000",
	blue: "#0000ff",
	fuchsia: "#ff00ff",
	gray: "#808080",
	green: "#008000",
	lime: "#00ff00",
	maroon: "#800000",
	navy: "#000080",
	olive: "#808000",
	purple: "#800080",
	red: "#ff0000",
	silver: "#c0c0c0",
	teal: "#008080",
	white: "#ffffff",
	yellow: "#ffff00",

	// 4.2.3. "transparent" color keyword
	transparent: [ null, null, null, 0 ],

	_default: "#ffffff"
};

} )( jQuery );

/******************************************************************************/
/****************************** CLASS ANIMATIONS ******************************/
/******************************************************************************/
( function() {

var classAnimationActions = [ "add", "remove", "toggle" ],
	shorthandStyles = {
		border: 1,
		borderBottom: 1,
		borderColor: 1,
		borderLeft: 1,
		borderRight: 1,
		borderTop: 1,
		borderWidth: 1,
		margin: 1,
		padding: 1
	};

$.each(
	[ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
	function( _, prop ) {
		$.fx.step[ prop ] = function( fx ) {
			if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
				jQuery.style( fx.elem, prop, fx.end );
				fx.setAttr = true;
			}
		};
	}
);

function getElementStyles( elem ) {
	var key, len,
		style = elem.ownerDocument.defaultView ?
			elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
			elem.currentStyle,
		styles = {};

	if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
		len = style.length;
		while ( len-- ) {
			key = style[ len ];
			if ( typeof style[ key ] === "string" ) {
				styles[ $.camelCase( key ) ] = style[ key ];
			}
		}

	// Support: Opera, IE <9
	} else {
		for ( key in style ) {
			if ( typeof style[ key ] === "string" ) {
				styles[ key ] = style[ key ];
			}
		}
	}

	return styles;
}

function styleDifference( oldStyle, newStyle ) {
	var diff = {},
		name, value;

	for ( name in newStyle ) {
		value = newStyle[ name ];
		if ( oldStyle[ name ] !== value ) {
			if ( !shorthandStyles[ name ] ) {
				if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
					diff[ name ] = value;
				}
			}
		}
	}

	return diff;
}

// Support: jQuery <1.8
if ( !$.fn.addBack ) {
	$.fn.addBack = function( selector ) {
		return this.add( selector == null ?
			this.prevObject : this.prevObject.filter( selector )
		);
	};
}

$.effects.animateClass = function( value, duration, easing, callback ) {
	var o = $.speed( duration, easing, callback );

	return this.queue( function() {
		var animated = $( this ),
			baseClass = animated.attr( "class" ) || "",
			applyClassChange,
			allAnimations = o.children ? animated.find( "*" ).addBack() : animated;

		// Map the animated objects to store the original styles.
		allAnimations = allAnimations.map( function() {
			var el = $( this );
			return {
				el: el,
				start: getElementStyles( this )
			};
		} );

		// Apply class change
		applyClassChange = function() {
			$.each( classAnimationActions, function( i, action ) {
				if ( value[ action ] ) {
					animated[ action + "Class" ]( value[ action ] );
				}
			} );
		};
		applyClassChange();

		// Map all animated objects again - calculate new styles and diff
		allAnimations = allAnimations.map( function() {
			this.end = getElementStyles( this.el[ 0 ] );
			this.diff = styleDifference( this.start, this.end );
			return this;
		} );

		// Apply original class
		animated.attr( "class", baseClass );

		// Map all animated objects again - this time collecting a promise
		allAnimations = allAnimations.map( function() {
			var styleInfo = this,
				dfd = $.Deferred(),
				opts = $.extend( {}, o, {
					queue: false,
					complete: function() {
						dfd.resolve( styleInfo );
					}
				} );

			this.el.animate( this.diff, opts );
			return dfd.promise();
		} );

		// Once all animations have completed:
		$.when.apply( $, allAnimations.get() ).done( function() {

			// Set the final class
			applyClassChange();

			// For each animated element,
			// clear all css properties that were animated
			$.each( arguments, function() {
				var el = this.el;
				$.each( this.diff, function( key ) {
					el.css( key, "" );
				} );
			} );

			// This is guarnteed to be there if you use jQuery.speed()
			// it also handles dequeuing the next anim...
			o.complete.call( animated[ 0 ] );
		} );
	} );
};

$.fn.extend( {
	addClass: ( function( orig ) {
		return function( classNames, speed, easing, callback ) {
			return speed ?
				$.effects.animateClass.call( this,
					{ add: classNames }, speed, easing, callback ) :
				orig.apply( this, arguments );
		};
	} )( $.fn.addClass ),

	removeClass: ( function( orig ) {
		return function( classNames, speed, easing, callback ) {
			return arguments.length > 1 ?
				$.effects.animateClass.call( this,
					{ remove: classNames }, speed, easing, callback ) :
				orig.apply( this, arguments );
		};
	} )( $.fn.removeClass ),

	toggleClass: ( function( orig ) {
		return function( classNames, force, speed, easing, callback ) {
			if ( typeof force === "boolean" || force === undefined ) {
				if ( !speed ) {

					// Without speed parameter
					return orig.apply( this, arguments );
				} else {
					return $.effects.animateClass.call( this,
						( force ? { add: classNames } : { remove: classNames } ),
						speed, easing, callback );
				}
			} else {

				// Without force parameter
				return $.effects.animateClass.call( this,
					{ toggle: classNames }, force, speed, easing );
			}
		};
	} )( $.fn.toggleClass ),

	switchClass: function( remove, add, speed, easing, callback ) {
		return $.effects.animateClass.call( this, {
			add: add,
			remove: remove
		}, speed, easing, callback );
	}
} );

} )();

/******************************************************************************/
/*********************************** EFFECTS **********************************/
/******************************************************************************/

( function() {

if ( $.expr && $.expr.filters && $.expr.filters.animated ) {
	$.expr.filters.animated = ( function( orig ) {
		return function( elem ) {
			return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
		};
	} )( $.expr.filters.animated );
}

if ( $.uiBackCompat !== false ) {
	$.extend( $.effects, {

		// Saves a set of properties in a data storage
		save: function( element, set ) {
			var i = 0, length = set.length;
			for ( ; i < length; i++ ) {
				if ( set[ i ] !== null ) {
					element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
				}
			}
		},

		// Restores a set of previously saved properties from a data storage
		restore: function( element, set ) {
			var val, i = 0, length = set.length;
			for ( ; i < length; i++ ) {
				if ( set[ i ] !== null ) {
					val = element.data( dataSpace + set[ i ] );
					element.css( set[ i ], val );
				}
			}
		},

		setMode: function( el, mode ) {
			if ( mode === "toggle" ) {
				mode = el.is( ":hidden" ) ? "show" : "hide";
			}
			return mode;
		},

		// Wraps the element around a wrapper that copies position properties
		createWrapper: function( element ) {

			// If the element is already wrapped, return it
			if ( element.parent().is( ".ui-effects-wrapper" ) ) {
				return element.parent();
			}

			// Wrap the element
			var props = {
					width: element.outerWidth( true ),
					height: element.outerHeight( true ),
					"float": element.css( "float" )
				},
				wrapper = $( "<div></div>" )
					.addClass( "ui-effects-wrapper" )
					.css( {
						fontSize: "100%",
						background: "transparent",
						border: "none",
						margin: 0,
						padding: 0
					} ),

				// Store the size in case width/height are defined in % - Fixes #5245
				size = {
					width: element.width(),
					height: element.height()
				},
				active = document.activeElement;

			// Support: Firefox
			// Firefox incorrectly exposes anonymous content
			// https://bugzilla.mozilla.org/show_bug.cgi?id=561664
			try {
				active.id;
			} catch ( e ) {
				active = document.body;
			}

			element.wrap( wrapper );

			// Fixes #7595 - Elements lose focus when wrapped.
			if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
				$( active ).trigger( "focus" );
			}

			// Hotfix for jQuery 1.4 since some change in wrap() seems to actually
			// lose the reference to the wrapped element
			wrapper = element.parent();

			// Transfer positioning properties to the wrapper
			if ( element.css( "position" ) === "static" ) {
				wrapper.css( { position: "relative" } );
				element.css( { position: "relative" } );
			} else {
				$.extend( props, {
					position: element.css( "position" ),
					zIndex: element.css( "z-index" )
				} );
				$.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
					props[ pos ] = element.css( pos );
					if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
						props[ pos ] = "auto";
					}
				} );
				element.css( {
					position: "relative",
					top: 0,
					left: 0,
					right: "auto",
					bottom: "auto"
				} );
			}
			element.css( size );

			return wrapper.css( props ).show();
		},

		removeWrapper: function( element ) {
			var active = document.activeElement;

			if ( element.parent().is( ".ui-effects-wrapper" ) ) {
				element.parent().replaceWith( element );

				// Fixes #7595 - Elements lose focus when wrapped.
				if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
					$( active ).trigger( "focus" );
				}
			}

			return element;
		}
	} );
}

$.extend( $.effects, {
	version: "1.12.1",

	define: function( name, mode, effect ) {
		if ( !effect ) {
			effect = mode;
			mode = "effect";
		}

		$.effects.effect[ name ] = effect;
		$.effects.effect[ name ].mode = mode;

		return effect;
	},

	scaledDimensions: function( element, percent, direction ) {
		if ( percent === 0 ) {
			return {
				height: 0,
				width: 0,
				outerHeight: 0,
				outerWidth: 0
			};
		}

		var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
			y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;

		return {
			height: element.height() * y,
			width: element.width() * x,
			outerHeight: element.outerHeight() * y,
			outerWidth: element.outerWidth() * x
		};

	},

	clipToBox: function( animation ) {
		return {
			width: animation.clip.right - animation.clip.left,
			height: animation.clip.bottom - animation.clip.top,
			left: animation.clip.left,
			top: animation.clip.top
		};
	},

	// Injects recently queued functions to be first in line (after "inprogress")
	unshift: function( element, queueLength, count ) {
		var queue = element.queue();

		if ( queueLength > 1 ) {
			queue.splice.apply( queue,
				[ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
		}
		element.dequeue();
	},

	saveStyle: function( element ) {
		element.data( dataSpaceStyle, element[ 0 ].style.cssText );
	},

	restoreStyle: function( element ) {
		element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
		element.removeData( dataSpaceStyle );
	},

	mode: function( element, mode ) {
		var hidden = element.is( ":hidden" );

		if ( mode === "toggle" ) {
			mode = hidden ? "show" : "hide";
		}
		if ( hidden ? mode === "hide" : mode === "show" ) {
			mode = "none";
		}
		return mode;
	},

	// Translates a [top,left] array into a baseline value
	getBaseline: function( origin, original ) {
		var y, x;

		switch ( origin[ 0 ] ) {
		case "top":
			y = 0;
			break;
		case "middle":
			y = 0.5;
			break;
		case "bottom":
			y = 1;
			break;
		default:
			y = origin[ 0 ] / original.height;
		}

		switch ( origin[ 1 ] ) {
		case "left":
			x = 0;
			break;
		case "center":
			x = 0.5;
			break;
		case "right":
			x = 1;
			break;
		default:
			x = origin[ 1 ] / original.width;
		}

		return {
			x: x,
			y: y
		};
	},

	// Creates a placeholder element so that the original element can be made absolute
	createPlaceholder: function( element ) {
		var placeholder,
			cssPosition = element.css( "position" ),
			position = element.position();

		// Lock in margins first to account for form elements, which
		// will change margin if you explicitly set height
		// see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
		// Support: Safari
		element.css( {
			marginTop: element.css( "marginTop" ),
			marginBottom: element.css( "marginBottom" ),
			marginLeft: element.css( "marginLeft" ),
			marginRight: element.css( "marginRight" )
		} )
		.outerWidth( element.outerWidth() )
		.outerHeight( element.outerHeight() );

		if ( /^(static|relative)/.test( cssPosition ) ) {
			cssPosition = "absolute";

			placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {

				// Convert inline to inline block to account for inline elements
				// that turn to inline block based on content (like img)
				display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
					"inline-block" :
					"block",
				visibility: "hidden",

				// Margins need to be set to account for margin collapse
				marginTop: element.css( "marginTop" ),
				marginBottom: element.css( "marginBottom" ),
				marginLeft: element.css( "marginLeft" ),
				marginRight: element.css( "marginRight" ),
				"float": element.css( "float" )
			} )
			.outerWidth( element.outerWidth() )
			.outerHeight( element.outerHeight() )
			.addClass( "ui-effects-placeholder" );

			element.data( dataSpace + "placeholder", placeholder );
		}

		element.css( {
			position: cssPosition,
			left: position.left,
			top: position.top
		} );

		return placeholder;
	},

	removePlaceholder: function( element ) {
		var dataKey = dataSpace + "placeholder",
				placeholder = element.data( dataKey );

		if ( placeholder ) {
			placeholder.remove();
			element.removeData( dataKey );
		}
	},

	// Removes a placeholder if it exists and restores
	// properties that were modified during placeholder creation
	cleanUp: function( element ) {
		$.effects.restoreStyle( element );
		$.effects.removePlaceholder( element );
	},

	setTransition: function( element, list, factor, value ) {
		value = value || {};
		$.each( list, function( i, x ) {
			var unit = element.cssUnit( x );
			if ( unit[ 0 ] > 0 ) {
				value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
			}
		} );
		return value;
	}
} );

// Return an effect options object for the given parameters:
function _normalizeArguments( effect, options, speed, callback ) {

	// Allow passing all options as the first parameter
	if ( $.isPlainObject( effect ) ) {
		options = effect;
		effect = effect.effect;
	}

	// Convert to an object
	effect = { effect: effect };

	// Catch (effect, null, ...)
	if ( options == null ) {
		options = {};
	}

	// Catch (effect, callback)
	if ( $.isFunction( options ) ) {
		callback = options;
		speed = null;
		options = {};
	}

	// Catch (effect, speed, ?)
	if ( typeof options === "number" || $.fx.speeds[ options ] ) {
		callback = speed;
		speed = options;
		options = {};
	}

	// Catch (effect, options, callback)
	if ( $.isFunction( speed ) ) {
		callback = speed;
		speed = null;
	}

	// Add options to effect
	if ( options ) {
		$.extend( effect, options );
	}

	speed = speed || options.duration;
	effect.duration = $.fx.off ? 0 :
		typeof speed === "number" ? speed :
		speed in $.fx.speeds ? $.fx.speeds[ speed ] :
		$.fx.speeds._default;

	effect.complete = callback || options.complete;

	return effect;
}

function standardAnimationOption( option ) {

	// Valid standard speeds (nothing, number, named speed)
	if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
		return true;
	}

	// Invalid strings - treat as "normal" speed
	if ( typeof option === "string" && !$.effects.effect[ option ] ) {
		return true;
	}

	// Complete callback
	if ( $.isFunction( option ) ) {
		return true;
	}

	// Options hash (but not naming an effect)
	if ( typeof option === "object" && !option.effect ) {
		return true;
	}

	// Didn't match any standard API
	return false;
}

$.fn.extend( {
	effect: function( /* effect, options, speed, callback */ ) {
		var args = _normalizeArguments.apply( this, arguments ),
			effectMethod = $.effects.effect[ args.effect ],
			defaultMode = effectMethod.mode,
			queue = args.queue,
			queueName = queue || "fx",
			complete = args.complete,
			mode = args.mode,
			modes = [],
			prefilter = function( next ) {
				var el = $( this ),
					normalizedMode = $.effects.mode( el, mode ) || defaultMode;

				// Sentinel for duck-punching the :animated psuedo-selector
				el.data( dataSpaceAnimated, true );

				// Save effect mode for later use,
				// we can't just call $.effects.mode again later,
				// as the .show() below destroys the initial state
				modes.push( normalizedMode );

				// See $.uiBackCompat inside of run() for removal of defaultMode in 1.13
				if ( defaultMode && ( normalizedMode === "show" ||
						( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
					el.show();
				}

				if ( !defaultMode || normalizedMode !== "none" ) {
					$.effects.saveStyle( el );
				}

				if ( $.isFunction( next ) ) {
					next();
				}
			};

		if ( $.fx.off || !effectMethod ) {

			// Delegate to the original method (e.g., .show()) if possible
			if ( mode ) {
				return this[ mode ]( args.duration, complete );
			} else {
				return this.each( function() {
					if ( complete ) {
						complete.call( this );
					}
				} );
			}
		}

		function run( next ) {
			var elem = $( this );

			function cleanup() {
				elem.removeData( dataSpaceAnimated );

				$.effects.cleanUp( elem );

				if ( args.mode === "hide" ) {
					elem.hide();
				}

				done();
			}

			function done() {
				if ( $.isFunction( complete ) ) {
					complete.call( elem[ 0 ] );
				}

				if ( $.isFunction( next ) ) {
					next();
				}
			}

			// Override mode option on a per element basis,
			// as toggle can be either show or hide depending on element state
			args.mode = modes.shift();

			if ( $.uiBackCompat !== false && !defaultMode ) {
				if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {

					// Call the core method to track "olddisplay" properly
					elem[ mode ]();
					done();
				} else {
					effectMethod.call( elem[ 0 ], args, done );
				}
			} else {
				if ( args.mode === "none" ) {

					// Call the core method to track "olddisplay" properly
					elem[ mode ]();
					done();
				} else {
					effectMethod.call( elem[ 0 ], args, cleanup );
				}
			}
		}

		// Run prefilter on all elements first to ensure that
		// any showing or hiding happens before placeholder creation,
		// which ensures that any layout changes are correctly captured.
		return queue === false ?
			this.each( prefilter ).each( run ) :
			this.queue( queueName, prefilter ).queue( queueName, run );
	},

	show: ( function( orig ) {
		return function( option ) {
			if ( standardAnimationOption( option ) ) {
				return orig.apply( this, arguments );
			} else {
				var args = _normalizeArguments.apply( this, arguments );
				args.mode = "show";
				return this.effect.call( this, args );
			}
		};
	} )( $.fn.show ),

	hide: ( function( orig ) {
		return function( option ) {
			if ( standardAnimationOption( option ) ) {
				return orig.apply( this, arguments );
			} else {
				var args = _normalizeArguments.apply( this, arguments );
				args.mode = "hide";
				return this.effect.call( this, args );
			}
		};
	} )( $.fn.hide ),

	toggle: ( function( orig ) {
		return function( option ) {
			if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
				return orig.apply( this, arguments );
			} else {
				var args = _normalizeArguments.apply( this, arguments );
				args.mode = "toggle";
				return this.effect.call( this, args );
			}
		};
	} )( $.fn.toggle ),

	cssUnit: function( key ) {
		var style = this.css( key ),
			val = [];

		$.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
			if ( style.indexOf( unit ) > 0 ) {
				val = [ parseFloat( style ), unit ];
			}
		} );
		return val;
	},

	cssClip: function( clipObj ) {
		if ( clipObj ) {
			return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
				clipObj.bottom + "px " + clipObj.left + "px)" );
		}
		return parseClip( this.css( "clip" ), this );
	},

	transfer: function( options, done ) {
		var element = $( this ),
			target = $( options.to ),
			targetFixed = target.css( "position" ) === "fixed",
			body = $( "body" ),
			fixTop = targetFixed ? body.scrollTop() : 0,
			fixLeft = targetFixed ? body.scrollLeft() : 0,
			endPosition = target.offset(),
			animation = {
				top: endPosition.top - fixTop,
				left: endPosition.left - fixLeft,
				height: target.innerHeight(),
				width: target.innerWidth()
			},
			startPosition = element.offset(),
			transfer = $( "<div class='ui-effects-transfer'></div>" )
				.appendTo( "body" )
				.addClass( options.className )
				.css( {
					top: startPosition.top - fixTop,
					left: startPosition.left - fixLeft,
					height: element.innerHeight(),
					width: element.innerWidth(),
					position: targetFixed ? "fixed" : "absolute"
				} )
				.animate( animation, options.duration, options.easing, function() {
					transfer.remove();
					if ( $.isFunction( done ) ) {
						done();
					}
				} );
	}
} );

function parseClip( str, element ) {
		var outerWidth = element.outerWidth(),
			outerHeight = element.outerHeight(),
			clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,
			values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];

		return {
			top: parseFloat( values[ 1 ] ) || 0,
			right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
			bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
			left: parseFloat( values[ 4 ] ) || 0
		};
}

$.fx.step.clip = function( fx ) {
	if ( !fx.clipInit ) {
		fx.start = $( fx.elem ).cssClip();
		if ( typeof fx.end === "string" ) {
			fx.end = parseClip( fx.end, fx.elem );
		}
		fx.clipInit = true;
	}

	$( fx.elem ).cssClip( {
		top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
		right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
		bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
		left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
	} );
};

} )();

/******************************************************************************/
/*********************************** EASING ***********************************/
/******************************************************************************/

( function() {

// Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)

var baseEasings = {};

$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
	baseEasings[ name ] = function( p ) {
		return Math.pow( p, i + 2 );
	};
} );

$.extend( baseEasings, {
	Sine: function( p ) {
		return 1 - Math.cos( p * Math.PI / 2 );
	},
	Circ: function( p ) {
		return 1 - Math.sqrt( 1 - p * p );
	},
	Elastic: function( p ) {
		return p === 0 || p === 1 ? p :
			-Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
	},
	Back: function( p ) {
		return p * p * ( 3 * p - 2 );
	},
	Bounce: function( p ) {
		var pow2,
			bounce = 4;

		while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
		return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
	}
} );

$.each( baseEasings, function( name, easeIn ) {
	$.easing[ "easeIn" + name ] = easeIn;
	$.easing[ "easeOut" + name ] = function( p ) {
		return 1 - easeIn( 1 - p );
	};
	$.easing[ "easeInOut" + name ] = function( p ) {
		return p < 0.5 ?
			easeIn( p * 2 ) / 2 :
			1 - easeIn( p * -2 + 2 ) / 2;
	};
} );

} )();

var effect = $.effects;


/*!
 * jQuery UI Effects Blind 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Blind Effect
//>>group: Effects
//>>description: Blinds the element.
//>>docs: http://api.jqueryui.com/blind-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
	var map = {
			up: [ "bottom", "top" ],
			vertical: [ "bottom", "top" ],
			down: [ "top", "bottom" ],
			left: [ "right", "left" ],
			horizontal: [ "right", "left" ],
			right: [ "left", "right" ]
		},
		element = $( this ),
		direction = options.direction || "up",
		start = element.cssClip(),
		animate = { clip: $.extend( {}, start ) },
		placeholder = $.effects.createPlaceholder( element );

	animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];

	if ( options.mode === "show" ) {
		element.cssClip( animate.clip );
		if ( placeholder ) {
			placeholder.css( $.effects.clipToBox( animate ) );
		}

		animate.clip = start;
	}

	if ( placeholder ) {
		placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
	}

	element.animate( animate, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: done
	} );
} );


/*!
 * jQuery UI Effects Bounce 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Bounce Effect
//>>group: Effects
//>>description: Bounces an element horizontally or vertically n times.
//>>docs: http://api.jqueryui.com/bounce-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
	var upAnim, downAnim, refValue,
		element = $( this ),

		// Defaults:
		mode = options.mode,
		hide = mode === "hide",
		show = mode === "show",
		direction = options.direction || "up",
		distance = options.distance,
		times = options.times || 5,

		// Number of internal animations
		anims = times * 2 + ( show || hide ? 1 : 0 ),
		speed = options.duration / anims,
		easing = options.easing,

		// Utility:
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		motion = ( direction === "up" || direction === "left" ),
		i = 0,

		queuelen = element.queue().length;

	$.effects.createPlaceholder( element );

	refValue = element.css( ref );

	// Default distance for the BIGGEST bounce is the outer Distance / 3
	if ( !distance ) {
		distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
	}

	if ( show ) {
		downAnim = { opacity: 1 };
		downAnim[ ref ] = refValue;

		// If we are showing, force opacity 0 and set the initial position
		// then do the "first" animation
		element
			.css( "opacity", 0 )
			.css( ref, motion ? -distance * 2 : distance * 2 )
			.animate( downAnim, speed, easing );
	}

	// Start at the smallest distance if we are hiding
	if ( hide ) {
		distance = distance / Math.pow( 2, times - 1 );
	}

	downAnim = {};
	downAnim[ ref ] = refValue;

	// Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
	for ( ; i < times; i++ ) {
		upAnim = {};
		upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;

		element
			.animate( upAnim, speed, easing )
			.animate( downAnim, speed, easing );

		distance = hide ? distance * 2 : distance / 2;
	}

	// Last Bounce when Hiding
	if ( hide ) {
		upAnim = { opacity: 0 };
		upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;

		element.animate( upAnim, speed, easing );
	}

	element.queue( done );

	$.effects.unshift( element, queuelen, anims + 1 );
} );


/*!
 * jQuery UI Effects Clip 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Clip Effect
//>>group: Effects
//>>description: Clips the element on and off like an old TV.
//>>docs: http://api.jqueryui.com/clip-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
	var start,
		animate = {},
		element = $( this ),
		direction = options.direction || "vertical",
		both = direction === "both",
		horizontal = both || direction === "horizontal",
		vertical = both || direction === "vertical";

	start = element.cssClip();
	animate.clip = {
		top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
		right: horizontal ? ( start.right - start.left ) / 2 : start.right,
		bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
		left: horizontal ? ( start.right - start.left ) / 2 : start.left
	};

	$.effects.createPlaceholder( element );

	if ( options.mode === "show" ) {
		element.cssClip( animate.clip );
		animate.clip = start;
	}

	element.animate( animate, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: done
	} );

} );


/*!
 * jQuery UI Effects Drop 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Drop Effect
//>>group: Effects
//>>description: Moves an element in one direction and hides it at the same time.
//>>docs: http://api.jqueryui.com/drop-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {

	var distance,
		element = $( this ),
		mode = options.mode,
		show = mode === "show",
		direction = options.direction || "left",
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
		oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
		animation = {
			opacity: 0
		};

	$.effects.createPlaceholder( element );

	distance = options.distance ||
		element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;

	animation[ ref ] = motion + distance;

	if ( show ) {
		element.css( animation );

		animation[ ref ] = oppositeMotion + distance;
		animation.opacity = 1;
	}

	// Animate
	element.animate( animation, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: done
	} );
} );


/*!
 * jQuery UI Effects Explode 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Explode Effect
//>>group: Effects
// jscs:disable maximumLineLength
//>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/explode-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {

	var i, j, left, top, mx, my,
		rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
		cells = rows,
		element = $( this ),
		mode = options.mode,
		show = mode === "show",

		// Show and then visibility:hidden the element before calculating offset
		offset = element.show().css( "visibility", "hidden" ).offset(),

		// Width and height of a piece
		width = Math.ceil( element.outerWidth() / cells ),
		height = Math.ceil( element.outerHeight() / rows ),
		pieces = [];

	// Children animate complete:
	function childComplete() {
		pieces.push( this );
		if ( pieces.length === rows * cells ) {
			animComplete();
		}
	}

	// Clone the element for each row and cell.
	for ( i = 0; i < rows; i++ ) { // ===>
		top = offset.top + i * height;
		my = i - ( rows - 1 ) / 2;

		for ( j = 0; j < cells; j++ ) { // |||
			left = offset.left + j * width;
			mx = j - ( cells - 1 ) / 2;

			// Create a clone of the now hidden main element that will be absolute positioned
			// within a wrapper div off the -left and -top equal to size of our pieces
			element
				.clone()
				.appendTo( "body" )
				.wrap( "<div></div>" )
				.css( {
					position: "absolute",
					visibility: "visible",
					left: -j * width,
					top: -i * height
				} )

				// Select the wrapper - make it overflow: hidden and absolute positioned based on
				// where the original was located +left and +top equal to the size of pieces
				.parent()
					.addClass( "ui-effects-explode" )
					.css( {
						position: "absolute",
						overflow: "hidden",
						width: width,
						height: height,
						left: left + ( show ? mx * width : 0 ),
						top: top + ( show ? my * height : 0 ),
						opacity: show ? 0 : 1
					} )
					.animate( {
						left: left + ( show ? 0 : mx * width ),
						top: top + ( show ? 0 : my * height ),
						opacity: show ? 1 : 0
					}, options.duration || 500, options.easing, childComplete );
		}
	}

	function animComplete() {
		element.css( {
			visibility: "visible"
		} );
		$( pieces ).remove();
		done();
	}
} );


/*!
 * jQuery UI Effects Fade 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Fade Effect
//>>group: Effects
//>>description: Fades the element.
//>>docs: http://api.jqueryui.com/fade-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
	var show = options.mode === "show";

	$( this )
		.css( "opacity", show ? 0 : 1 )
		.animate( {
			opacity: show ? 1 : 0
		}, {
			queue: false,
			duration: options.duration,
			easing: options.easing,
			complete: done
		} );
} );


/*!
 * jQuery UI Effects Fold 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Fold Effect
//>>group: Effects
//>>description: Folds an element first horizontally and then vertically.
//>>docs: http://api.jqueryui.com/fold-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {

	// Create element
	var element = $( this ),
		mode = options.mode,
		show = mode === "show",
		hide = mode === "hide",
		size = options.size || 15,
		percent = /([0-9]+)%/.exec( size ),
		horizFirst = !!options.horizFirst,
		ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
		duration = options.duration / 2,

		placeholder = $.effects.createPlaceholder( element ),

		start = element.cssClip(),
		animation1 = { clip: $.extend( {}, start ) },
		animation2 = { clip: $.extend( {}, start ) },

		distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],

		queuelen = element.queue().length;

	if ( percent ) {
		size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
	}
	animation1.clip[ ref[ 0 ] ] = size;
	animation2.clip[ ref[ 0 ] ] = size;
	animation2.clip[ ref[ 1 ] ] = 0;

	if ( show ) {
		element.cssClip( animation2.clip );
		if ( placeholder ) {
			placeholder.css( $.effects.clipToBox( animation2 ) );
		}

		animation2.clip = start;
	}

	// Animate
	element
		.queue( function( next ) {
			if ( placeholder ) {
				placeholder
					.animate( $.effects.clipToBox( animation1 ), duration, options.easing )
					.animate( $.effects.clipToBox( animation2 ), duration, options.easing );
			}

			next();
		} )
		.animate( animation1, duration, options.easing )
		.animate( animation2, duration, options.easing )
		.queue( done );

	$.effects.unshift( element, queuelen, 4 );
} );


/*!
 * jQuery UI Effects Highlight 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Highlight Effect
//>>group: Effects
//>>description: Highlights the background of an element in a defined color for a custom duration.
//>>docs: http://api.jqueryui.com/highlight-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
	var element = $( this ),
		animation = {
			backgroundColor: element.css( "backgroundColor" )
		};

	if ( options.mode === "hide" ) {
		animation.opacity = 0;
	}

	$.effects.saveStyle( element );

	element
		.css( {
			backgroundImage: "none",
			backgroundColor: options.color || "#ffff99"
		} )
		.animate( animation, {
			queue: false,
			duration: options.duration,
			easing: options.easing,
			complete: done
		} );
} );


/*!
 * jQuery UI Effects Size 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Size Effect
//>>group: Effects
//>>description: Resize an element to a specified width and height.
//>>docs: http://api.jqueryui.com/size-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectSize = $.effects.define( "size", function( options, done ) {

	// Create element
	var baseline, factor, temp,
		element = $( this ),

		// Copy for children
		cProps = [ "fontSize" ],
		vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
		hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],

		// Set options
		mode = options.mode,
		restore = mode !== "effect",
		scale = options.scale || "both",
		origin = options.origin || [ "middle", "center" ],
		position = element.css( "position" ),
		pos = element.position(),
		original = $.effects.scaledDimensions( element ),
		from = options.from || original,
		to = options.to || $.effects.scaledDimensions( element, 0 );

	$.effects.createPlaceholder( element );

	if ( mode === "show" ) {
		temp = from;
		from = to;
		to = temp;
	}

	// Set scaling factor
	factor = {
		from: {
			y: from.height / original.height,
			x: from.width / original.width
		},
		to: {
			y: to.height / original.height,
			x: to.width / original.width
		}
	};

	// Scale the css box
	if ( scale === "box" || scale === "both" ) {

		// Vertical props scaling
		if ( factor.from.y !== factor.to.y ) {
			from = $.effects.setTransition( element, vProps, factor.from.y, from );
			to = $.effects.setTransition( element, vProps, factor.to.y, to );
		}

		// Horizontal props scaling
		if ( factor.from.x !== factor.to.x ) {
			from = $.effects.setTransition( element, hProps, factor.from.x, from );
			to = $.effects.setTransition( element, hProps, factor.to.x, to );
		}
	}

	// Scale the content
	if ( scale === "content" || scale === "both" ) {

		// Vertical props scaling
		if ( factor.from.y !== factor.to.y ) {
			from = $.effects.setTransition( element, cProps, factor.from.y, from );
			to = $.effects.setTransition( element, cProps, factor.to.y, to );
		}
	}

	// Adjust the position properties based on the provided origin points
	if ( origin ) {
		baseline = $.effects.getBaseline( origin, original );
		from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
		from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
		to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
		to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
	}
	element.css( from );

	// Animate the children if desired
	if ( scale === "content" || scale === "both" ) {

		vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
		hProps = hProps.concat( [ "marginLeft", "marginRight" ] );

		// Only animate children with width attributes specified
		// TODO: is this right? should we include anything with css width specified as well
		element.find( "*[width]" ).each( function() {
			var child = $( this ),
				childOriginal = $.effects.scaledDimensions( child ),
				childFrom = {
					height: childOriginal.height * factor.from.y,
					width: childOriginal.width * factor.from.x,
					outerHeight: childOriginal.outerHeight * factor.from.y,
					outerWidth: childOriginal.outerWidth * factor.from.x
				},
				childTo = {
					height: childOriginal.height * factor.to.y,
					width: childOriginal.width * factor.to.x,
					outerHeight: childOriginal.height * factor.to.y,
					outerWidth: childOriginal.width * factor.to.x
				};

			// Vertical props scaling
			if ( factor.from.y !== factor.to.y ) {
				childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
				childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
			}

			// Horizontal props scaling
			if ( factor.from.x !== factor.to.x ) {
				childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
				childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
			}

			if ( restore ) {
				$.effects.saveStyle( child );
			}

			// Animate children
			child.css( childFrom );
			child.animate( childTo, options.duration, options.easing, function() {

				// Restore children
				if ( restore ) {
					$.effects.restoreStyle( child );
				}
			} );
		} );
	}

	// Animate
	element.animate( to, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: function() {

			var offset = element.offset();

			if ( to.opacity === 0 ) {
				element.css( "opacity", from.opacity );
			}

			if ( !restore ) {
				element
					.css( "position", position === "static" ? "relative" : position )
					.offset( offset );

				// Need to save style here so that automatic style restoration
				// doesn't restore to the original styles from before the animation.
				$.effects.saveStyle( element );
			}

			done();
		}
	} );

} );


/*!
 * jQuery UI Effects Scale 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Scale Effect
//>>group: Effects
//>>description: Grows or shrinks an element and its content.
//>>docs: http://api.jqueryui.com/scale-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectScale = $.effects.define( "scale", function( options, done ) {

	// Create element
	var el = $( this ),
		mode = options.mode,
		percent = parseInt( options.percent, 10 ) ||
			( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),

		newOptions = $.extend( true, {
			from: $.effects.scaledDimensions( el ),
			to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
			origin: options.origin || [ "middle", "center" ]
		}, options );

	// Fade option to support puff
	if ( options.fade ) {
		newOptions.from.opacity = 1;
		newOptions.to.opacity = 0;
	}

	$.effects.effect.size.call( this, newOptions, done );
} );


/*!
 * jQuery UI Effects Puff 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Puff Effect
//>>group: Effects
//>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
//>>docs: http://api.jqueryui.com/puff-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
	var newOptions = $.extend( true, {}, options, {
		fade: true,
		percent: parseInt( options.percent, 10 ) || 150
	} );

	$.effects.effect.scale.call( this, newOptions, done );
} );


/*!
 * jQuery UI Effects Pulsate 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Pulsate Effect
//>>group: Effects
//>>description: Pulsates an element n times by changing the opacity to zero and back.
//>>docs: http://api.jqueryui.com/pulsate-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
	var element = $( this ),
		mode = options.mode,
		show = mode === "show",
		hide = mode === "hide",
		showhide = show || hide,

		// Showing or hiding leaves off the "last" animation
		anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
		duration = options.duration / anims,
		animateTo = 0,
		i = 1,
		queuelen = element.queue().length;

	if ( show || !element.is( ":visible" ) ) {
		element.css( "opacity", 0 ).show();
		animateTo = 1;
	}

	// Anims - 1 opacity "toggles"
	for ( ; i < anims; i++ ) {
		element.animate( { opacity: animateTo }, duration, options.easing );
		animateTo = 1 - animateTo;
	}

	element.animate( { opacity: animateTo }, duration, options.easing );

	element.queue( done );

	$.effects.unshift( element, queuelen, anims + 1 );
} );


/*!
 * jQuery UI Effects Shake 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Shake Effect
//>>group: Effects
//>>description: Shakes an element horizontally or vertically n times.
//>>docs: http://api.jqueryui.com/shake-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectShake = $.effects.define( "shake", function( options, done ) {

	var i = 1,
		element = $( this ),
		direction = options.direction || "left",
		distance = options.distance || 20,
		times = options.times || 3,
		anims = times * 2 + 1,
		speed = Math.round( options.duration / anims ),
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		positiveMotion = ( direction === "up" || direction === "left" ),
		animation = {},
		animation1 = {},
		animation2 = {},

		queuelen = element.queue().length;

	$.effects.createPlaceholder( element );

	// Animation
	animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
	animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
	animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;

	// Animate
	element.animate( animation, speed, options.easing );

	// Shakes
	for ( ; i < times; i++ ) {
		element
			.animate( animation1, speed, options.easing )
			.animate( animation2, speed, options.easing );
	}

	element
		.animate( animation1, speed, options.easing )
		.animate( animation, speed / 2, options.easing )
		.queue( done );

	$.effects.unshift( element, queuelen, anims + 1 );
} );


/*!
 * jQuery UI Effects Slide 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Slide Effect
//>>group: Effects
//>>description: Slides an element in and out of the viewport.
//>>docs: http://api.jqueryui.com/slide-effect/
//>>demos: http://jqueryui.com/effect/



var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
	var startClip, startRef,
		element = $( this ),
		map = {
			up: [ "bottom", "top" ],
			down: [ "top", "bottom" ],
			left: [ "right", "left" ],
			right: [ "left", "right" ]
		},
		mode = options.mode,
		direction = options.direction || "left",
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		positiveMotion = ( direction === "up" || direction === "left" ),
		distance = options.distance ||
			element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
		animation = {};

	$.effects.createPlaceholder( element );

	startClip = element.cssClip();
	startRef = element.position()[ ref ];

	// Define hide animation
	animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
	animation.clip = element.cssClip();
	animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];

	// Reverse the animation if we're showing
	if ( mode === "show" ) {
		element.cssClip( animation.clip );
		element.css( ref, animation[ ref ] );
		animation.clip = startClip;
		animation[ ref ] = startRef;
	}

	// Actually animate
	element.animate( animation, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: done
	} );
} );


/*!
 * jQuery UI Effects Transfer 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Transfer Effect
//>>group: Effects
//>>description: Displays a transfer effect from one element to another.
//>>docs: http://api.jqueryui.com/transfer-effect/
//>>demos: http://jqueryui.com/effect/



var effect;
if ( $.uiBackCompat !== false ) {
	effect = $.effects.define( "transfer", function( options, done ) {
		$( this ).transfer( options, done );
	} );
}
var effectsEffectTransfer = effect;


/*!
 * jQuery UI Focusable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: :focusable Selector
//>>group: Core
//>>description: Selects elements which can be focused.
//>>docs: http://api.jqueryui.com/focusable-selector/



// Selectors
$.ui.focusable = function( element, hasTabindex ) {
	var map, mapName, img, focusableIfVisible, fieldset,
		nodeName = element.nodeName.toLowerCase();

	if ( "area" === nodeName ) {
		map = element.parentNode;
		mapName = map.name;
		if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
			return false;
		}
		img = $( "img[usemap='#" + mapName + "']" );
		return img.length > 0 && img.is( ":visible" );
	}

	if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
		focusableIfVisible = !element.disabled;

		if ( focusableIfVisible ) {

			// Form controls within a disabled fieldset are disabled.
			// However, controls within the fieldset's legend do not get disabled.
			// Since controls generally aren't placed inside legends, we skip
			// this portion of the check.
			fieldset = $( element ).closest( "fieldset" )[ 0 ];
			if ( fieldset ) {
				focusableIfVisible = !fieldset.disabled;
			}
		}
	} else if ( "a" === nodeName ) {
		focusableIfVisible = element.href || hasTabindex;
	} else {
		focusableIfVisible = hasTabindex;
	}

	return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
};

// Support: IE 8 only
// IE 8 doesn't resolve inherit to visible/hidden for computed values
function visible( element ) {
	var visibility = element.css( "visibility" );
	while ( visibility === "inherit" ) {
		element = element.parent();
		visibility = element.css( "visibility" );
	}
	return visibility !== "hidden";
}

$.extend( $.expr[ ":" ], {
	focusable: function( element ) {
		return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
	}
} );

var focusable = $.ui.focusable;




// Support: IE8 Only
// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
// with a string, so we need to find the proper form.
var form = $.fn.form = function() {
	return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
};


/*!
 * jQuery UI Form Reset Mixin 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Form Reset Mixin
//>>group: Core
//>>description: Refresh input widgets when their form is reset
//>>docs: http://api.jqueryui.com/form-reset-mixin/



var formResetMixin = $.ui.formResetMixin = {
	_formResetHandler: function() {
		var form = $( this );

		// Wait for the form reset to actually happen before refreshing
		setTimeout( function() {
			var instances = form.data( "ui-form-reset-instances" );
			$.each( instances, function() {
				this.refresh();
			} );
		} );
	},

	_bindFormResetHandler: function() {
		this.form = this.element.form();
		if ( !this.form.length ) {
			return;
		}

		var instances = this.form.data( "ui-form-reset-instances" ) || [];
		if ( !instances.length ) {

			// We don't use _on() here because we use a single event handler per form
			this.form.on( "reset.ui-form-reset", this._formResetHandler );
		}
		instances.push( this );
		this.form.data( "ui-form-reset-instances", instances );
	},

	_unbindFormResetHandler: function() {
		if ( !this.form.length ) {
			return;
		}

		var instances = this.form.data( "ui-form-reset-instances" );
		instances.splice( $.inArray( this, instances ), 1 );
		if ( instances.length ) {
			this.form.data( "ui-form-reset-instances", instances );
		} else {
			this.form
				.removeData( "ui-form-reset-instances" )
				.off( "reset.ui-form-reset" );
		}
	}
};


/*!
 * jQuery UI Support for jQuery core 1.7.x 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 */

//>>label: jQuery 1.7 Support
//>>group: Core
//>>description: Support version 1.7.x of jQuery core



// Support: jQuery 1.7 only
// Not a great way to check versions, but since we only support 1.7+ and only
// need to detect <1.8, this is a simple check that should suffice. Checking
// for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0
// and we'll never reach 1.70.0 (if we do, we certainly won't be supporting
// 1.7 anymore). See #11197 for why we're not using feature detection.
if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) {

	// Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight()
	// Unlike jQuery Core 1.8+, these only support numeric values to set the
	// dimensions in pixels
	$.each( [ "Width", "Height" ], function( i, name ) {
		var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
			type = name.toLowerCase(),
			orig = {
				innerWidth: $.fn.innerWidth,
				innerHeight: $.fn.innerHeight,
				outerWidth: $.fn.outerWidth,
				outerHeight: $.fn.outerHeight
			};

		function reduce( elem, size, border, margin ) {
			$.each( side, function() {
				size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
				if ( border ) {
					size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
				}
				if ( margin ) {
					size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
				}
			} );
			return size;
		}

		$.fn[ "inner" + name ] = function( size ) {
			if ( size === undefined ) {
				return orig[ "inner" + name ].call( this );
			}

			return this.each( function() {
				$( this ).css( type, reduce( this, size ) + "px" );
			} );
		};

		$.fn[ "outer" + name ] = function( size, margin ) {
			if ( typeof size !== "number" ) {
				return orig[ "outer" + name ].call( this, size );
			}

			return this.each( function() {
				$( this ).css( type, reduce( this, size, true, margin ) + "px" );
			} );
		};
	} );

	$.fn.addBack = function( selector ) {
		return this.add( selector == null ?
			this.prevObject : this.prevObject.filter( selector )
		);
	};
}

;
/*!
 * jQuery UI Keycode 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Keycode
//>>group: Core
//>>description: Provide keycodes as keynames
//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/


var keycode = $.ui.keyCode = {
	BACKSPACE: 8,
	COMMA: 188,
	DELETE: 46,
	DOWN: 40,
	END: 35,
	ENTER: 13,
	ESCAPE: 27,
	HOME: 36,
	LEFT: 37,
	PAGE_DOWN: 34,
	PAGE_UP: 33,
	PERIOD: 190,
	RIGHT: 39,
	SPACE: 32,
	TAB: 9,
	UP: 38
};




// Internal use only
var escapeSelector = $.ui.escapeSelector = ( function() {
	var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
	return function( selector ) {
		return selector.replace( selectorEscape, "\\$1" );
	};
} )();


/*!
 * jQuery UI Labels 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: labels
//>>group: Core
//>>description: Find all the labels associated with a given input
//>>docs: http://api.jqueryui.com/labels/



var labels = $.fn.labels = function() {
	var ancestor, selector, id, labels, ancestors;

	// Check control.labels first
	if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
		return this.pushStack( this[ 0 ].labels );
	}

	// Support: IE <= 11, FF <= 37, Android <= 2.3 only
	// Above browsers do not support control.labels. Everything below is to support them
	// as well as document fragments. control.labels does not work on document fragments
	labels = this.eq( 0 ).parents( "label" );

	// Look for the label based on the id
	id = this.attr( "id" );
	if ( id ) {

		// We don't search against the document in case the element
		// is disconnected from the DOM
		ancestor = this.eq( 0 ).parents().last();

		// Get a full set of top level ancestors
		ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );

		// Create a selector for the label based on the id
		selector = "label[for='" + $.ui.escapeSelector( id ) + "']";

		labels = labels.add( ancestors.find( selector ).addBack( selector ) );

	}

	// Return whatever we have found for labels
	return this.pushStack( labels );
};


/*!
 * jQuery UI Scroll Parent 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: scrollParent
//>>group: Core
//>>description: Get the closest ancestor element that is scrollable.
//>>docs: http://api.jqueryui.com/scrollParent/



var scrollParent = $.fn.scrollParent = function( includeHidden ) {
	var position = this.css( "position" ),
		excludeStaticParent = position === "absolute",
		overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
		scrollParent = this.parents().filter( function() {
			var parent = $( this );
			if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
				return false;
			}
			return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
				parent.css( "overflow-x" ) );
		} ).eq( 0 );

	return position === "fixed" || !scrollParent.length ?
		$( this[ 0 ].ownerDocument || document ) :
		scrollParent;
};


/*!
 * jQuery UI Tabbable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: :tabbable Selector
//>>group: Core
//>>description: Selects elements which can be tabbed to.
//>>docs: http://api.jqueryui.com/tabbable-selector/



var tabbable = $.extend( $.expr[ ":" ], {
	tabbable: function( element ) {
		var tabIndex = $.attr( element, "tabindex" ),
			hasTabindex = tabIndex != null;
		return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
	}
} );


/*!
 * jQuery UI Unique ID 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: uniqueId
//>>group: Core
//>>description: Functions to generate and remove uniqueId's
//>>docs: http://api.jqueryui.com/uniqueId/



var uniqueId = $.fn.extend( {
	uniqueId: ( function() {
		var uuid = 0;

		return function() {
			return this.each( function() {
				if ( !this.id ) {
					this.id = "ui-id-" + ( ++uuid );
				}
			} );
		};
	} )(),

	removeUniqueId: function() {
		return this.each( function() {
			if ( /^ui-id-\d+$/.test( this.id ) ) {
				$( this ).removeAttr( "id" );
			}
		} );
	}
} );


/*!
 * jQuery UI Accordion 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Accordion
//>>group: Widgets
// jscs:disable maximumLineLength
//>>description: Displays collapsible content panels for presenting information in a limited amount of space.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/accordion/
//>>demos: http://jqueryui.com/accordion/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/accordion.css
//>>css.theme: ../../themes/base/theme.css



var widgetsAccordion = $.widget( "ui.accordion", {
	version: "1.12.1",
	options: {
		active: 0,
		animate: {},
		classes: {
			"ui-accordion-header": "ui-corner-top",
			"ui-accordion-header-collapsed": "ui-corner-all",
			"ui-accordion-content": "ui-corner-bottom"
		},
		collapsible: false,
		event: "click",
		header: "> li > :first-child, > :not(li):even",
		heightStyle: "auto",
		icons: {
			activeHeader: "ui-icon-triangle-1-s",
			header: "ui-icon-triangle-1-e"
		},

		// Callbacks
		activate: null,
		beforeActivate: null
	},

	hideProps: {
		borderTopWidth: "hide",
		borderBottomWidth: "hide",
		paddingTop: "hide",
		paddingBottom: "hide",
		height: "hide"
	},

	showProps: {
		borderTopWidth: "show",
		borderBottomWidth: "show",
		paddingTop: "show",
		paddingBottom: "show",
		height: "show"
	},

	_create: function() {
		var options = this.options;

		this.prevShow = this.prevHide = $();
		this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
		this.element.attr( "role", "tablist" );

		// Don't allow collapsible: false and active: false / null
		if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
			options.active = 0;
		}

		this._processPanels();

		// handle negative values
		if ( options.active < 0 ) {
			options.active += this.headers.length;
		}
		this._refresh();
	},

	_getCreateEventData: function() {
		return {
			header: this.active,
			panel: !this.active.length ? $() : this.active.next()
		};
	},

	_createIcons: function() {
		var icon, children,
			icons = this.options.icons;

		if ( icons ) {
			icon = $( "<span>" );
			this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
			icon.prependTo( this.headers );
			children = this.active.children( ".ui-accordion-header-icon" );
			this._removeClass( children, icons.header )
				._addClass( children, null, icons.activeHeader )
				._addClass( this.headers, "ui-accordion-icons" );
		}
	},

	_destroyIcons: function() {
		this._removeClass( this.headers, "ui-accordion-icons" );
		this.headers.children( ".ui-accordion-header-icon" ).remove();
	},

	_destroy: function() {
		var contents;

		// Clean up main element
		this.element.removeAttr( "role" );

		// Clean up headers
		this.headers
			.removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
			.removeUniqueId();

		this._destroyIcons();

		// Clean up content panels
		contents = this.headers.next()
			.css( "display", "" )
			.removeAttr( "role aria-hidden aria-labelledby" )
			.removeUniqueId();

		if ( this.options.heightStyle !== "content" ) {
			contents.css( "height", "" );
		}
	},

	_setOption: function( key, value ) {
		if ( key === "active" ) {

			// _activate() will handle invalid values and update this.options
			this._activate( value );
			return;
		}

		if ( key === "event" ) {
			if ( this.options.event ) {
				this._off( this.headers, this.options.event );
			}
			this._setupEvents( value );
		}

		this._super( key, value );

		// Setting collapsible: false while collapsed; open first panel
		if ( key === "collapsible" && !value && this.options.active === false ) {
			this._activate( 0 );
		}

		if ( key === "icons" ) {
			this._destroyIcons();
			if ( value ) {
				this._createIcons();
			}
		}
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this.element.attr( "aria-disabled", value );

		// Support: IE8 Only
		// #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
		// so we need to add the disabled class to the headers and panels
		this._toggleClass( null, "ui-state-disabled", !!value );
		this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
			!!value );
	},

	_keydown: function( event ) {
		if ( event.altKey || event.ctrlKey ) {
			return;
		}

		var keyCode = $.ui.keyCode,
			length = this.headers.length,
			currentIndex = this.headers.index( event.target ),
			toFocus = false;

		switch ( event.keyCode ) {
		case keyCode.RIGHT:
		case keyCode.DOWN:
			toFocus = this.headers[ ( currentIndex + 1 ) % length ];
			break;
		case keyCode.LEFT:
		case keyCode.UP:
			toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
			break;
		case keyCode.SPACE:
		case keyCode.ENTER:
			this._eventHandler( event );
			break;
		case keyCode.HOME:
			toFocus = this.headers[ 0 ];
			break;
		case keyCode.END:
			toFocus = this.headers[ length - 1 ];
			break;
		}

		if ( toFocus ) {
			$( event.target ).attr( "tabIndex", -1 );
			$( toFocus ).attr( "tabIndex", 0 );
			$( toFocus ).trigger( "focus" );
			event.preventDefault();
		}
	},

	_panelKeyDown: function( event ) {
		if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
			$( event.currentTarget ).prev().trigger( "focus" );
		}
	},

	refresh: function() {
		var options = this.options;
		this._processPanels();

		// Was collapsed or no panel
		if ( ( options.active === false && options.collapsible === true ) ||
				!this.headers.length ) {
			options.active = false;
			this.active = $();

		// active false only when collapsible is true
		} else if ( options.active === false ) {
			this._activate( 0 );

		// was active, but active panel is gone
		} else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {

			// all remaining panel are disabled
			if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
				options.active = false;
				this.active = $();

			// activate previous panel
			} else {
				this._activate( Math.max( 0, options.active - 1 ) );
			}

		// was active, active panel still exists
		} else {

			// make sure active index is correct
			options.active = this.headers.index( this.active );
		}

		this._destroyIcons();

		this._refresh();
	},

	_processPanels: function() {
		var prevHeaders = this.headers,
			prevPanels = this.panels;

		this.headers = this.element.find( this.options.header );
		this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
			"ui-state-default" );

		this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
		this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );

		// Avoid memory leaks (#10056)
		if ( prevPanels ) {
			this._off( prevHeaders.not( this.headers ) );
			this._off( prevPanels.not( this.panels ) );
		}
	},

	_refresh: function() {
		var maxHeight,
			options = this.options,
			heightStyle = options.heightStyle,
			parent = this.element.parent();

		this.active = this._findActive( options.active );
		this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
			._removeClass( this.active, "ui-accordion-header-collapsed" );
		this._addClass( this.active.next(), "ui-accordion-content-active" );
		this.active.next().show();

		this.headers
			.attr( "role", "tab" )
			.each( function() {
				var header = $( this ),
					headerId = header.uniqueId().attr( "id" ),
					panel = header.next(),
					panelId = panel.uniqueId().attr( "id" );
				header.attr( "aria-controls", panelId );
				panel.attr( "aria-labelledby", headerId );
			} )
			.next()
				.attr( "role", "tabpanel" );

		this.headers
			.not( this.active )
				.attr( {
					"aria-selected": "false",
					"aria-expanded": "false",
					tabIndex: -1
				} )
				.next()
					.attr( {
						"aria-hidden": "true"
					} )
					.hide();

		// Make sure at least one header is in the tab order
		if ( !this.active.length ) {
			this.headers.eq( 0 ).attr( "tabIndex", 0 );
		} else {
			this.active.attr( {
				"aria-selected": "true",
				"aria-expanded": "true",
				tabIndex: 0
			} )
				.next()
					.attr( {
						"aria-hidden": "false"
					} );
		}

		this._createIcons();

		this._setupEvents( options.event );

		if ( heightStyle === "fill" ) {
			maxHeight = parent.height();
			this.element.siblings( ":visible" ).each( function() {
				var elem = $( this ),
					position = elem.css( "position" );

				if ( position === "absolute" || position === "fixed" ) {
					return;
				}
				maxHeight -= elem.outerHeight( true );
			} );

			this.headers.each( function() {
				maxHeight -= $( this ).outerHeight( true );
			} );

			this.headers.next()
				.each( function() {
					$( this ).height( Math.max( 0, maxHeight -
						$( this ).innerHeight() + $( this ).height() ) );
				} )
				.css( "overflow", "auto" );
		} else if ( heightStyle === "auto" ) {
			maxHeight = 0;
			this.headers.next()
				.each( function() {
					var isVisible = $( this ).is( ":visible" );
					if ( !isVisible ) {
						$( this ).show();
					}
					maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
					if ( !isVisible ) {
						$( this ).hide();
					}
				} )
				.height( maxHeight );
		}
	},

	_activate: function( index ) {
		var active = this._findActive( index )[ 0 ];

		// Trying to activate the already active panel
		if ( active === this.active[ 0 ] ) {
			return;
		}

		// Trying to collapse, simulate a click on the currently active header
		active = active || this.active[ 0 ];

		this._eventHandler( {
			target: active,
			currentTarget: active,
			preventDefault: $.noop
		} );
	},

	_findActive: function( selector ) {
		return typeof selector === "number" ? this.headers.eq( selector ) : $();
	},

	_setupEvents: function( event ) {
		var events = {
			keydown: "_keydown"
		};
		if ( event ) {
			$.each( event.split( " " ), function( index, eventName ) {
				events[ eventName ] = "_eventHandler";
			} );
		}

		this._off( this.headers.add( this.headers.next() ) );
		this._on( this.headers, events );
		this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
		this._hoverable( this.headers );
		this._focusable( this.headers );
	},

	_eventHandler: function( event ) {
		var activeChildren, clickedChildren,
			options = this.options,
			active = this.active,
			clicked = $( event.currentTarget ),
			clickedIsActive = clicked[ 0 ] === active[ 0 ],
			collapsing = clickedIsActive && options.collapsible,
			toShow = collapsing ? $() : clicked.next(),
			toHide = active.next(),
			eventData = {
				oldHeader: active,
				oldPanel: toHide,
				newHeader: collapsing ? $() : clicked,
				newPanel: toShow
			};

		event.preventDefault();

		if (

				// click on active header, but not collapsible
				( clickedIsActive && !options.collapsible ) ||

				// allow canceling activation
				( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
			return;
		}

		options.active = collapsing ? false : this.headers.index( clicked );

		// When the call to ._toggle() comes after the class changes
		// it causes a very odd bug in IE 8 (see #6720)
		this.active = clickedIsActive ? $() : clicked;
		this._toggle( eventData );

		// Switch classes
		// corner classes on the previously active header stay after the animation
		this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
		if ( options.icons ) {
			activeChildren = active.children( ".ui-accordion-header-icon" );
			this._removeClass( activeChildren, null, options.icons.activeHeader )
				._addClass( activeChildren, null, options.icons.header );
		}

		if ( !clickedIsActive ) {
			this._removeClass( clicked, "ui-accordion-header-collapsed" )
				._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
			if ( options.icons ) {
				clickedChildren = clicked.children( ".ui-accordion-header-icon" );
				this._removeClass( clickedChildren, null, options.icons.header )
					._addClass( clickedChildren, null, options.icons.activeHeader );
			}

			this._addClass( clicked.next(), "ui-accordion-content-active" );
		}
	},

	_toggle: function( data ) {
		var toShow = data.newPanel,
			toHide = this.prevShow.length ? this.prevShow : data.oldPanel;

		// Handle activating a panel during the animation for another activation
		this.prevShow.add( this.prevHide ).stop( true, true );
		this.prevShow = toShow;
		this.prevHide = toHide;

		if ( this.options.animate ) {
			this._animate( toShow, toHide, data );
		} else {
			toHide.hide();
			toShow.show();
			this._toggleComplete( data );
		}

		toHide.attr( {
			"aria-hidden": "true"
		} );
		toHide.prev().attr( {
			"aria-selected": "false",
			"aria-expanded": "false"
		} );

		// if we're switching panels, remove the old header from the tab order
		// if we're opening from collapsed state, remove the previous header from the tab order
		// if we're collapsing, then keep the collapsing header in the tab order
		if ( toShow.length && toHide.length ) {
			toHide.prev().attr( {
				"tabIndex": -1,
				"aria-expanded": "false"
			} );
		} else if ( toShow.length ) {
			this.headers.filter( function() {
				return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
			} )
				.attr( "tabIndex", -1 );
		}

		toShow
			.attr( "aria-hidden", "false" )
			.prev()
				.attr( {
					"aria-selected": "true",
					"aria-expanded": "true",
					tabIndex: 0
				} );
	},

	_animate: function( toShow, toHide, data ) {
		var total, easing, duration,
			that = this,
			adjust = 0,
			boxSizing = toShow.css( "box-sizing" ),
			down = toShow.length &&
				( !toHide.length || ( toShow.index() < toHide.index() ) ),
			animate = this.options.animate || {},
			options = down && animate.down || animate,
			complete = function() {
				that._toggleComplete( data );
			};

		if ( typeof options === "number" ) {
			duration = options;
		}
		if ( typeof options === "string" ) {
			easing = options;
		}

		// fall back from options to animation in case of partial down settings
		easing = easing || options.easing || animate.easing;
		duration = duration || options.duration || animate.duration;

		if ( !toHide.length ) {
			return toShow.animate( this.showProps, duration, easing, complete );
		}
		if ( !toShow.length ) {
			return toHide.animate( this.hideProps, duration, easing, complete );
		}

		total = toShow.show().outerHeight();
		toHide.animate( this.hideProps, {
			duration: duration,
			easing: easing,
			step: function( now, fx ) {
				fx.now = Math.round( now );
			}
		} );
		toShow
			.hide()
			.animate( this.showProps, {
				duration: duration,
				easing: easing,
				complete: complete,
				step: function( now, fx ) {
					fx.now = Math.round( now );
					if ( fx.prop !== "height" ) {
						if ( boxSizing === "content-box" ) {
							adjust += fx.now;
						}
					} else if ( that.options.heightStyle !== "content" ) {
						fx.now = Math.round( total - toHide.outerHeight() - adjust );
						adjust = 0;
					}
				}
			} );
	},

	_toggleComplete: function( data ) {
		var toHide = data.oldPanel,
			prev = toHide.prev();

		this._removeClass( toHide, "ui-accordion-content-active" );
		this._removeClass( prev, "ui-accordion-header-active" )
			._addClass( prev, "ui-accordion-header-collapsed" );

		// Work around for rendering bug in IE (#5421)
		if ( toHide.length ) {
			toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
		}
		this._trigger( "activate", null, data );
	}
} );



var safeActiveElement = $.ui.safeActiveElement = function( document ) {
	var activeElement;

	// Support: IE 9 only
	// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
	try {
		activeElement = document.activeElement;
	} catch ( error ) {
		activeElement = document.body;
	}

	// Support: IE 9 - 11 only
	// IE may return null instead of an element
	// Interestingly, this only seems to occur when NOT in an iframe
	if ( !activeElement ) {
		activeElement = document.body;
	}

	// Support: IE 11 only
	// IE11 returns a seemingly empty object in some cases when accessing
	// document.activeElement from an <iframe>
	if ( !activeElement.nodeName ) {
		activeElement = document.body;
	}

	return activeElement;
};


/*!
 * jQuery UI Menu 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Menu
//>>group: Widgets
//>>description: Creates nestable menus.
//>>docs: http://api.jqueryui.com/menu/
//>>demos: http://jqueryui.com/menu/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/menu.css
//>>css.theme: ../../themes/base/theme.css



var widgetsMenu = $.widget( "ui.menu", {
	version: "1.12.1",
	defaultElement: "<ul>",
	delay: 300,
	options: {
		icons: {
			submenu: "ui-icon-caret-1-e"
		},
		items: "> *",
		menus: "ul",
		position: {
			my: "left top",
			at: "right top"
		},
		role: "menu",

		// Callbacks
		blur: null,
		focus: null,
		select: null
	},

	_create: function() {
		this.activeMenu = this.element;

		// Flag used to prevent firing of the click handler
		// as the event bubbles up through nested menus
		this.mouseHandled = false;
		this.element
			.uniqueId()
			.attr( {
				role: this.options.role,
				tabIndex: 0
			} );

		this._addClass( "ui-menu", "ui-widget ui-widget-content" );
		this._on( {

			// Prevent focus from sticking to links inside menu after clicking
			// them (focus should always stay on UL during navigation).
			"mousedown .ui-menu-item": function( event ) {
				event.preventDefault();
			},
			"click .ui-menu-item": function( event ) {
				var target = $( event.target );
				var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
				if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
					this.select( event );

					// Only set the mouseHandled flag if the event will bubble, see #9469.
					if ( !event.isPropagationStopped() ) {
						this.mouseHandled = true;
					}

					// Open submenu on click
					if ( target.has( ".ui-menu" ).length ) {
						this.expand( event );
					} else if ( !this.element.is( ":focus" ) &&
							active.closest( ".ui-menu" ).length ) {

						// Redirect focus to the menu
						this.element.trigger( "focus", [ true ] );

						// If the active item is on the top level, let it stay active.
						// Otherwise, blur the active item since it is no longer visible.
						if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
							clearTimeout( this.timer );
						}
					}
				}
			},
			"mouseenter .ui-menu-item": function( event ) {

				// Ignore mouse events while typeahead is active, see #10458.
				// Prevents focusing the wrong item when typeahead causes a scroll while the mouse
				// is over an item in the menu
				if ( this.previousFilter ) {
					return;
				}

				var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
					target = $( event.currentTarget );

				// Ignore bubbled events on parent items, see #11641
				if ( actualTarget[ 0 ] !== target[ 0 ] ) {
					return;
				}

				// Remove ui-state-active class from siblings of the newly focused menu item
				// to avoid a jump caused by adjacent elements both having a class with a border
				this._removeClass( target.siblings().children( ".ui-state-active" ),
					null, "ui-state-active" );
				this.focus( event, target );
			},
			mouseleave: "collapseAll",
			"mouseleave .ui-menu": "collapseAll",
			focus: function( event, keepActiveItem ) {

				// If there's already an active item, keep it active
				// If not, activate the first item
				var item = this.active || this.element.find( this.options.items ).eq( 0 );

				if ( !keepActiveItem ) {
					this.focus( event, item );
				}
			},
			blur: function( event ) {
				this._delay( function() {
					var notContained = !$.contains(
						this.element[ 0 ],
						$.ui.safeActiveElement( this.document[ 0 ] )
					);
					if ( notContained ) {
						this.collapseAll( event );
					}
				} );
			},
			keydown: "_keydown"
		} );

		this.refresh();

		// Clicks outside of a menu collapse any open menus
		this._on( this.document, {
			click: function( event ) {
				if ( this._closeOnDocumentClick( event ) ) {
					this.collapseAll( event );
				}

				// Reset the mouseHandled flag
				this.mouseHandled = false;
			}
		} );
	},

	_destroy: function() {
		var items = this.element.find( ".ui-menu-item" )
				.removeAttr( "role aria-disabled" ),
			submenus = items.children( ".ui-menu-item-wrapper" )
				.removeUniqueId()
				.removeAttr( "tabIndex role aria-haspopup" );

		// Destroy (sub)menus
		this.element
			.removeAttr( "aria-activedescendant" )
			.find( ".ui-menu" ).addBack()
				.removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
					"tabIndex" )
				.removeUniqueId()
				.show();

		submenus.children().each( function() {
			var elem = $( this );
			if ( elem.data( "ui-menu-submenu-caret" ) ) {
				elem.remove();
			}
		} );
	},

	_keydown: function( event ) {
		var match, prev, character, skip,
			preventDefault = true;

		switch ( event.keyCode ) {
		case $.ui.keyCode.PAGE_UP:
			this.previousPage( event );
			break;
		case $.ui.keyCode.PAGE_DOWN:
			this.nextPage( event );
			break;
		case $.ui.keyCode.HOME:
			this._move( "first", "first", event );
			break;
		case $.ui.keyCode.END:
			this._move( "last", "last", event );
			break;
		case $.ui.keyCode.UP:
			this.previous( event );
			break;
		case $.ui.keyCode.DOWN:
			this.next( event );
			break;
		case $.ui.keyCode.LEFT:
			this.collapse( event );
			break;
		case $.ui.keyCode.RIGHT:
			if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
				this.expand( event );
			}
			break;
		case $.ui.keyCode.ENTER:
		case $.ui.keyCode.SPACE:
			this._activate( event );
			break;
		case $.ui.keyCode.ESCAPE:
			this.collapse( event );
			break;
		default:
			preventDefault = false;
			prev = this.previousFilter || "";
			skip = false;

			// Support number pad values
			character = event.keyCode >= 96 && event.keyCode <= 105 ?
				( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );

			clearTimeout( this.filterTimer );

			if ( character === prev ) {
				skip = true;
			} else {
				character = prev + character;
			}

			match = this._filterMenuItems( character );
			match = skip && match.index( this.active.next() ) !== -1 ?
				this.active.nextAll( ".ui-menu-item" ) :
				match;

			// If no matches on the current filter, reset to the last character pressed
			// to move down the menu to the first item that starts with that character
			if ( !match.length ) {
				character = String.fromCharCode( event.keyCode );
				match = this._filterMenuItems( character );
			}

			if ( match.length ) {
				this.focus( event, match );
				this.previousFilter = character;
				this.filterTimer = this._delay( function() {
					delete this.previousFilter;
				}, 1000 );
			} else {
				delete this.previousFilter;
			}
		}

		if ( preventDefault ) {
			event.preventDefault();
		}
	},

	_activate: function( event ) {
		if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
			if ( this.active.children( "[aria-haspopup='true']" ).length ) {
				this.expand( event );
			} else {
				this.select( event );
			}
		}
	},

	refresh: function() {
		var menus, items, newSubmenus, newItems, newWrappers,
			that = this,
			icon = this.options.icons.submenu,
			submenus = this.element.find( this.options.menus );

		this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );

		// Initialize nested menus
		newSubmenus = submenus.filter( ":not(.ui-menu)" )
			.hide()
			.attr( {
				role: this.options.role,
				"aria-hidden": "true",
				"aria-expanded": "false"
			} )
			.each( function() {
				var menu = $( this ),
					item = menu.prev(),
					submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );

				that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
				item
					.attr( "aria-haspopup", "true" )
					.prepend( submenuCaret );
				menu.attr( "aria-labelledby", item.attr( "id" ) );
			} );

		this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );

		menus = submenus.add( this.element );
		items = menus.find( this.options.items );

		// Initialize menu-items containing spaces and/or dashes only as dividers
		items.not( ".ui-menu-item" ).each( function() {
			var item = $( this );
			if ( that._isDivider( item ) ) {
				that._addClass( item, "ui-menu-divider", "ui-widget-content" );
			}
		} );

		// Don't refresh list items that are already adapted
		newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
		newWrappers = newItems.children()
			.not( ".ui-menu" )
				.uniqueId()
				.attr( {
					tabIndex: -1,
					role: this._itemRole()
				} );
		this._addClass( newItems, "ui-menu-item" )
			._addClass( newWrappers, "ui-menu-item-wrapper" );

		// Add aria-disabled attribute to any disabled menu item
		items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );

		// If the active item has been removed, blur the menu
		if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
			this.blur();
		}
	},

	_itemRole: function() {
		return {
			menu: "menuitem",
			listbox: "option"
		}[ this.options.role ];
	},

	_setOption: function( key, value ) {
		if ( key === "icons" ) {
			var icons = this.element.find( ".ui-menu-icon" );
			this._removeClass( icons, null, this.options.icons.submenu )
				._addClass( icons, null, value.submenu );
		}
		this._super( key, value );
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this.element.attr( "aria-disabled", String( value ) );
		this._toggleClass( null, "ui-state-disabled", !!value );
	},

	focus: function( event, item ) {
		var nested, focused, activeParent;
		this.blur( event, event && event.type === "focus" );

		this._scrollIntoView( item );

		this.active = item.first();

		focused = this.active.children( ".ui-menu-item-wrapper" );
		this._addClass( focused, null, "ui-state-active" );

		// Only update aria-activedescendant if there's a role
		// otherwise we assume focus is managed elsewhere
		if ( this.options.role ) {
			this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
		}

		// Highlight active parent menu item, if any
		activeParent = this.active
			.parent()
				.closest( ".ui-menu-item" )
					.children( ".ui-menu-item-wrapper" );
		this._addClass( activeParent, null, "ui-state-active" );

		if ( event && event.type === "keydown" ) {
			this._close();
		} else {
			this.timer = this._delay( function() {
				this._close();
			}, this.delay );
		}

		nested = item.children( ".ui-menu" );
		if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
			this._startOpening( nested );
		}
		this.activeMenu = item.parent();

		this._trigger( "focus", event, { item: item } );
	},

	_scrollIntoView: function( item ) {
		var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
		if ( this._hasScroll() ) {
			borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
			paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
			offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
			scroll = this.activeMenu.scrollTop();
			elementHeight = this.activeMenu.height();
			itemHeight = item.outerHeight();

			if ( offset < 0 ) {
				this.activeMenu.scrollTop( scroll + offset );
			} else if ( offset + itemHeight > elementHeight ) {
				this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
			}
		}
	},

	blur: function( event, fromFocus ) {
		if ( !fromFocus ) {
			clearTimeout( this.timer );
		}

		if ( !this.active ) {
			return;
		}

		this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
			null, "ui-state-active" );

		this._trigger( "blur", event, { item: this.active } );
		this.active = null;
	},

	_startOpening: function( submenu ) {
		clearTimeout( this.timer );

		// Don't open if already open fixes a Firefox bug that caused a .5 pixel
		// shift in the submenu position when mousing over the caret icon
		if ( submenu.attr( "aria-hidden" ) !== "true" ) {
			return;
		}

		this.timer = this._delay( function() {
			this._close();
			this._open( submenu );
		}, this.delay );
	},

	_open: function( submenu ) {
		var position = $.extend( {
			of: this.active
		}, this.options.position );

		clearTimeout( this.timer );
		this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
			.hide()
			.attr( "aria-hidden", "true" );

		submenu
			.show()
			.removeAttr( "aria-hidden" )
			.attr( "aria-expanded", "true" )
			.position( position );
	},

	collapseAll: function( event, all ) {
		clearTimeout( this.timer );
		this.timer = this._delay( function() {

			// If we were passed an event, look for the submenu that contains the event
			var currentMenu = all ? this.element :
				$( event && event.target ).closest( this.element.find( ".ui-menu" ) );

			// If we found no valid submenu ancestor, use the main menu to close all
			// sub menus anyway
			if ( !currentMenu.length ) {
				currentMenu = this.element;
			}

			this._close( currentMenu );

			this.blur( event );

			// Work around active item staying active after menu is blurred
			this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );

			this.activeMenu = currentMenu;
		}, this.delay );
	},

	// With no arguments, closes the currently active menu - if nothing is active
	// it closes all menus.  If passed an argument, it will search for menus BELOW
	_close: function( startMenu ) {
		if ( !startMenu ) {
			startMenu = this.active ? this.active.parent() : this.element;
		}

		startMenu.find( ".ui-menu" )
			.hide()
			.attr( "aria-hidden", "true" )
			.attr( "aria-expanded", "false" );
	},

	_closeOnDocumentClick: function( event ) {
		return !$( event.target ).closest( ".ui-menu" ).length;
	},

	_isDivider: function( item ) {

		// Match hyphen, em dash, en dash
		return !/[^\-\u2014\u2013\s]/.test( item.text() );
	},

	collapse: function( event ) {
		var newItem = this.active &&
			this.active.parent().closest( ".ui-menu-item", this.element );
		if ( newItem && newItem.length ) {
			this._close();
			this.focus( event, newItem );
		}
	},

	expand: function( event ) {
		var newItem = this.active &&
			this.active
				.children( ".ui-menu " )
					.find( this.options.items )
						.first();

		if ( newItem && newItem.length ) {
			this._open( newItem.parent() );

			// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
			this._delay( function() {
				this.focus( event, newItem );
			} );
		}
	},

	next: function( event ) {
		this._move( "next", "first", event );
	},

	previous: function( event ) {
		this._move( "prev", "last", event );
	},

	isFirstItem: function() {
		return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
	},

	isLastItem: function() {
		return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
	},

	_move: function( direction, filter, event ) {
		var next;
		if ( this.active ) {
			if ( direction === "first" || direction === "last" ) {
				next = this.active
					[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
					.eq( -1 );
			} else {
				next = this.active
					[ direction + "All" ]( ".ui-menu-item" )
					.eq( 0 );
			}
		}
		if ( !next || !next.length || !this.active ) {
			next = this.activeMenu.find( this.options.items )[ filter ]();
		}

		this.focus( event, next );
	},

	nextPage: function( event ) {
		var item, base, height;

		if ( !this.active ) {
			this.next( event );
			return;
		}
		if ( this.isLastItem() ) {
			return;
		}
		if ( this._hasScroll() ) {
			base = this.active.offset().top;
			height = this.element.height();
			this.active.nextAll( ".ui-menu-item" ).each( function() {
				item = $( this );
				return item.offset().top - base - height < 0;
			} );

			this.focus( event, item );
		} else {
			this.focus( event, this.activeMenu.find( this.options.items )
				[ !this.active ? "first" : "last" ]() );
		}
	},

	previousPage: function( event ) {
		var item, base, height;
		if ( !this.active ) {
			this.next( event );
			return;
		}
		if ( this.isFirstItem() ) {
			return;
		}
		if ( this._hasScroll() ) {
			base = this.active.offset().top;
			height = this.element.height();
			this.active.prevAll( ".ui-menu-item" ).each( function() {
				item = $( this );
				return item.offset().top - base + height > 0;
			} );

			this.focus( event, item );
		} else {
			this.focus( event, this.activeMenu.find( this.options.items ).first() );
		}
	},

	_hasScroll: function() {
		return this.element.outerHeight() < this.element.prop( "scrollHeight" );
	},

	select: function( event ) {

		// TODO: It should never be possible to not have an active item at this
		// point, but the tests don't trigger mouseenter before click.
		this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
		var ui = { item: this.active };
		if ( !this.active.has( ".ui-menu" ).length ) {
			this.collapseAll( event, true );
		}
		this._trigger( "select", event, ui );
	},

	_filterMenuItems: function( character ) {
		var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
			regex = new RegExp( "^" + escapedCharacter, "i" );

		return this.activeMenu
			.find( this.options.items )

				// Only match on items, not dividers or other content (#10571)
				.filter( ".ui-menu-item" )
					.filter( function() {
						return regex.test(
							$.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
					} );
	}
} );


/*!
 * jQuery UI Autocomplete 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Autocomplete
//>>group: Widgets
//>>description: Lists suggested words as the user is typing.
//>>docs: http://api.jqueryui.com/autocomplete/
//>>demos: http://jqueryui.com/autocomplete/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/autocomplete.css
//>>css.theme: ../../themes/base/theme.css



$.widget( "ui.autocomplete", {
	version: "1.12.1",
	defaultElement: "<input>",
	options: {
		appendTo: null,
		autoFocus: false,
		delay: 300,
		minLength: 1,
		position: {
			my: "left top",
			at: "left bottom",
			collision: "none"
		},
		source: null,

		// Callbacks
		change: null,
		close: null,
		focus: null,
		open: null,
		response: null,
		search: null,
		select: null
	},

	requestIndex: 0,
	pending: 0,

	_create: function() {

		// Some browsers only repeat keydown events, not keypress events,
		// so we use the suppressKeyPress flag to determine if we've already
		// handled the keydown event. #7269
		// Unfortunately the code for & in keypress is the same as the up arrow,
		// so we use the suppressKeyPressRepeat flag to avoid handling keypress
		// events when we know the keydown event was used to modify the
		// search term. #7799
		var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
			nodeName = this.element[ 0 ].nodeName.toLowerCase(),
			isTextarea = nodeName === "textarea",
			isInput = nodeName === "input";

		// Textareas are always multi-line
		// Inputs are always single-line, even if inside a contentEditable element
		// IE also treats inputs as contentEditable
		// All other element types are determined by whether or not they're contentEditable
		this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );

		this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
		this.isNewMenu = true;

		this._addClass( "ui-autocomplete-input" );
		this.element.attr( "autocomplete", "off" );

		this._on( this.element, {
			keydown: function( event ) {
				if ( this.element.prop( "readOnly" ) ) {
					suppressKeyPress = true;
					suppressInput = true;
					suppressKeyPressRepeat = true;
					return;
				}

				suppressKeyPress = false;
				suppressInput = false;
				suppressKeyPressRepeat = false;
				var keyCode = $.ui.keyCode;
				switch ( event.keyCode ) {
				case keyCode.PAGE_UP:
					suppressKeyPress = true;
					this._move( "previousPage", event );
					break;
				case keyCode.PAGE_DOWN:
					suppressKeyPress = true;
					this._move( "nextPage", event );
					break;
				case keyCode.UP:
					suppressKeyPress = true;
					this._keyEvent( "previous", event );
					break;
				case keyCode.DOWN:
					suppressKeyPress = true;
					this._keyEvent( "next", event );
					break;
				case keyCode.ENTER:

					// when menu is open and has focus
					if ( this.menu.active ) {

						// #6055 - Opera still allows the keypress to occur
						// which causes forms to submit
						suppressKeyPress = true;
						event.preventDefault();
						this.menu.select( event );
					}
					break;
				case keyCode.TAB:
					if ( this.menu.active ) {
						this.menu.select( event );
					}
					break;
				case keyCode.ESCAPE:
					if ( this.menu.element.is( ":visible" ) ) {
						if ( !this.isMultiLine ) {
							this._value( this.term );
						}
						this.close( event );

						// Different browsers have different default behavior for escape
						// Single press can mean undo or clear
						// Double press in IE means clear the whole form
						event.preventDefault();
					}
					break;
				default:
					suppressKeyPressRepeat = true;

					// search timeout should be triggered before the input value is changed
					this._searchTimeout( event );
					break;
				}
			},
			keypress: function( event ) {
				if ( suppressKeyPress ) {
					suppressKeyPress = false;
					if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
						event.preventDefault();
					}
					return;
				}
				if ( suppressKeyPressRepeat ) {
					return;
				}

				// Replicate some key handlers to allow them to repeat in Firefox and Opera
				var keyCode = $.ui.keyCode;
				switch ( event.keyCode ) {
				case keyCode.PAGE_UP:
					this._move( "previousPage", event );
					break;
				case keyCode.PAGE_DOWN:
					this._move( "nextPage", event );
					break;
				case keyCode.UP:
					this._keyEvent( "previous", event );
					break;
				case keyCode.DOWN:
					this._keyEvent( "next", event );
					break;
				}
			},
			input: function( event ) {
				if ( suppressInput ) {
					suppressInput = false;
					event.preventDefault();
					return;
				}
				this._searchTimeout( event );
			},
			focus: function() {
				this.selectedItem = null;
				this.previous = this._value();
			},
			blur: function( event ) {
				if ( this.cancelBlur ) {
					delete this.cancelBlur;
					return;
				}

				clearTimeout( this.searching );
				this.close( event );
				this._change( event );
			}
		} );

		this._initSource();
		this.menu = $( "<ul>" )
			.appendTo( this._appendTo() )
			.menu( {

				// disable ARIA support, the live region takes care of that
				role: null
			} )
			.hide()
			.menu( "instance" );

		this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
		this._on( this.menu.element, {
			mousedown: function( event ) {

				// prevent moving focus out of the text field
				event.preventDefault();

				// IE doesn't prevent moving focus even with event.preventDefault()
				// so we set a flag to know when we should ignore the blur event
				this.cancelBlur = true;
				this._delay( function() {
					delete this.cancelBlur;

					// Support: IE 8 only
					// Right clicking a menu item or selecting text from the menu items will
					// result in focus moving out of the input. However, we've already received
					// and ignored the blur event because of the cancelBlur flag set above. So
					// we restore focus to ensure that the menu closes properly based on the user's
					// next actions.
					if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
						this.element.trigger( "focus" );
					}
				} );
			},
			menufocus: function( event, ui ) {
				var label, item;

				// support: Firefox
				// Prevent accidental activation of menu items in Firefox (#7024 #9118)
				if ( this.isNewMenu ) {
					this.isNewMenu = false;
					if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
						this.menu.blur();

						this.document.one( "mousemove", function() {
							$( event.target ).trigger( event.originalEvent );
						} );

						return;
					}
				}

				item = ui.item.data( "ui-autocomplete-item" );
				if ( false !== this._trigger( "focus", event, { item: item } ) ) {

					// use value to match what will end up in the input, if it was a key event
					if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
						this._value( item.value );
					}
				}

				// Announce the value in the liveRegion
				label = ui.item.attr( "aria-label" ) || item.value;
				if ( label && $.trim( label ).length ) {
					this.liveRegion.children().hide();
					$( "<div>" ).text( label ).appendTo( this.liveRegion );
				}
			},
			menuselect: function( event, ui ) {
				var item = ui.item.data( "ui-autocomplete-item" ),
					previous = this.previous;

				// Only trigger when focus was lost (click on menu)
				if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
					this.element.trigger( "focus" );
					this.previous = previous;

					// #6109 - IE triggers two focus events and the second
					// is asynchronous, so we need to reset the previous
					// term synchronously and asynchronously :-(
					this._delay( function() {
						this.previous = previous;
						this.selectedItem = item;
					} );
				}

				if ( false !== this._trigger( "select", event, { item: item } ) ) {
					this._value( item.value );
				}

				// reset the term after the select event
				// this allows custom select handling to work properly
				this.term = this._value();

				this.close( event );
				this.selectedItem = item;
			}
		} );

		this.liveRegion = $( "<div>", {
			role: "status",
			"aria-live": "assertive",
			"aria-relevant": "additions"
		} )
			.appendTo( this.document[ 0 ].body );

		this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );

		// Turning off autocomplete prevents the browser from remembering the
		// value when navigating through history, so we re-enable autocomplete
		// if the page is unloaded before the widget is destroyed. #7790
		this._on( this.window, {
			beforeunload: function() {
				this.element.removeAttr( "autocomplete" );
			}
		} );
	},

	_destroy: function() {
		clearTimeout( this.searching );
		this.element.removeAttr( "autocomplete" );
		this.menu.element.remove();
		this.liveRegion.remove();
	},

	_setOption: function( key, value ) {
		this._super( key, value );
		if ( key === "source" ) {
			this._initSource();
		}
		if ( key === "appendTo" ) {
			this.menu.element.appendTo( this._appendTo() );
		}
		if ( key === "disabled" && value && this.xhr ) {
			this.xhr.abort();
		}
	},

	_isEventTargetInWidget: function( event ) {
		var menuElement = this.menu.element[ 0 ];

		return event.target === this.element[ 0 ] ||
			event.target === menuElement ||
			$.contains( menuElement, event.target );
	},

	_closeOnClickOutside: function( event ) {
		if ( !this._isEventTargetInWidget( event ) ) {
			this.close();
		}
	},

	_appendTo: function() {
		var element = this.options.appendTo;

		if ( element ) {
			element = element.jquery || element.nodeType ?
				$( element ) :
				this.document.find( element ).eq( 0 );
		}

		if ( !element || !element[ 0 ] ) {
			element = this.element.closest( ".ui-front, dialog" );
		}

		if ( !element.length ) {
			element = this.document[ 0 ].body;
		}

		return element;
	},

	_initSource: function() {
		var array, url,
			that = this;
		if ( $.isArray( this.options.source ) ) {
			array = this.options.source;
			this.source = function( request, response ) {
				response( $.ui.autocomplete.filter( array, request.term ) );
			};
		} else if ( typeof this.options.source === "string" ) {
			url = this.options.source;
			this.source = function( request, response ) {
				if ( that.xhr ) {
					that.xhr.abort();
				}
				that.xhr = $.ajax( {
					url: url,
					data: request,
					dataType: "json",
					success: function( data ) {
						response( data );
					},
					error: function() {
						response( [] );
					}
				} );
			};
		} else {
			this.source = this.options.source;
		}
	},

	_searchTimeout: function( event ) {
		clearTimeout( this.searching );
		this.searching = this._delay( function() {

			// Search if the value has changed, or if the user retypes the same value (see #7434)
			var equalValues = this.term === this._value(),
				menuVisible = this.menu.element.is( ":visible" ),
				modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;

			if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
				this.selectedItem = null;
				this.search( null, event );
			}
		}, this.options.delay );
	},

	search: function( value, event ) {
		value = value != null ? value : this._value();

		// Always save the actual value, not the one passed as an argument
		this.term = this._value();

		if ( value.length < this.options.minLength ) {
			return this.close( event );
		}

		if ( this._trigger( "search", event ) === false ) {
			return;
		}

		return this._search( value );
	},

	_search: function( value ) {
		this.pending++;
		this._addClass( "ui-autocomplete-loading" );
		this.cancelSearch = false;

		this.source( { term: value }, this._response() );
	},

	_response: function() {
		var index = ++this.requestIndex;

		return $.proxy( function( content ) {
			if ( index === this.requestIndex ) {
				this.__response( content );
			}

			this.pending--;
			if ( !this.pending ) {
				this._removeClass( "ui-autocomplete-loading" );
			}
		}, this );
	},

	__response: function( content ) {
		if ( content ) {
			content = this._normalize( content );
		}
		this._trigger( "response", null, { content: content } );
		if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
			this._suggest( content );
			this._trigger( "open" );
		} else {

			// use ._close() instead of .close() so we don't cancel future searches
			this._close();
		}
	},

	close: function( event ) {
		this.cancelSearch = true;
		this._close( event );
	},

	_close: function( event ) {

		// Remove the handler that closes the menu on outside clicks
		this._off( this.document, "mousedown" );

		if ( this.menu.element.is( ":visible" ) ) {
			this.menu.element.hide();
			this.menu.blur();
			this.isNewMenu = true;
			this._trigger( "close", event );
		}
	},

	_change: function( event ) {
		if ( this.previous !== this._value() ) {
			this._trigger( "change", event, { item: this.selectedItem } );
		}
	},

	_normalize: function( items ) {

		// assume all items have the right format when the first item is complete
		if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
			return items;
		}
		return $.map( items, function( item ) {
			if ( typeof item === "string" ) {
				return {
					label: item,
					value: item
				};
			}
			return $.extend( {}, item, {
				label: item.label || item.value,
				value: item.value || item.label
			} );
		} );
	},

	_suggest: function( items ) {
		var ul = this.menu.element.empty();
		this._renderMenu( ul, items );
		this.isNewMenu = true;
		this.menu.refresh();

		// Size and position menu
		ul.show();
		this._resizeMenu();
		ul.position( $.extend( {
			of: this.element
		}, this.options.position ) );

		if ( this.options.autoFocus ) {
			this.menu.next();
		}

		// Listen for interactions outside of the widget (#6642)
		this._on( this.document, {
			mousedown: "_closeOnClickOutside"
		} );
	},

	_resizeMenu: function() {
		var ul = this.menu.element;
		ul.outerWidth( Math.max(

			// Firefox wraps long text (possibly a rounding bug)
			// so we add 1px to avoid the wrapping (#7513)
			ul.width( "" ).outerWidth() + 1,
			this.element.outerWidth()
		) );
	},

	_renderMenu: function( ul, items ) {
		var that = this;
		$.each( items, function( index, item ) {
			that._renderItemData( ul, item );
		} );
	},

	_renderItemData: function( ul, item ) {
		return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
	},

	_renderItem: function( ul, item ) {
		return $( "<li>" )
			.append( $( "<div>" ).text( item.label ) )
			.appendTo( ul );
	},

	_move: function( direction, event ) {
		if ( !this.menu.element.is( ":visible" ) ) {
			this.search( null, event );
			return;
		}
		if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
				this.menu.isLastItem() && /^next/.test( direction ) ) {

			if ( !this.isMultiLine ) {
				this._value( this.term );
			}

			this.menu.blur();
			return;
		}
		this.menu[ direction ]( event );
	},

	widget: function() {
		return this.menu.element;
	},

	_value: function() {
		return this.valueMethod.apply( this.element, arguments );
	},

	_keyEvent: function( keyEvent, event ) {
		if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
			this._move( keyEvent, event );

			// Prevents moving cursor to beginning/end of the text field in some browsers
			event.preventDefault();
		}
	},

	// Support: Chrome <=50
	// We should be able to just use this.element.prop( "isContentEditable" )
	// but hidden elements always report false in Chrome.
	// https://code.google.com/p/chromium/issues/detail?id=313082
	_isContentEditable: function( element ) {
		if ( !element.length ) {
			return false;
		}

		var editable = element.prop( "contentEditable" );

		if ( editable === "inherit" ) {
		  return this._isContentEditable( element.parent() );
		}

		return editable === "true";
	}
} );

$.extend( $.ui.autocomplete, {
	escapeRegex: function( value ) {
		return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
	},
	filter: function( array, term ) {
		var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
		return $.grep( array, function( value ) {
			return matcher.test( value.label || value.value || value );
		} );
	}
} );

// Live region extension, adding a `messages` option
// NOTE: This is an experimental API. We are still investigating
// a full solution for string manipulation and internationalization.
$.widget( "ui.autocomplete", $.ui.autocomplete, {
	options: {
		messages: {
			noResults: "No search results.",
			results: function( amount ) {
				return amount + ( amount > 1 ? " results are" : " result is" ) +
					" available, use up and down arrow keys to navigate.";
			}
		}
	},

	__response: function( content ) {
		var message;
		this._superApply( arguments );
		if ( this.options.disabled || this.cancelSearch ) {
			return;
		}
		if ( content && content.length ) {
			message = this.options.messages.results( content.length );
		} else {
			message = this.options.messages.noResults;
		}
		this.liveRegion.children().hide();
		$( "<div>" ).text( message ).appendTo( this.liveRegion );
	}
} );

var widgetsAutocomplete = $.ui.autocomplete;


/*!
 * jQuery UI Controlgroup 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Controlgroup
//>>group: Widgets
//>>description: Visually groups form control widgets
//>>docs: http://api.jqueryui.com/controlgroup/
//>>demos: http://jqueryui.com/controlgroup/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/controlgroup.css
//>>css.theme: ../../themes/base/theme.css


var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;

var widgetsControlgroup = $.widget( "ui.controlgroup", {
	version: "1.12.1",
	defaultElement: "<div>",
	options: {
		direction: "horizontal",
		disabled: null,
		onlyVisible: true,
		items: {
			"button": "input[type=button], input[type=submit], input[type=reset], button, a",
			"controlgroupLabel": ".ui-controlgroup-label",
			"checkboxradio": "input[type='checkbox'], input[type='radio']",
			"selectmenu": "select",
			"spinner": ".ui-spinner-input"
		}
	},

	_create: function() {
		this._enhance();
	},

	// To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
	_enhance: function() {
		this.element.attr( "role", "toolbar" );
		this.refresh();
	},

	_destroy: function() {
		this._callChildMethod( "destroy" );
		this.childWidgets.removeData( "ui-controlgroup-data" );
		this.element.removeAttr( "role" );
		if ( this.options.items.controlgroupLabel ) {
			this.element
				.find( this.options.items.controlgroupLabel )
				.find( ".ui-controlgroup-label-contents" )
				.contents().unwrap();
		}
	},

	_initWidgets: function() {
		var that = this,
			childWidgets = [];

		// First we iterate over each of the items options
		$.each( this.options.items, function( widget, selector ) {
			var labels;
			var options = {};

			// Make sure the widget has a selector set
			if ( !selector ) {
				return;
			}

			if ( widget === "controlgroupLabel" ) {
				labels = that.element.find( selector );
				labels.each( function() {
					var element = $( this );

					if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
						return;
					}
					element.contents()
						.wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
				} );
				that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
				childWidgets = childWidgets.concat( labels.get() );
				return;
			}

			// Make sure the widget actually exists
			if ( !$.fn[ widget ] ) {
				return;
			}

			// We assume everything is in the middle to start because we can't determine
			// first / last elements until all enhancments are done.
			if ( that[ "_" + widget + "Options" ] ) {
				options = that[ "_" + widget + "Options" ]( "middle" );
			} else {
				options = { classes: {} };
			}

			// Find instances of this widget inside controlgroup and init them
			that.element
				.find( selector )
				.each( function() {
					var element = $( this );
					var instance = element[ widget ]( "instance" );

					// We need to clone the default options for this type of widget to avoid
					// polluting the variable options which has a wider scope than a single widget.
					var instanceOptions = $.widget.extend( {}, options );

					// If the button is the child of a spinner ignore it
					// TODO: Find a more generic solution
					if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
						return;
					}

					// Create the widget if it doesn't exist
					if ( !instance ) {
						instance = element[ widget ]()[ widget ]( "instance" );
					}
					if ( instance ) {
						instanceOptions.classes =
							that._resolveClassesValues( instanceOptions.classes, instance );
					}
					element[ widget ]( instanceOptions );

					// Store an instance of the controlgroup to be able to reference
					// from the outermost element for changing options and refresh
					var widgetElement = element[ widget ]( "widget" );
					$.data( widgetElement[ 0 ], "ui-controlgroup-data",
						instance ? instance : element[ widget ]( "instance" ) );

					childWidgets.push( widgetElement[ 0 ] );
				} );
		} );

		this.childWidgets = $( $.unique( childWidgets ) );
		this._addClass( this.childWidgets, "ui-controlgroup-item" );
	},

	_callChildMethod: function( method ) {
		this.childWidgets.each( function() {
			var element = $( this ),
				data = element.data( "ui-controlgroup-data" );
			if ( data && data[ method ] ) {
				data[ method ]();
			}
		} );
	},

	_updateCornerClass: function( element, position ) {
		var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
		var add = this._buildSimpleOptions( position, "label" ).classes.label;

		this._removeClass( element, null, remove );
		this._addClass( element, null, add );
	},

	_buildSimpleOptions: function( position, key ) {
		var direction = this.options.direction === "vertical";
		var result = {
			classes: {}
		};
		result.classes[ key ] = {
			"middle": "",
			"first": "ui-corner-" + ( direction ? "top" : "left" ),
			"last": "ui-corner-" + ( direction ? "bottom" : "right" ),
			"only": "ui-corner-all"
		}[ position ];

		return result;
	},

	_spinnerOptions: function( position ) {
		var options = this._buildSimpleOptions( position, "ui-spinner" );

		options.classes[ "ui-spinner-up" ] = "";
		options.classes[ "ui-spinner-down" ] = "";

		return options;
	},

	_buttonOptions: function( position ) {
		return this._buildSimpleOptions( position, "ui-button" );
	},

	_checkboxradioOptions: function( position ) {
		return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
	},

	_selectmenuOptions: function( position ) {
		var direction = this.options.direction === "vertical";
		return {
			width: direction ? "auto" : false,
			classes: {
				middle: {
					"ui-selectmenu-button-open": "",
					"ui-selectmenu-button-closed": ""
				},
				first: {
					"ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
				},
				last: {
					"ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
				},
				only: {
					"ui-selectmenu-button-open": "ui-corner-top",
					"ui-selectmenu-button-closed": "ui-corner-all"
				}

			}[ position ]
		};
	},

	_resolveClassesValues: function( classes, instance ) {
		var result = {};
		$.each( classes, function( key ) {
			var current = instance.options.classes[ key ] || "";
			current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
			result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
		} );
		return result;
	},

	_setOption: function( key, value ) {
		if ( key === "direction" ) {
			this._removeClass( "ui-controlgroup-" + this.options.direction );
		}

		this._super( key, value );
		if ( key === "disabled" ) {
			this._callChildMethod( value ? "disable" : "enable" );
			return;
		}

		this.refresh();
	},

	refresh: function() {
		var children,
			that = this;

		this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );

		if ( this.options.direction === "horizontal" ) {
			this._addClass( null, "ui-helper-clearfix" );
		}
		this._initWidgets();

		children = this.childWidgets;

		// We filter here because we need to track all childWidgets not just the visible ones
		if ( this.options.onlyVisible ) {
			children = children.filter( ":visible" );
		}

		if ( children.length ) {

			// We do this last because we need to make sure all enhancment is done
			// before determining first and last
			$.each( [ "first", "last" ], function( index, value ) {
				var instance = children[ value ]().data( "ui-controlgroup-data" );

				if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
					var options = that[ "_" + instance.widgetName + "Options" ](
						children.length === 1 ? "only" : value
					);
					options.classes = that._resolveClassesValues( options.classes, instance );
					instance.element[ instance.widgetName ]( options );
				} else {
					that._updateCornerClass( children[ value ](), value );
				}
			} );

			// Finally call the refresh method on each of the child widgets.
			this._callChildMethod( "refresh" );
		}
	}
} );

/*!
 * jQuery UI Checkboxradio 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Checkboxradio
//>>group: Widgets
//>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
//>>docs: http://api.jqueryui.com/checkboxradio/
//>>demos: http://jqueryui.com/checkboxradio/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/button.css
//>>css.structure: ../../themes/base/checkboxradio.css
//>>css.theme: ../../themes/base/theme.css



$.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
	version: "1.12.1",
	options: {
		disabled: null,
		label: null,
		icon: true,
		classes: {
			"ui-checkboxradio-label": "ui-corner-all",
			"ui-checkboxradio-icon": "ui-corner-all"
		}
	},

	_getCreateOptions: function() {
		var disabled, labels;
		var that = this;
		var options = this._super() || {};

		// We read the type here, because it makes more sense to throw a element type error first,
		// rather then the error for lack of a label. Often if its the wrong type, it
		// won't have a label (e.g. calling on a div, btn, etc)
		this._readType();

		labels = this.element.labels();

		// If there are multiple labels, use the last one
		this.label = $( labels[ labels.length - 1 ] );
		if ( !this.label.length ) {
			$.error( "No label found for checkboxradio widget" );
		}

		this.originalLabel = "";

		// We need to get the label text but this may also need to make sure it does not contain the
		// input itself.
		this.label.contents().not( this.element[ 0 ] ).each( function() {

			// The label contents could be text, html, or a mix. We concat each element to get a
			// string representation of the label, without the input as part of it.
			that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
		} );

		// Set the label option if we found label text
		if ( this.originalLabel ) {
			options.label = this.originalLabel;
		}

		disabled = this.element[ 0 ].disabled;
		if ( disabled != null ) {
			options.disabled = disabled;
		}
		return options;
	},

	_create: function() {
		var checked = this.element[ 0 ].checked;

		this._bindFormResetHandler();

		if ( this.options.disabled == null ) {
			this.options.disabled = this.element[ 0 ].disabled;
		}

		this._setOption( "disabled", this.options.disabled );
		this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
		this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );

		if ( this.type === "radio" ) {
			this._addClass( this.label, "ui-checkboxradio-radio-label" );
		}

		if ( this.options.label && this.options.label !== this.originalLabel ) {
			this._updateLabel();
		} else if ( this.originalLabel ) {
			this.options.label = this.originalLabel;
		}

		this._enhance();

		if ( checked ) {
			this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
			if ( this.icon ) {
				this._addClass( this.icon, null, "ui-state-hover" );
			}
		}

		this._on( {
			change: "_toggleClasses",
			focus: function() {
				this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
			},
			blur: function() {
				this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
			}
		} );
	},

	_readType: function() {
		var nodeName = this.element[ 0 ].nodeName.toLowerCase();
		this.type = this.element[ 0 ].type;
		if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
			$.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
				" and element.type=" + this.type );
		}
	},

	// Support jQuery Mobile enhanced option
	_enhance: function() {
		this._updateIcon( this.element[ 0 ].checked );
	},

	widget: function() {
		return this.label;
	},

	_getRadioGroup: function() {
		var group;
		var name = this.element[ 0 ].name;
		var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";

		if ( !name ) {
			return $( [] );
		}

		if ( this.form.length ) {
			group = $( this.form[ 0 ].elements ).filter( nameSelector );
		} else {

			// Not inside a form, check all inputs that also are not inside a form
			group = $( nameSelector ).filter( function() {
				return $( this ).form().length === 0;
			} );
		}

		return group.not( this.element );
	},

	_toggleClasses: function() {
		var checked = this.element[ 0 ].checked;
		this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );

		if ( this.options.icon && this.type === "checkbox" ) {
			this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
				._toggleClass( this.icon, null, "ui-icon-blank", !checked );
		}

		if ( this.type === "radio" ) {
			this._getRadioGroup()
				.each( function() {
					var instance = $( this ).checkboxradio( "instance" );

					if ( instance ) {
						instance._removeClass( instance.label,
							"ui-checkboxradio-checked", "ui-state-active" );
					}
				} );
		}
	},

	_destroy: function() {
		this._unbindFormResetHandler();

		if ( this.icon ) {
			this.icon.remove();
			this.iconSpace.remove();
		}
	},

	_setOption: function( key, value ) {

		// We don't allow the value to be set to nothing
		if ( key === "label" && !value ) {
			return;
		}

		this._super( key, value );

		if ( key === "disabled" ) {
			this._toggleClass( this.label, null, "ui-state-disabled", value );
			this.element[ 0 ].disabled = value;

			// Don't refresh when setting disabled
			return;
		}
		this.refresh();
	},

	_updateIcon: function( checked ) {
		var toAdd = "ui-icon ui-icon-background ";

		if ( this.options.icon ) {
			if ( !this.icon ) {
				this.icon = $( "<span>" );
				this.iconSpace = $( "<span> </span>" );
				this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
			}

			if ( this.type === "checkbox" ) {
				toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
				this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
			} else {
				toAdd += "ui-icon-blank";
			}
			this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
			if ( !checked ) {
				this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
			}
			this.icon.prependTo( this.label ).after( this.iconSpace );
		} else if ( this.icon !== undefined ) {
			this.icon.remove();
			this.iconSpace.remove();
			delete this.icon;
		}
	},

	_updateLabel: function() {

		// Remove the contents of the label ( minus the icon, icon space, and input )
		var contents = this.label.contents().not( this.element[ 0 ] );
		if ( this.icon ) {
			contents = contents.not( this.icon[ 0 ] );
		}
		if ( this.iconSpace ) {
			contents = contents.not( this.iconSpace[ 0 ] );
		}
		contents.remove();

		this.label.append( this.options.label );
	},

	refresh: function() {
		var checked = this.element[ 0 ].checked,
			isDisabled = this.element[ 0 ].disabled;

		this._updateIcon( checked );
		this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
		if ( this.options.label !== null ) {
			this._updateLabel();
		}

		if ( isDisabled !== this.options.disabled ) {
			this._setOptions( { "disabled": isDisabled } );
		}
	}

} ] );

var widgetsCheckboxradio = $.ui.checkboxradio;


/*!
 * jQuery UI Button 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Button
//>>group: Widgets
//>>description: Enhances a form with themeable buttons.
//>>docs: http://api.jqueryui.com/button/
//>>demos: http://jqueryui.com/button/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/button.css
//>>css.theme: ../../themes/base/theme.css



$.widget( "ui.button", {
	version: "1.12.1",
	defaultElement: "<button>",
	options: {
		classes: {
			"ui-button": "ui-corner-all"
		},
		disabled: null,
		icon: null,
		iconPosition: "beginning",
		label: null,
		showLabel: true
	},

	_getCreateOptions: function() {
		var disabled,

			// This is to support cases like in jQuery Mobile where the base widget does have
			// an implementation of _getCreateOptions
			options = this._super() || {};

		this.isInput = this.element.is( "input" );

		disabled = this.element[ 0 ].disabled;
		if ( disabled != null ) {
			options.disabled = disabled;
		}

		this.originalLabel = this.isInput ? this.element.val() : this.element.html();
		if ( this.originalLabel ) {
			options.label = this.originalLabel;
		}

		return options;
	},

	_create: function() {
		if ( !this.option.showLabel & !this.options.icon ) {
			this.options.showLabel = true;
		}

		// We have to check the option again here even though we did in _getCreateOptions,
		// because null may have been passed on init which would override what was set in
		// _getCreateOptions
		if ( this.options.disabled == null ) {
			this.options.disabled = this.element[ 0 ].disabled || false;
		}

		this.hasTitle = !!this.element.attr( "title" );

		// Check to see if the label needs to be set or if its already correct
		if ( this.options.label && this.options.label !== this.originalLabel ) {
			if ( this.isInput ) {
				this.element.val( this.options.label );
			} else {
				this.element.html( this.options.label );
			}
		}
		this._addClass( "ui-button", "ui-widget" );
		this._setOption( "disabled", this.options.disabled );
		this._enhance();

		if ( this.element.is( "a" ) ) {
			this._on( {
				"keyup": function( event ) {
					if ( event.keyCode === $.ui.keyCode.SPACE ) {
						event.preventDefault();

						// Support: PhantomJS <= 1.9, IE 8 Only
						// If a native click is available use it so we actually cause navigation
						// otherwise just trigger a click event
						if ( this.element[ 0 ].click ) {
							this.element[ 0 ].click();
						} else {
							this.element.trigger( "click" );
						}
					}
				}
			} );
		}
	},

	_enhance: function() {
		if ( !this.element.is( "button" ) ) {
			this.element.attr( "role", "button" );
		}

		if ( this.options.icon ) {
			this._updateIcon( "icon", this.options.icon );
			this._updateTooltip();
		}
	},

	_updateTooltip: function() {
		this.title = this.element.attr( "title" );

		if ( !this.options.showLabel && !this.title ) {
			this.element.attr( "title", this.options.label );
		}
	},

	_updateIcon: function( option, value ) {
		var icon = option !== "iconPosition",
			position = icon ? this.options.iconPosition : value,
			displayBlock = position === "top" || position === "bottom";

		// Create icon
		if ( !this.icon ) {
			this.icon = $( "<span>" );

			this._addClass( this.icon, "ui-button-icon", "ui-icon" );

			if ( !this.options.showLabel ) {
				this._addClass( "ui-button-icon-only" );
			}
		} else if ( icon ) {

			// If we are updating the icon remove the old icon class
			this._removeClass( this.icon, null, this.options.icon );
		}

		// If we are updating the icon add the new icon class
		if ( icon ) {
			this._addClass( this.icon, null, value );
		}

		this._attachIcon( position );

		// If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
		// the iconSpace if there is one.
		if ( displayBlock ) {
			this._addClass( this.icon, null, "ui-widget-icon-block" );
			if ( this.iconSpace ) {
				this.iconSpace.remove();
			}
		} else {

			// Position is beginning or end so remove the ui-widget-icon-block class and add the
			// space if it does not exist
			if ( !this.iconSpace ) {
				this.iconSpace = $( "<span> </span>" );
				this._addClass( this.iconSpace, "ui-button-icon-space" );
			}
			this._removeClass( this.icon, null, "ui-wiget-icon-block" );
			this._attachIconSpace( position );
		}
	},

	_destroy: function() {
		this.element.removeAttr( "role" );

		if ( this.icon ) {
			this.icon.remove();
		}
		if ( this.iconSpace ) {
			this.iconSpace.remove();
		}
		if ( !this.hasTitle ) {
			this.element.removeAttr( "title" );
		}
	},

	_attachIconSpace: function( iconPosition ) {
		this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
	},

	_attachIcon: function( iconPosition ) {
		this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
	},

	_setOptions: function( options ) {
		var newShowLabel = options.showLabel === undefined ?
				this.options.showLabel :
				options.showLabel,
			newIcon = options.icon === undefined ? this.options.icon : options.icon;

		if ( !newShowLabel && !newIcon ) {
			options.showLabel = true;
		}
		this._super( options );
	},

	_setOption: function( key, value ) {
		if ( key === "icon" ) {
			if ( value ) {
				this._updateIcon( key, value );
			} else if ( this.icon ) {
				this.icon.remove();
				if ( this.iconSpace ) {
					this.iconSpace.remove();
				}
			}
		}

		if ( key === "iconPosition" ) {
			this._updateIcon( key, value );
		}

		// Make sure we can't end up with a button that has neither text nor icon
		if ( key === "showLabel" ) {
				this._toggleClass( "ui-button-icon-only", null, !value );
				this._updateTooltip();
		}

		if ( key === "label" ) {
			if ( this.isInput ) {
				this.element.val( value );
			} else {

				// If there is an icon, append it, else nothing then append the value
				// this avoids removal of the icon when setting label text
				this.element.html( value );
				if ( this.icon ) {
					this._attachIcon( this.options.iconPosition );
					this._attachIconSpace( this.options.iconPosition );
				}
			}
		}

		this._super( key, value );

		if ( key === "disabled" ) {
			this._toggleClass( null, "ui-state-disabled", value );
			this.element[ 0 ].disabled = value;
			if ( value ) {
				this.element.blur();
			}
		}
	},

	refresh: function() {

		// Make sure to only check disabled if its an element that supports this otherwise
		// check for the disabled class to determine state
		var isDisabled = this.element.is( "input, button" ) ?
			this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );

		if ( isDisabled !== this.options.disabled ) {
			this._setOptions( { disabled: isDisabled } );
		}

		this._updateTooltip();
	}
} );

// DEPRECATED
if ( $.uiBackCompat !== false ) {

	// Text and Icons options
	$.widget( "ui.button", $.ui.button, {
		options: {
			text: true,
			icons: {
				primary: null,
				secondary: null
			}
		},

		_create: function() {
			if ( this.options.showLabel && !this.options.text ) {
				this.options.showLabel = this.options.text;
			}
			if ( !this.options.showLabel && this.options.text ) {
				this.options.text = this.options.showLabel;
			}
			if ( !this.options.icon && ( this.options.icons.primary ||
					this.options.icons.secondary ) ) {
				if ( this.options.icons.primary ) {
					this.options.icon = this.options.icons.primary;
				} else {
					this.options.icon = this.options.icons.secondary;
					this.options.iconPosition = "end";
				}
			} else if ( this.options.icon ) {
				this.options.icons.primary = this.options.icon;
			}
			this._super();
		},

		_setOption: function( key, value ) {
			if ( key === "text" ) {
				this._super( "showLabel", value );
				return;
			}
			if ( key === "showLabel" ) {
				this.options.text = value;
			}
			if ( key === "icon" ) {
				this.options.icons.primary = value;
			}
			if ( key === "icons" ) {
				if ( value.primary ) {
					this._super( "icon", value.primary );
					this._super( "iconPosition", "beginning" );
				} else if ( value.secondary ) {
					this._super( "icon", value.secondary );
					this._super( "iconPosition", "end" );
				}
			}
			this._superApply( arguments );
		}
	} );

	$.fn.button = ( function( orig ) {
		return function() {
			if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
					( this.length && this[ 0 ].tagName === "INPUT" && (
						this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
					) ) ) {
				return orig.apply( this, arguments );
			}
			if ( !$.ui.checkboxradio ) {
				$.error( "Checkboxradio widget missing" );
			}
			if ( arguments.length === 0 ) {
				return this.checkboxradio( {
					"icon": false
				} );
			}
			return this.checkboxradio.apply( this, arguments );
		};
	} )( $.fn.button );

	$.fn.buttonset = function() {
		if ( !$.ui.controlgroup ) {
			$.error( "Controlgroup widget missing" );
		}
		if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
			return this.controlgroup.apply( this,
				[ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
		}
		if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
			return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
		}
		if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
			arguments[ 0 ].items = {
				button: arguments[ 0 ].items
			};
		}
		return this.controlgroup.apply( this, arguments );
	};
}

var widgetsButton = $.ui.button;


// jscs:disable maximumLineLength
/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
/*!
 * jQuery UI Datepicker 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Datepicker
//>>group: Widgets
//>>description: Displays a calendar from an input or inline for selecting dates.
//>>docs: http://api.jqueryui.com/datepicker/
//>>demos: http://jqueryui.com/datepicker/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/datepicker.css
//>>css.theme: ../../themes/base/theme.css



$.extend( $.ui, { datepicker: { version: "1.12.1" } } );

var datepicker_instActive;

function datepicker_getZindex( elem ) {
	var position, value;
	while ( elem.length && elem[ 0 ] !== document ) {

		// Ignore z-index if position is set to a value where z-index is ignored by the browser
		// This makes behavior of this function consistent across browsers
		// WebKit always returns auto if the element is positioned
		position = elem.css( "position" );
		if ( position === "absolute" || position === "relative" || position === "fixed" ) {

			// IE returns 0 when zIndex is not specified
			// other browsers return a string
			// we ignore the case of nested elements with an explicit value of 0
			// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
			value = parseInt( elem.css( "zIndex" ), 10 );
			if ( !isNaN( value ) && value !== 0 ) {
				return value;
			}
		}
		elem = elem.parent();
	}

	return 0;
}
/* Date picker manager.
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
   Settings for (groups of) date pickers are maintained in an instance object,
   allowing multiple different settings on the same page. */

function Datepicker() {
	this._curInst = null; // The current instance in use
	this._keyEvent = false; // If the last event was a key event
	this._disabledInputs = []; // List of date picker inputs that have been disabled
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
	this._inDialog = false; // True if showing within a "dialog", false if not
	this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
	this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
	this._appendClass = "ui-datepicker-append"; // The name of the append marker class
	this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
	this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
	this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
	this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
	this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
	this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[ "" ] = { // Default regional settings
		closeText: "Done", // Display text for close link
		prevText: "Prev", // Display text for previous month link
		nextText: "Next", // Display text for next month link
		currentText: "Today", // Display text for current month link
		monthNames: [ "January","February","March","April","May","June",
			"July","August","September","October","November","December" ], // Names of months for drop-down and formatting
		monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
		dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
		dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
		dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
		weekHeader: "Wk", // Column header for week of the year
		dateFormat: "mm/dd/yy", // See format options on parseDate
		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
		isRTL: false, // True if right-to-left language, false if left-to-right
		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
		yearSuffix: "" // Additional text to append to the year in the month headers
	};
	this._defaults = { // Global defaults for all the date picker instances
		showOn: "focus", // "focus" for popup on focus,
			// "button" for trigger button, or "both" for either
		showAnim: "fadeIn", // Name of jQuery animation for popup
		showOptions: {}, // Options for enhanced animations
		defaultDate: null, // Used when field is blank: actual date,
			// +/-number for offset from today, null for today
		appendText: "", // Display text following the input box, e.g. showing the format
		buttonText: "...", // Text for trigger button
		buttonImage: "", // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		hideIfNoPrevNext: false, // True to hide next/previous month links
			// if not applicable, false to just disable them
		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
		gotoCurrent: false, // True if today link goes back to current selection instead
		changeMonth: false, // True if month can be selected directly, false if only prev/next
		changeYear: false, // True if year can be selected directly, false if only prev/next
		yearRange: "c-10:c+10", // Range of years to display in drop-down,
			// either relative to today's year (-nn:+nn), relative to currently displayed year
			// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
		showOtherMonths: false, // True to show dates in other months, false to leave blank
		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
		showWeek: false, // True to show week of the year, false to not show it
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
			// takes a Date and returns the number of the week for it
		shortYearCutoff: "+10", // Short year values < this are in the current century,
			// > this are in the previous century,
			// string value starting with "+" for current year + value
		minDate: null, // The earliest selectable date, or null for no limit
		maxDate: null, // The latest selectable date, or null for no limit
		duration: "fast", // Duration of display/closure
		beforeShowDay: null, // Function that takes a date and returns an array with
			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
		beforeShow: null, // Function that takes an input field and
			// returns a set of custom settings for the date picker
		onSelect: null, // Define a callback function when a date is selected
		onChangeMonthYear: null, // Define a callback function when the month or year is changed
		onClose: null, // Define a callback function when the datepicker is closed
		numberOfMonths: 1, // Number of months to show at a time
		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
		stepMonths: 1, // Number of months to step back/forward
		stepBigMonths: 12, // Number of months to step back/forward for the big links
		altField: "", // Selector for an alternate field to store selected dates into
		altFormat: "", // The date format to use for the alternate field
		constrainInput: true, // The input is constrained by the current date format
		showButtonPanel: false, // True to show button panel, false to not show it
		autoSize: false, // True to size the input for the date format, false to leave as is
		disabled: false // The initial disabled state
	};
	$.extend( this._defaults, this.regional[ "" ] );
	this.regional.en = $.extend( true, {}, this.regional[ "" ] );
	this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
	this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
}

$.extend( Datepicker.prototype, {
	/* Class name added to elements to indicate already configured with a date picker. */
	markerClassName: "hasDatepicker",

	//Keep track of the maximum number of rows displayed (see #7043)
	maxRows: 4,

	// TODO rename to "widget" when switching to widget factory
	_widgetDatepicker: function() {
		return this.dpDiv;
	},

	/* Override the default settings for all instances of the date picker.
	 * @param  settings  object - the new settings to use as defaults (anonymous object)
	 * @return the manager object
	 */
	setDefaults: function( settings ) {
		datepicker_extendRemove( this._defaults, settings || {} );
		return this;
	},

	/* Attach the date picker to a jQuery selection.
	 * @param  target	element - the target input field or division or span
	 * @param  settings  object - the new settings to use for this date picker instance (anonymous)
	 */
	_attachDatepicker: function( target, settings ) {
		var nodeName, inline, inst;
		nodeName = target.nodeName.toLowerCase();
		inline = ( nodeName === "div" || nodeName === "span" );
		if ( !target.id ) {
			this.uuid += 1;
			target.id = "dp" + this.uuid;
		}
		inst = this._newInst( $( target ), inline );
		inst.settings = $.extend( {}, settings || {} );
		if ( nodeName === "input" ) {
			this._connectDatepicker( target, inst );
		} else if ( inline ) {
			this._inlineDatepicker( target, inst );
		}
	},

	/* Create a new instance object. */
	_newInst: function( target, inline ) {
		var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
		return { id: id, input: target, // associated target
			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
			drawMonth: 0, drawYear: 0, // month being drawn
			inline: inline, // is datepicker inline or not
			dpDiv: ( !inline ? this.dpDiv : // presentation div
			datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
	},

	/* Attach the date picker to an input field. */
	_connectDatepicker: function( target, inst ) {
		var input = $( target );
		inst.append = $( [] );
		inst.trigger = $( [] );
		if ( input.hasClass( this.markerClassName ) ) {
			return;
		}
		this._attachments( input, inst );
		input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
			on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
		this._autoSize( inst );
		$.data( target, "datepicker", inst );

		//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
		if ( inst.settings.disabled ) {
			this._disableDatepicker( target );
		}
	},

	/* Make attachments based on settings. */
	_attachments: function( input, inst ) {
		var showOn, buttonText, buttonImage,
			appendText = this._get( inst, "appendText" ),
			isRTL = this._get( inst, "isRTL" );

		if ( inst.append ) {
			inst.append.remove();
		}
		if ( appendText ) {
			inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
			input[ isRTL ? "before" : "after" ]( inst.append );
		}

		input.off( "focus", this._showDatepicker );

		if ( inst.trigger ) {
			inst.trigger.remove();
		}

		showOn = this._get( inst, "showOn" );
		if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
			input.on( "focus", this._showDatepicker );
		}
		if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
			buttonText = this._get( inst, "buttonText" );
			buttonImage = this._get( inst, "buttonImage" );
			inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
				$( "<img/>" ).addClass( this._triggerClass ).
					attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
				$( "<button type='button'></button>" ).addClass( this._triggerClass ).
					html( !buttonImage ? buttonText : $( "<img/>" ).attr(
					{ src:buttonImage, alt:buttonText, title:buttonText } ) ) );
			input[ isRTL ? "before" : "after" ]( inst.trigger );
			inst.trigger.on( "click", function() {
				if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
					$.datepicker._hideDatepicker();
				} else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
					$.datepicker._hideDatepicker();
					$.datepicker._showDatepicker( input[ 0 ] );
				} else {
					$.datepicker._showDatepicker( input[ 0 ] );
				}
				return false;
			} );
		}
	},

	/* Apply the maximum length for the date format. */
	_autoSize: function( inst ) {
		if ( this._get( inst, "autoSize" ) && !inst.inline ) {
			var findMax, max, maxI, i,
				date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
				dateFormat = this._get( inst, "dateFormat" );

			if ( dateFormat.match( /[DM]/ ) ) {
				findMax = function( names ) {
					max = 0;
					maxI = 0;
					for ( i = 0; i < names.length; i++ ) {
						if ( names[ i ].length > max ) {
							max = names[ i ].length;
							maxI = i;
						}
					}
					return maxI;
				};
				date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
					"monthNames" : "monthNamesShort" ) ) ) );
				date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
					"dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
			}
			inst.input.attr( "size", this._formatDate( inst, date ).length );
		}
	},

	/* Attach an inline date picker to a div. */
	_inlineDatepicker: function( target, inst ) {
		var divSpan = $( target );
		if ( divSpan.hasClass( this.markerClassName ) ) {
			return;
		}
		divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
		$.data( target, "datepicker", inst );
		this._setDate( inst, this._getDefaultDate( inst ), true );
		this._updateDatepicker( inst );
		this._updateAlternate( inst );

		//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
		if ( inst.settings.disabled ) {
			this._disableDatepicker( target );
		}

		// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
		// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
		inst.dpDiv.css( "display", "block" );
	},

	/* Pop-up the date picker in a "dialog" box.
	 * @param  input element - ignored
	 * @param  date	string or Date - the initial date to display
	 * @param  onSelect  function - the function to call when a date is selected
	 * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
	 * @param  pos int[2] - coordinates for the dialog's position within the screen or
	 *					event - with x/y coordinates or
	 *					leave empty for default (screen centre)
	 * @return the manager object
	 */
	_dialogDatepicker: function( input, date, onSelect, settings, pos ) {
		var id, browserWidth, browserHeight, scrollX, scrollY,
			inst = this._dialogInst; // internal instance

		if ( !inst ) {
			this.uuid += 1;
			id = "dp" + this.uuid;
			this._dialogInput = $( "<input type='text' id='" + id +
				"' style='position: absolute; top: -100px; width: 0px;'/>" );
			this._dialogInput.on( "keydown", this._doKeyDown );
			$( "body" ).append( this._dialogInput );
			inst = this._dialogInst = this._newInst( this._dialogInput, false );
			inst.settings = {};
			$.data( this._dialogInput[ 0 ], "datepicker", inst );
		}
		datepicker_extendRemove( inst.settings, settings || {} );
		date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
		this._dialogInput.val( date );

		this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
		if ( !this._pos ) {
			browserWidth = document.documentElement.clientWidth;
			browserHeight = document.documentElement.clientHeight;
			scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
			scrollY = document.documentElement.scrollTop || document.body.scrollTop;
			this._pos = // should use actual width/height below
				[ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
		}

		// Move input on screen for focus, but hidden behind dialog
		this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
		inst.settings.onSelect = onSelect;
		this._inDialog = true;
		this.dpDiv.addClass( this._dialogClass );
		this._showDatepicker( this._dialogInput[ 0 ] );
		if ( $.blockUI ) {
			$.blockUI( this.dpDiv );
		}
		$.data( this._dialogInput[ 0 ], "datepicker", inst );
		return this;
	},

	/* Detach a datepicker from its control.
	 * @param  target	element - the target input field or division or span
	 */
	_destroyDatepicker: function( target ) {
		var nodeName,
			$target = $( target ),
			inst = $.data( target, "datepicker" );

		if ( !$target.hasClass( this.markerClassName ) ) {
			return;
		}

		nodeName = target.nodeName.toLowerCase();
		$.removeData( target, "datepicker" );
		if ( nodeName === "input" ) {
			inst.append.remove();
			inst.trigger.remove();
			$target.removeClass( this.markerClassName ).
				off( "focus", this._showDatepicker ).
				off( "keydown", this._doKeyDown ).
				off( "keypress", this._doKeyPress ).
				off( "keyup", this._doKeyUp );
		} else if ( nodeName === "div" || nodeName === "span" ) {
			$target.removeClass( this.markerClassName ).empty();
		}

		if ( datepicker_instActive === inst ) {
			datepicker_instActive = null;
		}
	},

	/* Enable the date picker to a jQuery selection.
	 * @param  target	element - the target input field or division or span
	 */
	_enableDatepicker: function( target ) {
		var nodeName, inline,
			$target = $( target ),
			inst = $.data( target, "datepicker" );

		if ( !$target.hasClass( this.markerClassName ) ) {
			return;
		}

		nodeName = target.nodeName.toLowerCase();
		if ( nodeName === "input" ) {
			target.disabled = false;
			inst.trigger.filter( "button" ).
				each( function() { this.disabled = false; } ).end().
				filter( "img" ).css( { opacity: "1.0", cursor: "" } );
		} else if ( nodeName === "div" || nodeName === "span" ) {
			inline = $target.children( "." + this._inlineClass );
			inline.children().removeClass( "ui-state-disabled" );
			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
				prop( "disabled", false );
		}
		this._disabledInputs = $.map( this._disabledInputs,
			function( value ) { return ( value === target ? null : value ); } ); // delete entry
	},

	/* Disable the date picker to a jQuery selection.
	 * @param  target	element - the target input field or division or span
	 */
	_disableDatepicker: function( target ) {
		var nodeName, inline,
			$target = $( target ),
			inst = $.data( target, "datepicker" );

		if ( !$target.hasClass( this.markerClassName ) ) {
			return;
		}

		nodeName = target.nodeName.toLowerCase();
		if ( nodeName === "input" ) {
			target.disabled = true;
			inst.trigger.filter( "button" ).
				each( function() { this.disabled = true; } ).end().
				filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
		} else if ( nodeName === "div" || nodeName === "span" ) {
			inline = $target.children( "." + this._inlineClass );
			inline.children().addClass( "ui-state-disabled" );
			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
				prop( "disabled", true );
		}
		this._disabledInputs = $.map( this._disabledInputs,
			function( value ) { return ( value === target ? null : value ); } ); // delete entry
		this._disabledInputs[ this._disabledInputs.length ] = target;
	},

	/* Is the first field in a jQuery collection disabled as a datepicker?
	 * @param  target	element - the target input field or division or span
	 * @return boolean - true if disabled, false if enabled
	 */
	_isDisabledDatepicker: function( target ) {
		if ( !target ) {
			return false;
		}
		for ( var i = 0; i < this._disabledInputs.length; i++ ) {
			if ( this._disabledInputs[ i ] === target ) {
				return true;
			}
		}
		return false;
	},

	/* Retrieve the instance data for the target control.
	 * @param  target  element - the target input field or division or span
	 * @return  object - the associated instance data
	 * @throws  error if a jQuery problem getting data
	 */
	_getInst: function( target ) {
		try {
			return $.data( target, "datepicker" );
		}
		catch ( err ) {
			throw "Missing instance data for this datepicker";
		}
	},

	/* Update or retrieve the settings for a date picker attached to an input field or division.
	 * @param  target  element - the target input field or division or span
	 * @param  name	object - the new settings to update or
	 *				string - the name of the setting to change or retrieve,
	 *				when retrieving also "all" for all instance settings or
	 *				"defaults" for all global defaults
	 * @param  value   any - the new value for the setting
	 *				(omit if above is an object or to retrieve a value)
	 */
	_optionDatepicker: function( target, name, value ) {
		var settings, date, minDate, maxDate,
			inst = this._getInst( target );

		if ( arguments.length === 2 && typeof name === "string" ) {
			return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
				( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
				this._get( inst, name ) ) : null ) );
		}

		settings = name || {};
		if ( typeof name === "string" ) {
			settings = {};
			settings[ name ] = value;
		}

		if ( inst ) {
			if ( this._curInst === inst ) {
				this._hideDatepicker();
			}

			date = this._getDateDatepicker( target, true );
			minDate = this._getMinMaxDate( inst, "min" );
			maxDate = this._getMinMaxDate( inst, "max" );
			datepicker_extendRemove( inst.settings, settings );

			// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
			if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
				inst.settings.minDate = this._formatDate( inst, minDate );
			}
			if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
				inst.settings.maxDate = this._formatDate( inst, maxDate );
			}
			if ( "disabled" in settings ) {
				if ( settings.disabled ) {
					this._disableDatepicker( target );
				} else {
					this._enableDatepicker( target );
				}
			}
			this._attachments( $( target ), inst );
			this._autoSize( inst );
			this._setDate( inst, date );
			this._updateAlternate( inst );
			this._updateDatepicker( inst );
		}
	},

	// Change method deprecated
	_changeDatepicker: function( target, name, value ) {
		this._optionDatepicker( target, name, value );
	},

	/* Redraw the date picker attached to an input field or division.
	 * @param  target  element - the target input field or division or span
	 */
	_refreshDatepicker: function( target ) {
		var inst = this._getInst( target );
		if ( inst ) {
			this._updateDatepicker( inst );
		}
	},

	/* Set the dates for a jQuery selection.
	 * @param  target element - the target input field or division or span
	 * @param  date	Date - the new date
	 */
	_setDateDatepicker: function( target, date ) {
		var inst = this._getInst( target );
		if ( inst ) {
			this._setDate( inst, date );
			this._updateDatepicker( inst );
			this._updateAlternate( inst );
		}
	},

	/* Get the date(s) for the first entry in a jQuery selection.
	 * @param  target element - the target input field or division or span
	 * @param  noDefault boolean - true if no default date is to be used
	 * @return Date - the current date
	 */
	_getDateDatepicker: function( target, noDefault ) {
		var inst = this._getInst( target );
		if ( inst && !inst.inline ) {
			this._setDateFromField( inst, noDefault );
		}
		return ( inst ? this._getDate( inst ) : null );
	},

	/* Handle keystrokes. */
	_doKeyDown: function( event ) {
		var onSelect, dateStr, sel,
			inst = $.datepicker._getInst( event.target ),
			handled = true,
			isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );

		inst._keyEvent = true;
		if ( $.datepicker._datepickerShowing ) {
			switch ( event.keyCode ) {
				case 9: $.datepicker._hideDatepicker();
						handled = false;
						break; // hide on tab out
				case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
									$.datepicker._currentClass + ")", inst.dpDiv );
						if ( sel[ 0 ] ) {
							$.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
						}

						onSelect = $.datepicker._get( inst, "onSelect" );
						if ( onSelect ) {
							dateStr = $.datepicker._formatDate( inst );

							// Trigger custom callback
							onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
						} else {
							$.datepicker._hideDatepicker();
						}

						return false; // don't submit the form
				case 27: $.datepicker._hideDatepicker();
						break; // hide on escape
				case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
							-$.datepicker._get( inst, "stepBigMonths" ) :
							-$.datepicker._get( inst, "stepMonths" ) ), "M" );
						break; // previous month/year on page up/+ ctrl
				case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
							+$.datepicker._get( inst, "stepBigMonths" ) :
							+$.datepicker._get( inst, "stepMonths" ) ), "M" );
						break; // next month/year on page down/+ ctrl
				case 35: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._clearDate( event.target );
						}
						handled = event.ctrlKey || event.metaKey;
						break; // clear on ctrl or command +end
				case 36: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._gotoToday( event.target );
						}
						handled = event.ctrlKey || event.metaKey;
						break; // current on ctrl or command +home
				case 37: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
						}
						handled = event.ctrlKey || event.metaKey;

						// -1 day on ctrl or command +left
						if ( event.originalEvent.altKey ) {
							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
								-$.datepicker._get( inst, "stepBigMonths" ) :
								-$.datepicker._get( inst, "stepMonths" ) ), "M" );
						}

						// next month/year on alt +left on Mac
						break;
				case 38: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._adjustDate( event.target, -7, "D" );
						}
						handled = event.ctrlKey || event.metaKey;
						break; // -1 week on ctrl or command +up
				case 39: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
						}
						handled = event.ctrlKey || event.metaKey;

						// +1 day on ctrl or command +right
						if ( event.originalEvent.altKey ) {
							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
								+$.datepicker._get( inst, "stepBigMonths" ) :
								+$.datepicker._get( inst, "stepMonths" ) ), "M" );
						}

						// next month/year on alt +right
						break;
				case 40: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._adjustDate( event.target, +7, "D" );
						}
						handled = event.ctrlKey || event.metaKey;
						break; // +1 week on ctrl or command +down
				default: handled = false;
			}
		} else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
			$.datepicker._showDatepicker( this );
		} else {
			handled = false;
		}

		if ( handled ) {
			event.preventDefault();
			event.stopPropagation();
		}
	},

	/* Filter entered characters - based on date format. */
	_doKeyPress: function( event ) {
		var chars, chr,
			inst = $.datepicker._getInst( event.target );

		if ( $.datepicker._get( inst, "constrainInput" ) ) {
			chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
			chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
			return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
		}
	},

	/* Synchronise manual entry and field/alternate field. */
	_doKeyUp: function( event ) {
		var date,
			inst = $.datepicker._getInst( event.target );

		if ( inst.input.val() !== inst.lastVal ) {
			try {
				date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
					( inst.input ? inst.input.val() : null ),
					$.datepicker._getFormatConfig( inst ) );

				if ( date ) { // only if valid
					$.datepicker._setDateFromField( inst );
					$.datepicker._updateAlternate( inst );
					$.datepicker._updateDatepicker( inst );
				}
			}
			catch ( err ) {
			}
		}
		return true;
	},

	/* Pop-up the date picker for a given input field.
	 * If false returned from beforeShow event handler do not show.
	 * @param  input  element - the input field attached to the date picker or
	 *					event - if triggered by focus
	 */
	_showDatepicker: function( input ) {
		input = input.target || input;
		if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
			input = $( "input", input.parentNode )[ 0 ];
		}

		if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
			return;
		}

		var inst, beforeShow, beforeShowSettings, isFixed,
			offset, showAnim, duration;

		inst = $.datepicker._getInst( input );
		if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
			$.datepicker._curInst.dpDiv.stop( true, true );
			if ( inst && $.datepicker._datepickerShowing ) {
				$.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
			}
		}

		beforeShow = $.datepicker._get( inst, "beforeShow" );
		beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
		if ( beforeShowSettings === false ) {
			return;
		}
		datepicker_extendRemove( inst.settings, beforeShowSettings );

		inst.lastVal = null;
		$.datepicker._lastInput = input;
		$.datepicker._setDateFromField( inst );

		if ( $.datepicker._inDialog ) { // hide cursor
			input.value = "";
		}
		if ( !$.datepicker._pos ) { // position below input
			$.datepicker._pos = $.datepicker._findPos( input );
			$.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
		}

		isFixed = false;
		$( input ).parents().each( function() {
			isFixed |= $( this ).css( "position" ) === "fixed";
			return !isFixed;
		} );

		offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
		$.datepicker._pos = null;

		//to avoid flashes on Firefox
		inst.dpDiv.empty();

		// determine sizing offscreen
		inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
		$.datepicker._updateDatepicker( inst );

		// fix width for dynamic number of date pickers
		// and adjust position before showing
		offset = $.datepicker._checkOffset( inst, offset, isFixed );
		inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
			"static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
			left: offset.left + "px", top: offset.top + "px" } );

		if ( !inst.inline ) {
			showAnim = $.datepicker._get( inst, "showAnim" );
			duration = $.datepicker._get( inst, "duration" );
			inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
			$.datepicker._datepickerShowing = true;

			if ( $.effects && $.effects.effect[ showAnim ] ) {
				inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
			} else {
				inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
			}

			if ( $.datepicker._shouldFocusInput( inst ) ) {
				inst.input.trigger( "focus" );
			}

			$.datepicker._curInst = inst;
		}
	},

	/* Generate the date picker content. */
	_updateDatepicker: function( inst ) {
		this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
		datepicker_instActive = inst; // for delegate hover events
		inst.dpDiv.empty().append( this._generateHTML( inst ) );
		this._attachHandlers( inst );

		var origyearshtml,
			numMonths = this._getNumberOfMonths( inst ),
			cols = numMonths[ 1 ],
			width = 17,
			activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );

		if ( activeCell.length > 0 ) {
			datepicker_handleMouseover.apply( activeCell.get( 0 ) );
		}

		inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
		if ( cols > 1 ) {
			inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
		}
		inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
			"Class" ]( "ui-datepicker-multi" );
		inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
			"Class" ]( "ui-datepicker-rtl" );

		if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
			inst.input.trigger( "focus" );
		}

		// Deffered render of the years select (to avoid flashes on Firefox)
		if ( inst.yearshtml ) {
			origyearshtml = inst.yearshtml;
			setTimeout( function() {

				//assure that inst.yearshtml didn't change.
				if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
					inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
				}
				origyearshtml = inst.yearshtml = null;
			}, 0 );
		}
	},

	// #6694 - don't focus the input if it's already focused
	// this breaks the change event in IE
	// Support: IE and jQuery <1.9
	_shouldFocusInput: function( inst ) {
		return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
	},

	/* Check positioning to remain on screen. */
	_checkOffset: function( inst, offset, isFixed ) {
		var dpWidth = inst.dpDiv.outerWidth(),
			dpHeight = inst.dpDiv.outerHeight(),
			inputWidth = inst.input ? inst.input.outerWidth() : 0,
			inputHeight = inst.input ? inst.input.outerHeight() : 0,
			viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
			viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );

		offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
		offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
		offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;

		// Now check if datepicker is showing outside window viewport - move to a better place if so.
		offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
			Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
		offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
			Math.abs( dpHeight + inputHeight ) : 0 );

		return offset;
	},

	/* Find an object's position on the screen. */
	_findPos: function( obj ) {
		var position,
			inst = this._getInst( obj ),
			isRTL = this._get( inst, "isRTL" );

		while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
			obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
		}

		position = $( obj ).offset();
		return [ position.left, position.top ];
	},

	/* Hide the date picker from view.
	 * @param  input  element - the input field attached to the date picker
	 */
	_hideDatepicker: function( input ) {
		var showAnim, duration, postProcess, onClose,
			inst = this._curInst;

		if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
			return;
		}

		if ( this._datepickerShowing ) {
			showAnim = this._get( inst, "showAnim" );
			duration = this._get( inst, "duration" );
			postProcess = function() {
				$.datepicker._tidyDialog( inst );
			};

			// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
			if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
				inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
			} else {
				inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
					( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
			}

			if ( !showAnim ) {
				postProcess();
			}
			this._datepickerShowing = false;

			onClose = this._get( inst, "onClose" );
			if ( onClose ) {
				onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
			}

			this._lastInput = null;
			if ( this._inDialog ) {
				this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
				if ( $.blockUI ) {
					$.unblockUI();
					$( "body" ).append( this.dpDiv );
				}
			}
			this._inDialog = false;
		}
	},

	/* Tidy up after a dialog display. */
	_tidyDialog: function( inst ) {
		inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
	},

	/* Close date picker if clicked elsewhere. */
	_checkExternalClick: function( event ) {
		if ( !$.datepicker._curInst ) {
			return;
		}

		var $target = $( event.target ),
			inst = $.datepicker._getInst( $target[ 0 ] );

		if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
				$target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
				!$target.hasClass( $.datepicker.markerClassName ) &&
				!$target.closest( "." + $.datepicker._triggerClass ).length &&
				$.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
			( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
				$.datepicker._hideDatepicker();
		}
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function( id, offset, period ) {
		var target = $( id ),
			inst = this._getInst( target[ 0 ] );

		if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
			return;
		}
		this._adjustInstDate( inst, offset +
			( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
			period );
		this._updateDatepicker( inst );
	},

	/* Action for current link. */
	_gotoToday: function( id ) {
		var date,
			target = $( id ),
			inst = this._getInst( target[ 0 ] );

		if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
			inst.selectedDay = inst.currentDay;
			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
			inst.drawYear = inst.selectedYear = inst.currentYear;
		} else {
			date = new Date();
			inst.selectedDay = date.getDate();
			inst.drawMonth = inst.selectedMonth = date.getMonth();
			inst.drawYear = inst.selectedYear = date.getFullYear();
		}
		this._notifyChange( inst );
		this._adjustDate( target );
	},

	/* Action for selecting a new month/year. */
	_selectMonthYear: function( id, select, period ) {
		var target = $( id ),
			inst = this._getInst( target[ 0 ] );

		inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
		inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
			parseInt( select.options[ select.selectedIndex ].value, 10 );

		this._notifyChange( inst );
		this._adjustDate( target );
	},

	/* Action for selecting a day. */
	_selectDay: function( id, month, year, td ) {
		var inst,
			target = $( id );

		if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
			return;
		}

		inst = this._getInst( target[ 0 ] );
		inst.selectedDay = inst.currentDay = $( "a", td ).html();
		inst.selectedMonth = inst.currentMonth = month;
		inst.selectedYear = inst.currentYear = year;
		this._selectDate( id, this._formatDate( inst,
			inst.currentDay, inst.currentMonth, inst.currentYear ) );
	},

	/* Erase the input field and hide the date picker. */
	_clearDate: function( id ) {
		var target = $( id );
		this._selectDate( target, "" );
	},

	/* Update the input field with the selected date. */
	_selectDate: function( id, dateStr ) {
		var onSelect,
			target = $( id ),
			inst = this._getInst( target[ 0 ] );

		dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
		if ( inst.input ) {
			inst.input.val( dateStr );
		}
		this._updateAlternate( inst );

		onSelect = this._get( inst, "onSelect" );
		if ( onSelect ) {
			onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );  // trigger custom callback
		} else if ( inst.input ) {
			inst.input.trigger( "change" ); // fire the change event
		}

		if ( inst.inline ) {
			this._updateDatepicker( inst );
		} else {
			this._hideDatepicker();
			this._lastInput = inst.input[ 0 ];
			if ( typeof( inst.input[ 0 ] ) !== "object" ) {
				inst.input.trigger( "focus" ); // restore focus
			}
			this._lastInput = null;
		}
	},

	/* Update any alternate field to synchronise with the main field. */
	_updateAlternate: function( inst ) {
		var altFormat, date, dateStr,
			altField = this._get( inst, "altField" );

		if ( altField ) { // update alternate field too
			altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
			date = this._getDate( inst );
			dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
			$( altField ).val( dateStr );
		}
	},

	/* Set as beforeShowDay function to prevent selection of weekends.
	 * @param  date  Date - the date to customise
	 * @return [boolean, string] - is this date selectable?, what is its CSS class?
	 */
	noWeekends: function( date ) {
		var day = date.getDay();
		return [ ( day > 0 && day < 6 ), "" ];
	},

	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
	 * @param  date  Date - the date to get the week for
	 * @return  number - the number of the week within the year that contains this date
	 */
	iso8601Week: function( date ) {
		var time,
			checkDate = new Date( date.getTime() );

		// Find Thursday of this week starting on Monday
		checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );

		time = checkDate.getTime();
		checkDate.setMonth( 0 ); // Compare with Jan 1
		checkDate.setDate( 1 );
		return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
	},

	/* Parse a string value into a date object.
	 * See formatDate below for the possible formats.
	 *
	 * @param  format string - the expected format of the date
	 * @param  value string - the date in the above format
	 * @param  settings Object - attributes include:
	 *					shortYearCutoff  number - the cutoff year for determining the century (optional)
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
	 *					dayNames		string[7] - names of the days from Sunday (optional)
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
	 *					monthNames		string[12] - names of the months (optional)
	 * @return  Date - the extracted date value or null if value is blank
	 */
	parseDate: function( format, value, settings ) {
		if ( format == null || value == null ) {
			throw "Invalid arguments";
		}

		value = ( typeof value === "object" ? value.toString() : value + "" );
		if ( value === "" ) {
			return null;
		}

		var iFormat, dim, extra,
			iValue = 0,
			shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
			shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
				new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
			year = -1,
			month = -1,
			day = -1,
			doy = -1,
			literal = false,
			date,

			// Check whether a format character is doubled
			lookAhead = function( match ) {
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
				if ( matches ) {
					iFormat++;
				}
				return matches;
			},

			// Extract a number from the string value
			getNumber = function( match ) {
				var isDoubled = lookAhead( match ),
					size = ( match === "@" ? 14 : ( match === "!" ? 20 :
					( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
					minSize = ( match === "y" ? size : 1 ),
					digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
					num = value.substring( iValue ).match( digits );
				if ( !num ) {
					throw "Missing number at position " + iValue;
				}
				iValue += num[ 0 ].length;
				return parseInt( num[ 0 ], 10 );
			},

			// Extract a name from the string value and convert to an index
			getName = function( match, shortNames, longNames ) {
				var index = -1,
					names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
						return [ [ k, v ] ];
					} ).sort( function( a, b ) {
						return -( a[ 1 ].length - b[ 1 ].length );
					} );

				$.each( names, function( i, pair ) {
					var name = pair[ 1 ];
					if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
						index = pair[ 0 ];
						iValue += name.length;
						return false;
					}
				} );
				if ( index !== -1 ) {
					return index + 1;
				} else {
					throw "Unknown name at position " + iValue;
				}
			},

			// Confirm that a literal character matches the string value
			checkLiteral = function() {
				if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
					throw "Unexpected literal at position " + iValue;
				}
				iValue++;
			};

		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
			if ( literal ) {
				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
					literal = false;
				} else {
					checkLiteral();
				}
			} else {
				switch ( format.charAt( iFormat ) ) {
					case "d":
						day = getNumber( "d" );
						break;
					case "D":
						getName( "D", dayNamesShort, dayNames );
						break;
					case "o":
						doy = getNumber( "o" );
						break;
					case "m":
						month = getNumber( "m" );
						break;
					case "M":
						month = getName( "M", monthNamesShort, monthNames );
						break;
					case "y":
						year = getNumber( "y" );
						break;
					case "@":
						date = new Date( getNumber( "@" ) );
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "!":
						date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "'":
						if ( lookAhead( "'" ) ) {
							checkLiteral();
						} else {
							literal = true;
						}
						break;
					default:
						checkLiteral();
				}
			}
		}

		if ( iValue < value.length ) {
			extra = value.substr( iValue );
			if ( !/^\s+/.test( extra ) ) {
				throw "Extra/unparsed characters found in date: " + extra;
			}
		}

		if ( year === -1 ) {
			year = new Date().getFullYear();
		} else if ( year < 100 ) {
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
				( year <= shortYearCutoff ? 0 : -100 );
		}

		if ( doy > -1 ) {
			month = 1;
			day = doy;
			do {
				dim = this._getDaysInMonth( year, month - 1 );
				if ( day <= dim ) {
					break;
				}
				month++;
				day -= dim;
			} while ( true );
		}

		date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
		if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
			throw "Invalid date"; // E.g. 31/02/00
		}
		return date;
	},

	/* Standard date formats. */
	ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
	COOKIE: "D, dd M yy",
	ISO_8601: "yy-mm-dd",
	RFC_822: "D, d M y",
	RFC_850: "DD, dd-M-y",
	RFC_1036: "D, d M y",
	RFC_1123: "D, d M yy",
	RFC_2822: "D, d M yy",
	RSS: "D, d M y", // RFC 822
	TICKS: "!",
	TIMESTAMP: "@",
	W3C: "yy-mm-dd", // ISO 8601

	_ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
		Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),

	/* Format a date object into a string value.
	 * The format can be combinations of the following:
	 * d  - day of month (no leading zero)
	 * dd - day of month (two digit)
	 * o  - day of year (no leading zeros)
	 * oo - day of year (three digit)
	 * D  - day name short
	 * DD - day name long
	 * m  - month of year (no leading zero)
	 * mm - month of year (two digit)
	 * M  - month name short
	 * MM - month name long
	 * y  - year (two digit)
	 * yy - year (four digit)
	 * @ - Unix timestamp (ms since 01/01/1970)
	 * ! - Windows ticks (100ns since 01/01/0001)
	 * "..." - literal text
	 * '' - single quote
	 *
	 * @param  format string - the desired format of the date
	 * @param  date Date - the date value to format
	 * @param  settings Object - attributes include:
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
	 *					dayNames		string[7] - names of the days from Sunday (optional)
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
	 *					monthNames		string[12] - names of the months (optional)
	 * @return  string - the date in the above format
	 */
	formatDate: function( format, date, settings ) {
		if ( !date ) {
			return "";
		}

		var iFormat,
			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,

			// Check whether a format character is doubled
			lookAhead = function( match ) {
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
				if ( matches ) {
					iFormat++;
				}
				return matches;
			},

			// Format a number, with leading zero if necessary
			formatNumber = function( match, value, len ) {
				var num = "" + value;
				if ( lookAhead( match ) ) {
					while ( num.length < len ) {
						num = "0" + num;
					}
				}
				return num;
			},

			// Format a name, short or long as requested
			formatName = function( match, value, shortNames, longNames ) {
				return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
			},
			output = "",
			literal = false;

		if ( date ) {
			for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
				if ( literal ) {
					if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
						literal = false;
					} else {
						output += format.charAt( iFormat );
					}
				} else {
					switch ( format.charAt( iFormat ) ) {
						case "d":
							output += formatNumber( "d", date.getDate(), 2 );
							break;
						case "D":
							output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
							break;
						case "o":
							output += formatNumber( "o",
								Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
							break;
						case "m":
							output += formatNumber( "m", date.getMonth() + 1, 2 );
							break;
						case "M":
							output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
							break;
						case "y":
							output += ( lookAhead( "y" ) ? date.getFullYear() :
								( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
							break;
						case "@":
							output += date.getTime();
							break;
						case "!":
							output += date.getTime() * 10000 + this._ticksTo1970;
							break;
						case "'":
							if ( lookAhead( "'" ) ) {
								output += "'";
							} else {
								literal = true;
							}
							break;
						default:
							output += format.charAt( iFormat );
					}
				}
			}
		}
		return output;
	},

	/* Extract all possible characters from the date format. */
	_possibleChars: function( format ) {
		var iFormat,
			chars = "",
			literal = false,

			// Check whether a format character is doubled
			lookAhead = function( match ) {
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
				if ( matches ) {
					iFormat++;
				}
				return matches;
			};

		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
			if ( literal ) {
				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
					literal = false;
				} else {
					chars += format.charAt( iFormat );
				}
			} else {
				switch ( format.charAt( iFormat ) ) {
					case "d": case "m": case "y": case "@":
						chars += "0123456789";
						break;
					case "D": case "M":
						return null; // Accept anything
					case "'":
						if ( lookAhead( "'" ) ) {
							chars += "'";
						} else {
							literal = true;
						}
						break;
					default:
						chars += format.charAt( iFormat );
				}
			}
		}
		return chars;
	},

	/* Get a setting value, defaulting if necessary. */
	_get: function( inst, name ) {
		return inst.settings[ name ] !== undefined ?
			inst.settings[ name ] : this._defaults[ name ];
	},

	/* Parse existing date and initialise date picker. */
	_setDateFromField: function( inst, noDefault ) {
		if ( inst.input.val() === inst.lastVal ) {
			return;
		}

		var dateFormat = this._get( inst, "dateFormat" ),
			dates = inst.lastVal = inst.input ? inst.input.val() : null,
			defaultDate = this._getDefaultDate( inst ),
			date = defaultDate,
			settings = this._getFormatConfig( inst );

		try {
			date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
		} catch ( event ) {
			dates = ( noDefault ? "" : dates );
		}
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		inst.currentDay = ( dates ? date.getDate() : 0 );
		inst.currentMonth = ( dates ? date.getMonth() : 0 );
		inst.currentYear = ( dates ? date.getFullYear() : 0 );
		this._adjustInstDate( inst );
	},

	/* Retrieve the default date shown on opening. */
	_getDefaultDate: function( inst ) {
		return this._restrictMinMax( inst,
			this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
	},

	/* A date may be specified as an exact value or a relative one. */
	_determineDate: function( inst, date, defaultDate ) {
		var offsetNumeric = function( offset ) {
				var date = new Date();
				date.setDate( date.getDate() + offset );
				return date;
			},
			offsetString = function( offset ) {
				try {
					return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
						offset, $.datepicker._getFormatConfig( inst ) );
				}
				catch ( e ) {

					// Ignore
				}

				var date = ( offset.toLowerCase().match( /^c/ ) ?
					$.datepicker._getDate( inst ) : null ) || new Date(),
					year = date.getFullYear(),
					month = date.getMonth(),
					day = date.getDate(),
					pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
					matches = pattern.exec( offset );

				while ( matches ) {
					switch ( matches[ 2 ] || "d" ) {
						case "d" : case "D" :
							day += parseInt( matches[ 1 ], 10 ); break;
						case "w" : case "W" :
							day += parseInt( matches[ 1 ], 10 ) * 7; break;
						case "m" : case "M" :
							month += parseInt( matches[ 1 ], 10 );
							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
							break;
						case "y": case "Y" :
							year += parseInt( matches[ 1 ], 10 );
							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
							break;
					}
					matches = pattern.exec( offset );
				}
				return new Date( year, month, day );
			},
			newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
				( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );

		newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
		if ( newDate ) {
			newDate.setHours( 0 );
			newDate.setMinutes( 0 );
			newDate.setSeconds( 0 );
			newDate.setMilliseconds( 0 );
		}
		return this._daylightSavingAdjust( newDate );
	},

	/* Handle switch to/from daylight saving.
	 * Hours may be non-zero on daylight saving cut-over:
	 * > 12 when midnight changeover, but then cannot generate
	 * midnight datetime, so jump to 1AM, otherwise reset.
	 * @param  date  (Date) the date to check
	 * @return  (Date) the corrected date
	 */
	_daylightSavingAdjust: function( date ) {
		if ( !date ) {
			return null;
		}
		date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
		return date;
	},

	/* Set the date(s) directly. */
	_setDate: function( inst, date, noChange ) {
		var clear = !date,
			origMonth = inst.selectedMonth,
			origYear = inst.selectedYear,
			newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );

		inst.selectedDay = inst.currentDay = newDate.getDate();
		inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
		inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
		if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
			this._notifyChange( inst );
		}
		this._adjustInstDate( inst );
		if ( inst.input ) {
			inst.input.val( clear ? "" : this._formatDate( inst ) );
		}
	},

	/* Retrieve the date(s) directly. */
	_getDate: function( inst ) {
		var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
			this._daylightSavingAdjust( new Date(
			inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
			return startDate;
	},

	/* Attach the onxxx handlers.  These are declared statically so
	 * they work with static code transformers like Caja.
	 */
	_attachHandlers: function( inst ) {
		var stepMonths = this._get( inst, "stepMonths" ),
			id = "#" + inst.id.replace( /\\\\/g, "\\" );
		inst.dpDiv.find( "[data-handler]" ).map( function() {
			var handler = {
				prev: function() {
					$.datepicker._adjustDate( id, -stepMonths, "M" );
				},
				next: function() {
					$.datepicker._adjustDate( id, +stepMonths, "M" );
				},
				hide: function() {
					$.datepicker._hideDatepicker();
				},
				today: function() {
					$.datepicker._gotoToday( id );
				},
				selectDay: function() {
					$.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
					return false;
				},
				selectMonth: function() {
					$.datepicker._selectMonthYear( id, this, "M" );
					return false;
				},
				selectYear: function() {
					$.datepicker._selectMonthYear( id, this, "Y" );
					return false;
				}
			};
			$( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
		} );
	},

	/* Generate the HTML for the current state of the date picker. */
	_generateHTML: function( inst ) {
		var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
			controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
			monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
			selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
			cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
			printDate, dRow, tbody, daySettings, otherMonth, unselectable,
			tempDate = new Date(),
			today = this._daylightSavingAdjust(
				new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
			isRTL = this._get( inst, "isRTL" ),
			showButtonPanel = this._get( inst, "showButtonPanel" ),
			hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
			navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
			numMonths = this._getNumberOfMonths( inst ),
			showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
			stepMonths = this._get( inst, "stepMonths" ),
			isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
			currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
				new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
			minDate = this._getMinMaxDate( inst, "min" ),
			maxDate = this._getMinMaxDate( inst, "max" ),
			drawMonth = inst.drawMonth - showCurrentAtPos,
			drawYear = inst.drawYear;

		if ( drawMonth < 0 ) {
			drawMonth += 12;
			drawYear--;
		}
		if ( maxDate ) {
			maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
				maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
			maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
			while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
				drawMonth--;
				if ( drawMonth < 0 ) {
					drawMonth = 11;
					drawYear--;
				}
			}
		}
		inst.drawMonth = drawMonth;
		inst.drawYear = drawYear;

		prevText = this._get( inst, "prevText" );
		prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
			this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
			this._getFormatConfig( inst ) ) );

		prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
			"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
			" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
			( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) );

		nextText = this._get( inst, "nextText" );
		nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
			this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
			this._getFormatConfig( inst ) ) );

		next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
			"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
			" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
			( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) );

		currentText = this._get( inst, "currentText" );
		gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
		currentText = ( !navigationAsDateFormat ? currentText :
			this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );

		controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
			this._get( inst, "closeText" ) + "</button>" : "" );

		buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
			( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
			">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";

		firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
		firstDay = ( isNaN( firstDay ) ? 0 : firstDay );

		showWeek = this._get( inst, "showWeek" );
		dayNames = this._get( inst, "dayNames" );
		dayNamesMin = this._get( inst, "dayNamesMin" );
		monthNames = this._get( inst, "monthNames" );
		monthNamesShort = this._get( inst, "monthNamesShort" );
		beforeShowDay = this._get( inst, "beforeShowDay" );
		showOtherMonths = this._get( inst, "showOtherMonths" );
		selectOtherMonths = this._get( inst, "selectOtherMonths" );
		defaultDate = this._getDefaultDate( inst );
		html = "";

		for ( row = 0; row < numMonths[ 0 ]; row++ ) {
			group = "";
			this.maxRows = 4;
			for ( col = 0; col < numMonths[ 1 ]; col++ ) {
				selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
				cornerClass = " ui-corner-all";
				calender = "";
				if ( isMultiMonth ) {
					calender += "<div class='ui-datepicker-group";
					if ( numMonths[ 1 ] > 1 ) {
						switch ( col ) {
							case 0: calender += " ui-datepicker-group-first";
								cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
							case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
								cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
							default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
						}
					}
					calender += "'>";
				}
				calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
					( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
					( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
					this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
					row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
					"</div><table class='ui-datepicker-calendar'><thead>" +
					"<tr>";
				thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
				for ( dow = 0; dow < 7; dow++ ) { // days of the week
					day = ( dow + firstDay ) % 7;
					thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
						"<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
				}
				calender += thead + "</tr></thead><tbody>";
				daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
				if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
					inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
				}
				leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
				curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
				numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
				this.maxRows = numRows;
				printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
				for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
					calender += "<tr>";
					tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
						this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
					for ( dow = 0; dow < 7; dow++ ) { // create date picker days
						daySettings = ( beforeShowDay ?
							beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
						otherMonth = ( printDate.getMonth() !== drawMonth );
						unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
							( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
						tbody += "<td class='" +
							( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
							( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
							( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
							( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?

							// or defaultDate is current printedDate and defaultDate is selectedDate
							" " + this._dayOverClass : "" ) + // highlight selected day
							( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) +  // highlight unselectable days
							( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
							( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
							( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
							( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
							( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
							( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
							( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
							( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
							( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
							( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
							"' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
						printDate.setDate( printDate.getDate() + 1 );
						printDate = this._daylightSavingAdjust( printDate );
					}
					calender += tbody + "</tr>";
				}
				drawMonth++;
				if ( drawMonth > 11 ) {
					drawMonth = 0;
					drawYear++;
				}
				calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
							( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
				group += calender;
			}
			html += group;
		}
		html += buttonPanel;
		inst._keyEvent = false;
		return html;
	},

	/* Generate the month and year header. */
	_generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
			secondary, monthNames, monthNamesShort ) {

		var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
			changeMonth = this._get( inst, "changeMonth" ),
			changeYear = this._get( inst, "changeYear" ),
			showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
			html = "<div class='ui-datepicker-title'>",
			monthHtml = "";

		// Month selection
		if ( secondary || !changeMonth ) {
			monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
		} else {
			inMinYear = ( minDate && minDate.getFullYear() === drawYear );
			inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
			monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
			for ( month = 0; month < 12; month++ ) {
				if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
					monthHtml += "<option value='" + month + "'" +
						( month === drawMonth ? " selected='selected'" : "" ) +
						">" + monthNamesShort[ month ] + "</option>";
				}
			}
			monthHtml += "</select>";
		}

		if ( !showMonthAfterYear ) {
			html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
		}

		// Year selection
		if ( !inst.yearshtml ) {
			inst.yearshtml = "";
			if ( secondary || !changeYear ) {
				html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
			} else {

				// determine range of years to display
				years = this._get( inst, "yearRange" ).split( ":" );
				thisYear = new Date().getFullYear();
				determineYear = function( value ) {
					var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
						( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
						parseInt( value, 10 ) ) );
					return ( isNaN( year ) ? thisYear : year );
				};
				year = determineYear( years[ 0 ] );
				endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
				year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
				endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
				inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
				for ( ; year <= endYear; year++ ) {
					inst.yearshtml += "<option value='" + year + "'" +
						( year === drawYear ? " selected='selected'" : "" ) +
						">" + year + "</option>";
				}
				inst.yearshtml += "</select>";

				html += inst.yearshtml;
				inst.yearshtml = null;
			}
		}

		html += this._get( inst, "yearSuffix" );
		if ( showMonthAfterYear ) {
			html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
		}
		html += "</div>"; // Close datepicker_header
		return html;
	},

	/* Adjust one of the date sub-fields. */
	_adjustInstDate: function( inst, offset, period ) {
		var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
			month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
			day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
			date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );

		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		if ( period === "M" || period === "Y" ) {
			this._notifyChange( inst );
		}
	},

	/* Ensure a date is within any min/max bounds. */
	_restrictMinMax: function( inst, date ) {
		var minDate = this._getMinMaxDate( inst, "min" ),
			maxDate = this._getMinMaxDate( inst, "max" ),
			newDate = ( minDate && date < minDate ? minDate : date );
		return ( maxDate && newDate > maxDate ? maxDate : newDate );
	},

	/* Notify change of month/year. */
	_notifyChange: function( inst ) {
		var onChange = this._get( inst, "onChangeMonthYear" );
		if ( onChange ) {
			onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
				[ inst.selectedYear, inst.selectedMonth + 1, inst ] );
		}
	},

	/* Determine the number of months to show. */
	_getNumberOfMonths: function( inst ) {
		var numMonths = this._get( inst, "numberOfMonths" );
		return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
	},

	/* Determine the current maximum date - ensure no time components are set. */
	_getMinMaxDate: function( inst, minMax ) {
		return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
	},

	/* Find the number of days in a given month. */
	_getDaysInMonth: function( year, month ) {
		return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
	},

	/* Find the day of the week of the first of a month. */
	_getFirstDayOfMonth: function( year, month ) {
		return new Date( year, month, 1 ).getDay();
	},

	/* Determines if we should allow a "next/prev" month display change. */
	_canAdjustMonth: function( inst, offset, curYear, curMonth ) {
		var numMonths = this._getNumberOfMonths( inst ),
			date = this._daylightSavingAdjust( new Date( curYear,
			curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );

		if ( offset < 0 ) {
			date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
		}
		return this._isInRange( inst, date );
	},

	/* Is the given date in the accepted range? */
	_isInRange: function( inst, date ) {
		var yearSplit, currentYear,
			minDate = this._getMinMaxDate( inst, "min" ),
			maxDate = this._getMinMaxDate( inst, "max" ),
			minYear = null,
			maxYear = null,
			years = this._get( inst, "yearRange" );
			if ( years ) {
				yearSplit = years.split( ":" );
				currentYear = new Date().getFullYear();
				minYear = parseInt( yearSplit[ 0 ], 10 );
				maxYear = parseInt( yearSplit[ 1 ], 10 );
				if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
					minYear += currentYear;
				}
				if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
					maxYear += currentYear;
				}
			}

		return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
			( !maxDate || date.getTime() <= maxDate.getTime() ) &&
			( !minYear || date.getFullYear() >= minYear ) &&
			( !maxYear || date.getFullYear() <= maxYear ) );
	},

	/* Provide the configuration settings for formatting/parsing. */
	_getFormatConfig: function( inst ) {
		var shortYearCutoff = this._get( inst, "shortYearCutoff" );
		shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
			new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
		return { shortYearCutoff: shortYearCutoff,
			dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
			monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
	},

	/* Format the given date for display. */
	_formatDate: function( inst, day, month, year ) {
		if ( !day ) {
			inst.currentDay = inst.selectedDay;
			inst.currentMonth = inst.selectedMonth;
			inst.currentYear = inst.selectedYear;
		}
		var date = ( day ? ( typeof day === "object" ? day :
			this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
			this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
		return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
	}
} );

/*
 * Bind hover events for datepicker elements.
 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
 */
function datepicker_bindHover( dpDiv ) {
	var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
	return dpDiv.on( "mouseout", selector, function() {
			$( this ).removeClass( "ui-state-hover" );
			if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
				$( this ).removeClass( "ui-datepicker-prev-hover" );
			}
			if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
				$( this ).removeClass( "ui-datepicker-next-hover" );
			}
		} )
		.on( "mouseover", selector, datepicker_handleMouseover );
}

function datepicker_handleMouseover() {
	if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
		$( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
		$( this ).addClass( "ui-state-hover" );
		if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
			$( this ).addClass( "ui-datepicker-prev-hover" );
		}
		if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
			$( this ).addClass( "ui-datepicker-next-hover" );
		}
	}
}

/* jQuery extend now ignores nulls! */
function datepicker_extendRemove( target, props ) {
	$.extend( target, props );
	for ( var name in props ) {
		if ( props[ name ] == null ) {
			target[ name ] = props[ name ];
		}
	}
	return target;
}

/* Invoke the datepicker functionality.
   @param  options  string - a command, optionally followed by additional parameters or
					Object - settings for attaching new datepicker functionality
   @return  jQuery object */
$.fn.datepicker = function( options ) {

	/* Verify an empty collection wasn't passed - Fixes #6976 */
	if ( !this.length ) {
		return this;
	}

	/* Initialise the date picker. */
	if ( !$.datepicker.initialized ) {
		$( document ).on( "mousedown", $.datepicker._checkExternalClick );
		$.datepicker.initialized = true;
	}

	/* Append datepicker main container to body if not exist. */
	if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
		$( "body" ).append( $.datepicker.dpDiv );
	}

	var otherArgs = Array.prototype.slice.call( arguments, 1 );
	if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
		return $.datepicker[ "_" + options + "Datepicker" ].
			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
	}
	if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
		return $.datepicker[ "_" + options + "Datepicker" ].
			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
	}
	return this.each( function() {
		typeof options === "string" ?
			$.datepicker[ "_" + options + "Datepicker" ].
				apply( $.datepicker, [ this ].concat( otherArgs ) ) :
			$.datepicker._attachDatepicker( this, options );
	} );
};

$.datepicker = new Datepicker(); // singleton instance
$.datepicker.initialized = false;
$.datepicker.uuid = new Date().getTime();
$.datepicker.version = "1.12.1";

var widgetsDatepicker = $.datepicker;




// This file is deprecated
var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );

/*!
 * jQuery UI Mouse 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Mouse
//>>group: Widgets
//>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
//>>docs: http://api.jqueryui.com/mouse/



var mouseHandled = false;
$( document ).on( "mouseup", function() {
	mouseHandled = false;
} );

var widgetsMouse = $.widget( "ui.mouse", {
	version: "1.12.1",
	options: {
		cancel: "input, textarea, button, select, option",
		distance: 1,
		delay: 0
	},
	_mouseInit: function() {
		var that = this;

		this.element
			.on( "mousedown." + this.widgetName, function( event ) {
				return that._mouseDown( event );
			} )
			.on( "click." + this.widgetName, function( event ) {
				if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
					$.removeData( event.target, that.widgetName + ".preventClickEvent" );
					event.stopImmediatePropagation();
					return false;
				}
			} );

		this.started = false;
	},

	// TODO: make sure destroying one instance of mouse doesn't mess with
	// other instances of mouse
	_mouseDestroy: function() {
		this.element.off( "." + this.widgetName );
		if ( this._mouseMoveDelegate ) {
			this.document
				.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
				.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
		}
	},

	_mouseDown: function( event ) {

		// don't let more than one widget handle mouseStart
		if ( mouseHandled ) {
			return;
		}

		this._mouseMoved = false;

		// We may have missed mouseup (out of window)
		( this._mouseStarted && this._mouseUp( event ) );

		this._mouseDownEvent = event;

		var that = this,
			btnIsLeft = ( event.which === 1 ),

			// event.target.nodeName works around a bug in IE 8 with
			// disabled inputs (#7620)
			elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
				$( event.target ).closest( this.options.cancel ).length : false );
		if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
			return true;
		}

		this.mouseDelayMet = !this.options.delay;
		if ( !this.mouseDelayMet ) {
			this._mouseDelayTimer = setTimeout( function() {
				that.mouseDelayMet = true;
			}, this.options.delay );
		}

		if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
			this._mouseStarted = ( this._mouseStart( event ) !== false );
			if ( !this._mouseStarted ) {
				event.preventDefault();
				return true;
			}
		}

		// Click event may never have fired (Gecko & Opera)
		if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
			$.removeData( event.target, this.widgetName + ".preventClickEvent" );
		}

		// These delegates are required to keep context
		this._mouseMoveDelegate = function( event ) {
			return that._mouseMove( event );
		};
		this._mouseUpDelegate = function( event ) {
			return that._mouseUp( event );
		};

		this.document
			.on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
			.on( "mouseup." + this.widgetName, this._mouseUpDelegate );

		event.preventDefault();

		mouseHandled = true;
		return true;
	},

	_mouseMove: function( event ) {

		// Only check for mouseups outside the document if you've moved inside the document
		// at least once. This prevents the firing of mouseup in the case of IE<9, which will
		// fire a mousemove event if content is placed under the cursor. See #7778
		// Support: IE <9
		if ( this._mouseMoved ) {

			// IE mouseup check - mouseup happened when mouse was out of window
			if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
					!event.button ) {
				return this._mouseUp( event );

			// Iframe mouseup check - mouseup occurred in another document
			} else if ( !event.which ) {

				// Support: Safari <=8 - 9
				// Safari sets which to 0 if you press any of the following keys
				// during a drag (#14461)
				if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
						event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
					this.ignoreMissingWhich = true;
				} else if ( !this.ignoreMissingWhich ) {
					return this._mouseUp( event );
				}
			}
		}

		if ( event.which || event.button ) {
			this._mouseMoved = true;
		}

		if ( this._mouseStarted ) {
			this._mouseDrag( event );
			return event.preventDefault();
		}

		if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
			this._mouseStarted =
				( this._mouseStart( this._mouseDownEvent, event ) !== false );
			( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
		}

		return !this._mouseStarted;
	},

	_mouseUp: function( event ) {
		this.document
			.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
			.off( "mouseup." + this.widgetName, this._mouseUpDelegate );

		if ( this._mouseStarted ) {
			this._mouseStarted = false;

			if ( event.target === this._mouseDownEvent.target ) {
				$.data( event.target, this.widgetName + ".preventClickEvent", true );
			}

			this._mouseStop( event );
		}

		if ( this._mouseDelayTimer ) {
			clearTimeout( this._mouseDelayTimer );
			delete this._mouseDelayTimer;
		}

		this.ignoreMissingWhich = false;
		mouseHandled = false;
		event.preventDefault();
	},

	_mouseDistanceMet: function( event ) {
		return ( Math.max(
				Math.abs( this._mouseDownEvent.pageX - event.pageX ),
				Math.abs( this._mouseDownEvent.pageY - event.pageY )
			) >= this.options.distance
		);
	},

	_mouseDelayMet: function( /* event */ ) {
		return this.mouseDelayMet;
	},

	// These are placeholder methods, to be overriden by extending plugin
	_mouseStart: function( /* event */ ) {},
	_mouseDrag: function( /* event */ ) {},
	_mouseStop: function( /* event */ ) {},
	_mouseCapture: function( /* event */ ) { return true; }
} );




// $.ui.plugin is deprecated. Use $.widget() extensions instead.
var plugin = $.ui.plugin = {
	add: function( module, option, set ) {
		var i,
			proto = $.ui[ module ].prototype;
		for ( i in set ) {
			proto.plugins[ i ] = proto.plugins[ i ] || [];
			proto.plugins[ i ].push( [ option, set[ i ] ] );
		}
	},
	call: function( instance, name, args, allowDisconnected ) {
		var i,
			set = instance.plugins[ name ];

		if ( !set ) {
			return;
		}

		if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
				instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
			return;
		}

		for ( i = 0; i < set.length; i++ ) {
			if ( instance.options[ set[ i ][ 0 ] ] ) {
				set[ i ][ 1 ].apply( instance.element, args );
			}
		}
	}
};



var safeBlur = $.ui.safeBlur = function( element ) {

	// Support: IE9 - 10 only
	// If the <body> is blurred, IE will switch windows, see #9420
	if ( element && element.nodeName.toLowerCase() !== "body" ) {
		$( element ).trigger( "blur" );
	}
};


/*!
 * jQuery UI Draggable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Draggable
//>>group: Interactions
//>>description: Enables dragging functionality for any element.
//>>docs: http://api.jqueryui.com/draggable/
//>>demos: http://jqueryui.com/draggable/
//>>css.structure: ../../themes/base/draggable.css



$.widget( "ui.draggable", $.ui.mouse, {
	version: "1.12.1",
	widgetEventPrefix: "drag",
	options: {
		addClasses: true,
		appendTo: "parent",
		axis: false,
		connectToSortable: false,
		containment: false,
		cursor: "auto",
		cursorAt: false,
		grid: false,
		handle: false,
		helper: "original",
		iframeFix: false,
		opacity: false,
		refreshPositions: false,
		revert: false,
		revertDuration: 500,
		scope: "default",
		scroll: true,
		scrollSensitivity: 20,
		scrollSpeed: 20,
		snap: false,
		snapMode: "both",
		snapTolerance: 20,
		stack: false,
		zIndex: false,

		// Callbacks
		drag: null,
		start: null,
		stop: null
	},
	_create: function() {

		if ( this.options.helper === "original" ) {
			this._setPositionRelative();
		}
		if ( this.options.addClasses ) {
			this._addClass( "ui-draggable" );
		}
		this._setHandleClassName();

		this._mouseInit();
	},

	_setOption: function( key, value ) {
		this._super( key, value );
		if ( key === "handle" ) {
			this._removeHandleClassName();
			this._setHandleClassName();
		}
	},

	_destroy: function() {
		if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
			this.destroyOnClear = true;
			return;
		}
		this._removeHandleClassName();
		this._mouseDestroy();
	},

	_mouseCapture: function( event ) {
		var o = this.options;

		// Among others, prevent a drag on a resizable-handle
		if ( this.helper || o.disabled ||
				$( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
			return false;
		}

		//Quit if we're not on a valid handle
		this.handle = this._getHandle( event );
		if ( !this.handle ) {
			return false;
		}

		this._blurActiveElement( event );

		this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );

		return true;

	},

	_blockFrames: function( selector ) {
		this.iframeBlocks = this.document.find( selector ).map( function() {
			var iframe = $( this );

			return $( "<div>" )
				.css( "position", "absolute" )
				.appendTo( iframe.parent() )
				.outerWidth( iframe.outerWidth() )
				.outerHeight( iframe.outerHeight() )
				.offset( iframe.offset() )[ 0 ];
		} );
	},

	_unblockFrames: function() {
		if ( this.iframeBlocks ) {
			this.iframeBlocks.remove();
			delete this.iframeBlocks;
		}
	},

	_blurActiveElement: function( event ) {
		var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
			target = $( event.target );

		// Don't blur if the event occurred on an element that is within
		// the currently focused element
		// See #10527, #12472
		if ( target.closest( activeElement ).length ) {
			return;
		}

		// Blur any element that currently has focus, see #4261
		$.ui.safeBlur( activeElement );
	},

	_mouseStart: function( event ) {

		var o = this.options;

		//Create and append the visible helper
		this.helper = this._createHelper( event );

		this._addClass( this.helper, "ui-draggable-dragging" );

		//Cache the helper size
		this._cacheHelperProportions();

		//If ddmanager is used for droppables, set the global draggable
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.current = this;
		}

		/*
		 * - Position generation -
		 * This block generates everything position related - it's the core of draggables.
		 */

		//Cache the margins of the original element
		this._cacheMargins();

		//Store the helper's css position
		this.cssPosition = this.helper.css( "position" );
		this.scrollParent = this.helper.scrollParent( true );
		this.offsetParent = this.helper.offsetParent();
		this.hasFixedAncestor = this.helper.parents().filter( function() {
				return $( this ).css( "position" ) === "fixed";
			} ).length > 0;

		//The element's absolute position on the page minus margins
		this.positionAbs = this.element.offset();
		this._refreshOffsets( event );

		//Generate the original position
		this.originalPosition = this.position = this._generatePosition( event, false );
		this.originalPageX = event.pageX;
		this.originalPageY = event.pageY;

		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
		( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );

		//Set a containment if given in the options
		this._setContainment();

		//Trigger event + callbacks
		if ( this._trigger( "start", event ) === false ) {
			this._clear();
			return false;
		}

		//Recache the helper size
		this._cacheHelperProportions();

		//Prepare the droppable offsets
		if ( $.ui.ddmanager && !o.dropBehaviour ) {
			$.ui.ddmanager.prepareOffsets( this, event );
		}

		// Execute the drag once - this causes the helper not to be visible before getting its
		// correct position
		this._mouseDrag( event, true );

		// If the ddmanager is used for droppables, inform the manager that dragging has started
		// (see #5003)
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.dragStart( this, event );
		}

		return true;
	},

	_refreshOffsets: function( event ) {
		this.offset = {
			top: this.positionAbs.top - this.margins.top,
			left: this.positionAbs.left - this.margins.left,
			scroll: false,
			parent: this._getParentOffset(),
			relative: this._getRelativeOffset()
		};

		this.offset.click = {
			left: event.pageX - this.offset.left,
			top: event.pageY - this.offset.top
		};
	},

	_mouseDrag: function( event, noPropagation ) {

		// reset any necessary cached properties (see #5009)
		if ( this.hasFixedAncestor ) {
			this.offset.parent = this._getParentOffset();
		}

		//Compute the helpers position
		this.position = this._generatePosition( event, true );
		this.positionAbs = this._convertPositionTo( "absolute" );

		//Call plugins and callbacks and use the resulting position if something is returned
		if ( !noPropagation ) {
			var ui = this._uiHash();
			if ( this._trigger( "drag", event, ui ) === false ) {
				this._mouseUp( new $.Event( "mouseup", event ) );
				return false;
			}
			this.position = ui.position;
		}

		this.helper[ 0 ].style.left = this.position.left + "px";
		this.helper[ 0 ].style.top = this.position.top + "px";

		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.drag( this, event );
		}

		return false;
	},

	_mouseStop: function( event ) {

		//If we are using droppables, inform the manager about the drop
		var that = this,
			dropped = false;
		if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
			dropped = $.ui.ddmanager.drop( this, event );
		}

		//if a drop comes from outside (a sortable)
		if ( this.dropped ) {
			dropped = this.dropped;
			this.dropped = false;
		}

		if ( ( this.options.revert === "invalid" && !dropped ) ||
				( this.options.revert === "valid" && dropped ) ||
				this.options.revert === true || ( $.isFunction( this.options.revert ) &&
				this.options.revert.call( this.element, dropped ) )
		) {
			$( this.helper ).animate(
				this.originalPosition,
				parseInt( this.options.revertDuration, 10 ),
				function() {
					if ( that._trigger( "stop", event ) !== false ) {
						that._clear();
					}
				}
			);
		} else {
			if ( this._trigger( "stop", event ) !== false ) {
				this._clear();
			}
		}

		return false;
	},

	_mouseUp: function( event ) {
		this._unblockFrames();

		// If the ddmanager is used for droppables, inform the manager that dragging has stopped
		// (see #5003)
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.dragStop( this, event );
		}

		// Only need to focus if the event occurred on the draggable itself, see #10527
		if ( this.handleElement.is( event.target ) ) {

			// The interaction is over; whether or not the click resulted in a drag,
			// focus the element
			this.element.trigger( "focus" );
		}

		return $.ui.mouse.prototype._mouseUp.call( this, event );
	},

	cancel: function() {

		if ( this.helper.is( ".ui-draggable-dragging" ) ) {
			this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
		} else {
			this._clear();
		}

		return this;

	},

	_getHandle: function( event ) {
		return this.options.handle ?
			!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
			true;
	},

	_setHandleClassName: function() {
		this.handleElement = this.options.handle ?
			this.element.find( this.options.handle ) : this.element;
		this._addClass( this.handleElement, "ui-draggable-handle" );
	},

	_removeHandleClassName: function() {
		this._removeClass( this.handleElement, "ui-draggable-handle" );
	},

	_createHelper: function( event ) {

		var o = this.options,
			helperIsFunction = $.isFunction( o.helper ),
			helper = helperIsFunction ?
				$( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
				( o.helper === "clone" ?
					this.element.clone().removeAttr( "id" ) :
					this.element );

		if ( !helper.parents( "body" ).length ) {
			helper.appendTo( ( o.appendTo === "parent" ?
				this.element[ 0 ].parentNode :
				o.appendTo ) );
		}

		// Http://bugs.jqueryui.com/ticket/9446
		// a helper function can return the original element
		// which wouldn't have been set to relative in _create
		if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
			this._setPositionRelative();
		}

		if ( helper[ 0 ] !== this.element[ 0 ] &&
				!( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
			helper.css( "position", "absolute" );
		}

		return helper;

	},

	_setPositionRelative: function() {
		if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
			this.element[ 0 ].style.position = "relative";
		}
	},

	_adjustOffsetFromHelper: function( obj ) {
		if ( typeof obj === "string" ) {
			obj = obj.split( " " );
		}
		if ( $.isArray( obj ) ) {
			obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
		}
		if ( "left" in obj ) {
			this.offset.click.left = obj.left + this.margins.left;
		}
		if ( "right" in obj ) {
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
		}
		if ( "top" in obj ) {
			this.offset.click.top = obj.top + this.margins.top;
		}
		if ( "bottom" in obj ) {
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
		}
	},

	_isRootNode: function( element ) {
		return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
	},

	_getParentOffset: function() {

		//Get the offsetParent and cache its position
		var po = this.offsetParent.offset(),
			document = this.document[ 0 ];

		// This is a special case where we need to modify a offset calculated on start, since the
		// following happened:
		// 1. The position of the helper is absolute, so it's position is calculated based on the
		// next positioned parent
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
		// the document, which means that the scroll is included in the initial calculation of the
		// offset of the parent, and never recalculated upon drag
		if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
			po.left += this.scrollParent.scrollLeft();
			po.top += this.scrollParent.scrollTop();
		}

		if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
			po = { top: 0, left: 0 };
		}

		return {
			top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
			left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
		};

	},

	_getRelativeOffset: function() {
		if ( this.cssPosition !== "relative" ) {
			return { top: 0, left: 0 };
		}

		var p = this.element.position(),
			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );

		return {
			top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
				( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
			left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
				( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
		};

	},

	_cacheMargins: function() {
		this.margins = {
			left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
			top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
			right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
			bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
		};
	},

	_cacheHelperProportions: function() {
		this.helperProportions = {
			width: this.helper.outerWidth(),
			height: this.helper.outerHeight()
		};
	},

	_setContainment: function() {

		var isUserScrollable, c, ce,
			o = this.options,
			document = this.document[ 0 ];

		this.relativeContainer = null;

		if ( !o.containment ) {
			this.containment = null;
			return;
		}

		if ( o.containment === "window" ) {
			this.containment = [
				$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
				$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
				$( window ).scrollLeft() + $( window ).width() -
					this.helperProportions.width - this.margins.left,
				$( window ).scrollTop() +
					( $( window ).height() || document.body.parentNode.scrollHeight ) -
					this.helperProportions.height - this.margins.top
			];
			return;
		}

		if ( o.containment === "document" ) {
			this.containment = [
				0,
				0,
				$( document ).width() - this.helperProportions.width - this.margins.left,
				( $( document ).height() || document.body.parentNode.scrollHeight ) -
					this.helperProportions.height - this.margins.top
			];
			return;
		}

		if ( o.containment.constructor === Array ) {
			this.containment = o.containment;
			return;
		}

		if ( o.containment === "parent" ) {
			o.containment = this.helper[ 0 ].parentNode;
		}

		c = $( o.containment );
		ce = c[ 0 ];

		if ( !ce ) {
			return;
		}

		isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );

		this.containment = [
			( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
				( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
			( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
				( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
			( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
				( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
				( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
				this.helperProportions.width -
				this.margins.left -
				this.margins.right,
			( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
				( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
				( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
				this.helperProportions.height -
				this.margins.top -
				this.margins.bottom
		];
		this.relativeContainer = c;
	},

	_convertPositionTo: function( d, pos ) {

		if ( !pos ) {
			pos = this.position;
		}

		var mod = d === "absolute" ? 1 : -1,
			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );

		return {
			top: (

				// The absolute mouse position
				pos.top	+

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.top * mod +

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.top * mod -
				( ( this.cssPosition === "fixed" ?
					-this.offset.scroll.top :
					( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
			),
			left: (

				// The absolute mouse position
				pos.left +

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.left * mod +

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.left * mod	-
				( ( this.cssPosition === "fixed" ?
					-this.offset.scroll.left :
					( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
			)
		};

	},

	_generatePosition: function( event, constrainPosition ) {

		var containment, co, top, left,
			o = this.options,
			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
			pageX = event.pageX,
			pageY = event.pageY;

		// Cache the scroll
		if ( !scrollIsRootNode || !this.offset.scroll ) {
			this.offset.scroll = {
				top: this.scrollParent.scrollTop(),
				left: this.scrollParent.scrollLeft()
			};
		}

		/*
		 * - Position constraining -
		 * Constrain the position to a mix of grid, containment.
		 */

		// If we are not dragging yet, we won't check for options
		if ( constrainPosition ) {
			if ( this.containment ) {
				if ( this.relativeContainer ) {
					co = this.relativeContainer.offset();
					containment = [
						this.containment[ 0 ] + co.left,
						this.containment[ 1 ] + co.top,
						this.containment[ 2 ] + co.left,
						this.containment[ 3 ] + co.top
					];
				} else {
					containment = this.containment;
				}

				if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
					pageX = containment[ 0 ] + this.offset.click.left;
				}
				if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
					pageY = containment[ 1 ] + this.offset.click.top;
				}
				if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
					pageX = containment[ 2 ] + this.offset.click.left;
				}
				if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
					pageY = containment[ 3 ] + this.offset.click.top;
				}
			}

			if ( o.grid ) {

				//Check for grid elements set to 0 to prevent divide by 0 error causing invalid
				// argument errors in IE (see ticket #6950)
				top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
					this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
				pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
					top - this.offset.click.top > containment[ 3 ] ) ?
						top :
						( ( top - this.offset.click.top >= containment[ 1 ] ) ?
							top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;

				left = o.grid[ 0 ] ? this.originalPageX +
					Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
					this.originalPageX;
				pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
					left - this.offset.click.left > containment[ 2 ] ) ?
						left :
						( ( left - this.offset.click.left >= containment[ 0 ] ) ?
							left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
			}

			if ( o.axis === "y" ) {
				pageX = this.originalPageX;
			}

			if ( o.axis === "x" ) {
				pageY = this.originalPageY;
			}
		}

		return {
			top: (

				// The absolute mouse position
				pageY -

				// Click offset (relative to the element)
				this.offset.click.top -

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.top -

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.top +
				( this.cssPosition === "fixed" ?
					-this.offset.scroll.top :
					( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
			),
			left: (

				// The absolute mouse position
				pageX -

				// Click offset (relative to the element)
				this.offset.click.left -

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.left -

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.left +
				( this.cssPosition === "fixed" ?
					-this.offset.scroll.left :
					( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
			)
		};

	},

	_clear: function() {
		this._removeClass( this.helper, "ui-draggable-dragging" );
		if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
			this.helper.remove();
		}
		this.helper = null;
		this.cancelHelperRemoval = false;
		if ( this.destroyOnClear ) {
			this.destroy();
		}
	},

	// From now on bulk stuff - mainly helpers

	_trigger: function( type, event, ui ) {
		ui = ui || this._uiHash();
		$.ui.plugin.call( this, type, [ event, ui, this ], true );

		// Absolute position and offset (see #6884 ) have to be recalculated after plugins
		if ( /^(drag|start|stop)/.test( type ) ) {
			this.positionAbs = this._convertPositionTo( "absolute" );
			ui.offset = this.positionAbs;
		}
		return $.Widget.prototype._trigger.call( this, type, event, ui );
	},

	plugins: {},

	_uiHash: function() {
		return {
			helper: this.helper,
			position: this.position,
			originalPosition: this.originalPosition,
			offset: this.positionAbs
		};
	}

} );

$.ui.plugin.add( "draggable", "connectToSortable", {
	start: function( event, ui, draggable ) {
		var uiSortable = $.extend( {}, ui, {
			item: draggable.element
		} );

		draggable.sortables = [];
		$( draggable.options.connectToSortable ).each( function() {
			var sortable = $( this ).sortable( "instance" );

			if ( sortable && !sortable.options.disabled ) {
				draggable.sortables.push( sortable );

				// RefreshPositions is called at drag start to refresh the containerCache
				// which is used in drag. This ensures it's initialized and synchronized
				// with any changes that might have happened on the page since initialization.
				sortable.refreshPositions();
				sortable._trigger( "activate", event, uiSortable );
			}
		} );
	},
	stop: function( event, ui, draggable ) {
		var uiSortable = $.extend( {}, ui, {
			item: draggable.element
		} );

		draggable.cancelHelperRemoval = false;

		$.each( draggable.sortables, function() {
			var sortable = this;

			if ( sortable.isOver ) {
				sortable.isOver = 0;

				// Allow this sortable to handle removing the helper
				draggable.cancelHelperRemoval = true;
				sortable.cancelHelperRemoval = false;

				// Use _storedCSS To restore properties in the sortable,
				// as this also handles revert (#9675) since the draggable
				// may have modified them in unexpected ways (#8809)
				sortable._storedCSS = {
					position: sortable.placeholder.css( "position" ),
					top: sortable.placeholder.css( "top" ),
					left: sortable.placeholder.css( "left" )
				};

				sortable._mouseStop( event );

				// Once drag has ended, the sortable should return to using
				// its original helper, not the shared helper from draggable
				sortable.options.helper = sortable.options._helper;
			} else {

				// Prevent this Sortable from removing the helper.
				// However, don't set the draggable to remove the helper
				// either as another connected Sortable may yet handle the removal.
				sortable.cancelHelperRemoval = true;

				sortable._trigger( "deactivate", event, uiSortable );
			}
		} );
	},
	drag: function( event, ui, draggable ) {
		$.each( draggable.sortables, function() {
			var innermostIntersecting = false,
				sortable = this;

			// Copy over variables that sortable's _intersectsWith uses
			sortable.positionAbs = draggable.positionAbs;
			sortable.helperProportions = draggable.helperProportions;
			sortable.offset.click = draggable.offset.click;

			if ( sortable._intersectsWith( sortable.containerCache ) ) {
				innermostIntersecting = true;

				$.each( draggable.sortables, function() {

					// Copy over variables that sortable's _intersectsWith uses
					this.positionAbs = draggable.positionAbs;
					this.helperProportions = draggable.helperProportions;
					this.offset.click = draggable.offset.click;

					if ( this !== sortable &&
							this._intersectsWith( this.containerCache ) &&
							$.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
						innermostIntersecting = false;
					}

					return innermostIntersecting;
				} );
			}

			if ( innermostIntersecting ) {

				// If it intersects, we use a little isOver variable and set it once,
				// so that the move-in stuff gets fired only once.
				if ( !sortable.isOver ) {
					sortable.isOver = 1;

					// Store draggable's parent in case we need to reappend to it later.
					draggable._parent = ui.helper.parent();

					sortable.currentItem = ui.helper
						.appendTo( sortable.element )
						.data( "ui-sortable-item", true );

					// Store helper option to later restore it
					sortable.options._helper = sortable.options.helper;

					sortable.options.helper = function() {
						return ui.helper[ 0 ];
					};

					// Fire the start events of the sortable with our passed browser event,
					// and our own helper (so it doesn't create a new one)
					event.target = sortable.currentItem[ 0 ];
					sortable._mouseCapture( event, true );
					sortable._mouseStart( event, true, true );

					// Because the browser event is way off the new appended portlet,
					// modify necessary variables to reflect the changes
					sortable.offset.click.top = draggable.offset.click.top;
					sortable.offset.click.left = draggable.offset.click.left;
					sortable.offset.parent.left -= draggable.offset.parent.left -
						sortable.offset.parent.left;
					sortable.offset.parent.top -= draggable.offset.parent.top -
						sortable.offset.parent.top;

					draggable._trigger( "toSortable", event );

					// Inform draggable that the helper is in a valid drop zone,
					// used solely in the revert option to handle "valid/invalid".
					draggable.dropped = sortable.element;

					// Need to refreshPositions of all sortables in the case that
					// adding to one sortable changes the location of the other sortables (#9675)
					$.each( draggable.sortables, function() {
						this.refreshPositions();
					} );

					// Hack so receive/update callbacks work (mostly)
					draggable.currentItem = draggable.element;
					sortable.fromOutside = draggable;
				}

				if ( sortable.currentItem ) {
					sortable._mouseDrag( event );

					// Copy the sortable's position because the draggable's can potentially reflect
					// a relative position, while sortable is always absolute, which the dragged
					// element has now become. (#8809)
					ui.position = sortable.position;
				}
			} else {

				// If it doesn't intersect with the sortable, and it intersected before,
				// we fake the drag stop of the sortable, but make sure it doesn't remove
				// the helper by using cancelHelperRemoval.
				if ( sortable.isOver ) {

					sortable.isOver = 0;
					sortable.cancelHelperRemoval = true;

					// Calling sortable's mouseStop would trigger a revert,
					// so revert must be temporarily false until after mouseStop is called.
					sortable.options._revert = sortable.options.revert;
					sortable.options.revert = false;

					sortable._trigger( "out", event, sortable._uiHash( sortable ) );
					sortable._mouseStop( event, true );

					// Restore sortable behaviors that were modfied
					// when the draggable entered the sortable area (#9481)
					sortable.options.revert = sortable.options._revert;
					sortable.options.helper = sortable.options._helper;

					if ( sortable.placeholder ) {
						sortable.placeholder.remove();
					}

					// Restore and recalculate the draggable's offset considering the sortable
					// may have modified them in unexpected ways. (#8809, #10669)
					ui.helper.appendTo( draggable._parent );
					draggable._refreshOffsets( event );
					ui.position = draggable._generatePosition( event, true );

					draggable._trigger( "fromSortable", event );

					// Inform draggable that the helper is no longer in a valid drop zone
					draggable.dropped = false;

					// Need to refreshPositions of all sortables just in case removing
					// from one sortable changes the location of other sortables (#9675)
					$.each( draggable.sortables, function() {
						this.refreshPositions();
					} );
				}
			}
		} );
	}
} );

$.ui.plugin.add( "draggable", "cursor", {
	start: function( event, ui, instance ) {
		var t = $( "body" ),
			o = instance.options;

		if ( t.css( "cursor" ) ) {
			o._cursor = t.css( "cursor" );
		}
		t.css( "cursor", o.cursor );
	},
	stop: function( event, ui, instance ) {
		var o = instance.options;
		if ( o._cursor ) {
			$( "body" ).css( "cursor", o._cursor );
		}
	}
} );

$.ui.plugin.add( "draggable", "opacity", {
	start: function( event, ui, instance ) {
		var t = $( ui.helper ),
			o = instance.options;
		if ( t.css( "opacity" ) ) {
			o._opacity = t.css( "opacity" );
		}
		t.css( "opacity", o.opacity );
	},
	stop: function( event, ui, instance ) {
		var o = instance.options;
		if ( o._opacity ) {
			$( ui.helper ).css( "opacity", o._opacity );
		}
	}
} );

$.ui.plugin.add( "draggable", "scroll", {
	start: function( event, ui, i ) {
		if ( !i.scrollParentNotHidden ) {
			i.scrollParentNotHidden = i.helper.scrollParent( false );
		}

		if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
				i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
			i.overflowOffset = i.scrollParentNotHidden.offset();
		}
	},
	drag: function( event, ui, i  ) {

		var o = i.options,
			scrolled = false,
			scrollParent = i.scrollParentNotHidden[ 0 ],
			document = i.document[ 0 ];

		if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
			if ( !o.axis || o.axis !== "x" ) {
				if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
						o.scrollSensitivity ) {
					scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
				} else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
					scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
				}
			}

			if ( !o.axis || o.axis !== "y" ) {
				if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
						o.scrollSensitivity ) {
					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
				} else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
				}
			}

		} else {

			if ( !o.axis || o.axis !== "x" ) {
				if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
					scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
				} else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
						o.scrollSensitivity ) {
					scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
				}
			}

			if ( !o.axis || o.axis !== "y" ) {
				if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
					scrolled = $( document ).scrollLeft(
						$( document ).scrollLeft() - o.scrollSpeed
					);
				} else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
						o.scrollSensitivity ) {
					scrolled = $( document ).scrollLeft(
						$( document ).scrollLeft() + o.scrollSpeed
					);
				}
			}

		}

		if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
			$.ui.ddmanager.prepareOffsets( i, event );
		}

	}
} );

$.ui.plugin.add( "draggable", "snap", {
	start: function( event, ui, i ) {

		var o = i.options;

		i.snapElements = [];

		$( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
			.each( function() {
				var $t = $( this ),
					$o = $t.offset();
				if ( this !== i.element[ 0 ] ) {
					i.snapElements.push( {
						item: this,
						width: $t.outerWidth(), height: $t.outerHeight(),
						top: $o.top, left: $o.left
					} );
				}
			} );

	},
	drag: function( event, ui, inst ) {

		var ts, bs, ls, rs, l, r, t, b, i, first,
			o = inst.options,
			d = o.snapTolerance,
			x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;

		for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {

			l = inst.snapElements[ i ].left - inst.margins.left;
			r = l + inst.snapElements[ i ].width;
			t = inst.snapElements[ i ].top - inst.margins.top;
			b = t + inst.snapElements[ i ].height;

			if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
					!$.contains( inst.snapElements[ i ].item.ownerDocument,
					inst.snapElements[ i ].item ) ) {
				if ( inst.snapElements[ i ].snapping ) {
					( inst.options.snap.release &&
						inst.options.snap.release.call(
							inst.element,
							event,
							$.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
						) );
				}
				inst.snapElements[ i ].snapping = false;
				continue;
			}

			if ( o.snapMode !== "inner" ) {
				ts = Math.abs( t - y2 ) <= d;
				bs = Math.abs( b - y1 ) <= d;
				ls = Math.abs( l - x2 ) <= d;
				rs = Math.abs( r - x1 ) <= d;
				if ( ts ) {
					ui.position.top = inst._convertPositionTo( "relative", {
						top: t - inst.helperProportions.height,
						left: 0
					} ).top;
				}
				if ( bs ) {
					ui.position.top = inst._convertPositionTo( "relative", {
						top: b,
						left: 0
					} ).top;
				}
				if ( ls ) {
					ui.position.left = inst._convertPositionTo( "relative", {
						top: 0,
						left: l - inst.helperProportions.width
					} ).left;
				}
				if ( rs ) {
					ui.position.left = inst._convertPositionTo( "relative", {
						top: 0,
						left: r
					} ).left;
				}
			}

			first = ( ts || bs || ls || rs );

			if ( o.snapMode !== "outer" ) {
				ts = Math.abs( t - y1 ) <= d;
				bs = Math.abs( b - y2 ) <= d;
				ls = Math.abs( l - x1 ) <= d;
				rs = Math.abs( r - x2 ) <= d;
				if ( ts ) {
					ui.position.top = inst._convertPositionTo( "relative", {
						top: t,
						left: 0
					} ).top;
				}
				if ( bs ) {
					ui.position.top = inst._convertPositionTo( "relative", {
						top: b - inst.helperProportions.height,
						left: 0
					} ).top;
				}
				if ( ls ) {
					ui.position.left = inst._convertPositionTo( "relative", {
						top: 0,
						left: l
					} ).left;
				}
				if ( rs ) {
					ui.position.left = inst._convertPositionTo( "relative", {
						top: 0,
						left: r - inst.helperProportions.width
					} ).left;
				}
			}

			if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
				( inst.options.snap.snap &&
					inst.options.snap.snap.call(
						inst.element,
						event,
						$.extend( inst._uiHash(), {
							snapItem: inst.snapElements[ i ].item
						} ) ) );
			}
			inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );

		}

	}
} );

$.ui.plugin.add( "draggable", "stack", {
	start: function( event, ui, instance ) {
		var min,
			o = instance.options,
			group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
				return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
					( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
			} );

		if ( !group.length ) { return; }

		min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
		$( group ).each( function( i ) {
			$( this ).css( "zIndex", min + i );
		} );
		this.css( "zIndex", ( min + group.length ) );
	}
} );

$.ui.plugin.add( "draggable", "zIndex", {
	start: function( event, ui, instance ) {
		var t = $( ui.helper ),
			o = instance.options;

		if ( t.css( "zIndex" ) ) {
			o._zIndex = t.css( "zIndex" );
		}
		t.css( "zIndex", o.zIndex );
	},
	stop: function( event, ui, instance ) {
		var o = instance.options;

		if ( o._zIndex ) {
			$( ui.helper ).css( "zIndex", o._zIndex );
		}
	}
} );

var widgetsDraggable = $.ui.draggable;


/*!
 * jQuery UI Resizable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Resizable
//>>group: Interactions
//>>description: Enables resize functionality for any element.
//>>docs: http://api.jqueryui.com/resizable/
//>>demos: http://jqueryui.com/resizable/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/resizable.css
//>>css.theme: ../../themes/base/theme.css



$.widget( "ui.resizable", $.ui.mouse, {
	version: "1.12.1",
	widgetEventPrefix: "resize",
	options: {
		alsoResize: false,
		animate: false,
		animateDuration: "slow",
		animateEasing: "swing",
		aspectRatio: false,
		autoHide: false,
		classes: {
			"ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
		},
		containment: false,
		ghost: false,
		grid: false,
		handles: "e,s,se",
		helper: false,
		maxHeight: null,
		maxWidth: null,
		minHeight: 10,
		minWidth: 10,

		// See #7960
		zIndex: 90,

		// Callbacks
		resize: null,
		start: null,
		stop: null
	},

	_num: function( value ) {
		return parseFloat( value ) || 0;
	},

	_isNumber: function( value ) {
		return !isNaN( parseFloat( value ) );
	},

	_hasScroll: function( el, a ) {

		if ( $( el ).css( "overflow" ) === "hidden" ) {
			return false;
		}

		var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
			has = false;

		if ( el[ scroll ] > 0 ) {
			return true;
		}

		// TODO: determine which cases actually cause this to happen
		// if the element doesn't have the scroll set, see if it's possible to
		// set the scroll
		el[ scroll ] = 1;
		has = ( el[ scroll ] > 0 );
		el[ scroll ] = 0;
		return has;
	},

	_create: function() {

		var margins,
			o = this.options,
			that = this;
		this._addClass( "ui-resizable" );

		$.extend( this, {
			_aspectRatio: !!( o.aspectRatio ),
			aspectRatio: o.aspectRatio,
			originalElement: this.element,
			_proportionallyResizeElements: [],
			_helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
		} );

		// Wrap the element if it cannot hold child nodes
		if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {

			this.element.wrap(
				$( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
					position: this.element.css( "position" ),
					width: this.element.outerWidth(),
					height: this.element.outerHeight(),
					top: this.element.css( "top" ),
					left: this.element.css( "left" )
				} )
			);

			this.element = this.element.parent().data(
				"ui-resizable", this.element.resizable( "instance" )
			);

			this.elementIsWrapper = true;

			margins = {
				marginTop: this.originalElement.css( "marginTop" ),
				marginRight: this.originalElement.css( "marginRight" ),
				marginBottom: this.originalElement.css( "marginBottom" ),
				marginLeft: this.originalElement.css( "marginLeft" )
			};

			this.element.css( margins );
			this.originalElement.css( "margin", 0 );

			// support: Safari
			// Prevent Safari textarea resize
			this.originalResizeStyle = this.originalElement.css( "resize" );
			this.originalElement.css( "resize", "none" );

			this._proportionallyResizeElements.push( this.originalElement.css( {
				position: "static",
				zoom: 1,
				display: "block"
			} ) );

			// Support: IE9
			// avoid IE jump (hard set the margin)
			this.originalElement.css( margins );

			this._proportionallyResize();
		}

		this._setupHandles();

		if ( o.autoHide ) {
			$( this.element )
				.on( "mouseenter", function() {
					if ( o.disabled ) {
						return;
					}
					that._removeClass( "ui-resizable-autohide" );
					that._handles.show();
				} )
				.on( "mouseleave", function() {
					if ( o.disabled ) {
						return;
					}
					if ( !that.resizing ) {
						that._addClass( "ui-resizable-autohide" );
						that._handles.hide();
					}
				} );
		}

		this._mouseInit();
	},

	_destroy: function() {

		this._mouseDestroy();

		var wrapper,
			_destroy = function( exp ) {
				$( exp )
					.removeData( "resizable" )
					.removeData( "ui-resizable" )
					.off( ".resizable" )
					.find( ".ui-resizable-handle" )
						.remove();
			};

		// TODO: Unwrap at same DOM position
		if ( this.elementIsWrapper ) {
			_destroy( this.element );
			wrapper = this.element;
			this.originalElement.css( {
				position: wrapper.css( "position" ),
				width: wrapper.outerWidth(),
				height: wrapper.outerHeight(),
				top: wrapper.css( "top" ),
				left: wrapper.css( "left" )
			} ).insertAfter( wrapper );
			wrapper.remove();
		}

		this.originalElement.css( "resize", this.originalResizeStyle );
		_destroy( this.originalElement );

		return this;
	},

	_setOption: function( key, value ) {
		this._super( key, value );

		switch ( key ) {
		case "handles":
			this._removeHandles();
			this._setupHandles();
			break;
		default:
			break;
		}
	},

	_setupHandles: function() {
		var o = this.options, handle, i, n, hname, axis, that = this;
		this.handles = o.handles ||
			( !$( ".ui-resizable-handle", this.element ).length ?
				"e,s,se" : {
					n: ".ui-resizable-n",
					e: ".ui-resizable-e",
					s: ".ui-resizable-s",
					w: ".ui-resizable-w",
					se: ".ui-resizable-se",
					sw: ".ui-resizable-sw",
					ne: ".ui-resizable-ne",
					nw: ".ui-resizable-nw"
				} );

		this._handles = $();
		if ( this.handles.constructor === String ) {

			if ( this.handles === "all" ) {
				this.handles = "n,e,s,w,se,sw,ne,nw";
			}

			n = this.handles.split( "," );
			this.handles = {};

			for ( i = 0; i < n.length; i++ ) {

				handle = $.trim( n[ i ] );
				hname = "ui-resizable-" + handle;
				axis = $( "<div>" );
				this._addClass( axis, "ui-resizable-handle " + hname );

				axis.css( { zIndex: o.zIndex } );

				this.handles[ handle ] = ".ui-resizable-" + handle;
				this.element.append( axis );
			}

		}

		this._renderAxis = function( target ) {

			var i, axis, padPos, padWrapper;

			target = target || this.element;

			for ( i in this.handles ) {

				if ( this.handles[ i ].constructor === String ) {
					this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
				} else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
					this.handles[ i ] = $( this.handles[ i ] );
					this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
				}

				if ( this.elementIsWrapper &&
						this.originalElement[ 0 ]
							.nodeName
							.match( /^(textarea|input|select|button)$/i ) ) {
					axis = $( this.handles[ i ], this.element );

					padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
						axis.outerHeight() :
						axis.outerWidth();

					padPos = [ "padding",
						/ne|nw|n/.test( i ) ? "Top" :
						/se|sw|s/.test( i ) ? "Bottom" :
						/^e$/.test( i ) ? "Right" : "Left" ].join( "" );

					target.css( padPos, padWrapper );

					this._proportionallyResize();
				}

				this._handles = this._handles.add( this.handles[ i ] );
			}
		};

		// TODO: make renderAxis a prototype function
		this._renderAxis( this.element );

		this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
		this._handles.disableSelection();

		this._handles.on( "mouseover", function() {
			if ( !that.resizing ) {
				if ( this.className ) {
					axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
				}
				that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
			}
		} );

		if ( o.autoHide ) {
			this._handles.hide();
			this._addClass( "ui-resizable-autohide" );
		}
	},

	_removeHandles: function() {
		this._handles.remove();
	},

	_mouseCapture: function( event ) {
		var i, handle,
			capture = false;

		for ( i in this.handles ) {
			handle = $( this.handles[ i ] )[ 0 ];
			if ( handle === event.target || $.contains( handle, event.target ) ) {
				capture = true;
			}
		}

		return !this.options.disabled && capture;
	},

	_mouseStart: function( event ) {

		var curleft, curtop, cursor,
			o = this.options,
			el = this.element;

		this.resizing = true;

		this._renderProxy();

		curleft = this._num( this.helper.css( "left" ) );
		curtop = this._num( this.helper.css( "top" ) );

		if ( o.containment ) {
			curleft += $( o.containment ).scrollLeft() || 0;
			curtop += $( o.containment ).scrollTop() || 0;
		}

		this.offset = this.helper.offset();
		this.position = { left: curleft, top: curtop };

		this.size = this._helper ? {
				width: this.helper.width(),
				height: this.helper.height()
			} : {
				width: el.width(),
				height: el.height()
			};

		this.originalSize = this._helper ? {
				width: el.outerWidth(),
				height: el.outerHeight()
			} : {
				width: el.width(),
				height: el.height()
			};

		this.sizeDiff = {
			width: el.outerWidth() - el.width(),
			height: el.outerHeight() - el.height()
		};

		this.originalPosition = { left: curleft, top: curtop };
		this.originalMousePosition = { left: event.pageX, top: event.pageY };

		this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
			o.aspectRatio :
			( ( this.originalSize.width / this.originalSize.height ) || 1 );

		cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
		$( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );

		this._addClass( "ui-resizable-resizing" );
		this._propagate( "start", event );
		return true;
	},

	_mouseDrag: function( event ) {

		var data, props,
			smp = this.originalMousePosition,
			a = this.axis,
			dx = ( event.pageX - smp.left ) || 0,
			dy = ( event.pageY - smp.top ) || 0,
			trigger = this._change[ a ];

		this._updatePrevProperties();

		if ( !trigger ) {
			return false;
		}

		data = trigger.apply( this, [ event, dx, dy ] );

		this._updateVirtualBoundaries( event.shiftKey );
		if ( this._aspectRatio || event.shiftKey ) {
			data = this._updateRatio( data, event );
		}

		data = this._respectSize( data, event );

		this._updateCache( data );

		this._propagate( "resize", event );

		props = this._applyChanges();

		if ( !this._helper && this._proportionallyResizeElements.length ) {
			this._proportionallyResize();
		}

		if ( !$.isEmptyObject( props ) ) {
			this._updatePrevProperties();
			this._trigger( "resize", event, this.ui() );
			this._applyChanges();
		}

		return false;
	},

	_mouseStop: function( event ) {

		this.resizing = false;
		var pr, ista, soffseth, soffsetw, s, left, top,
			o = this.options, that = this;

		if ( this._helper ) {

			pr = this._proportionallyResizeElements;
			ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
			soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
			soffsetw = ista ? 0 : that.sizeDiff.width;

			s = {
				width: ( that.helper.width()  - soffsetw ),
				height: ( that.helper.height() - soffseth )
			};
			left = ( parseFloat( that.element.css( "left" ) ) +
				( that.position.left - that.originalPosition.left ) ) || null;
			top = ( parseFloat( that.element.css( "top" ) ) +
				( that.position.top - that.originalPosition.top ) ) || null;

			if ( !o.animate ) {
				this.element.css( $.extend( s, { top: top, left: left } ) );
			}

			that.helper.height( that.size.height );
			that.helper.width( that.size.width );

			if ( this._helper && !o.animate ) {
				this._proportionallyResize();
			}
		}

		$( "body" ).css( "cursor", "auto" );

		this._removeClass( "ui-resizable-resizing" );

		this._propagate( "stop", event );

		if ( this._helper ) {
			this.helper.remove();
		}

		return false;

	},

	_updatePrevProperties: function() {
		this.prevPosition = {
			top: this.position.top,
			left: this.position.left
		};
		this.prevSize = {
			width: this.size.width,
			height: this.size.height
		};
	},

	_applyChanges: function() {
		var props = {};

		if ( this.position.top !== this.prevPosition.top ) {
			props.top = this.position.top + "px";
		}
		if ( this.position.left !== this.prevPosition.left ) {
			props.left = this.position.left + "px";
		}
		if ( this.size.width !== this.prevSize.width ) {
			props.width = this.size.width + "px";
		}
		if ( this.size.height !== this.prevSize.height ) {
			props.height = this.size.height + "px";
		}

		this.helper.css( props );

		return props;
	},

	_updateVirtualBoundaries: function( forceAspectRatio ) {
		var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
			o = this.options;

		b = {
			minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
			maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
			minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
			maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
		};

		if ( this._aspectRatio || forceAspectRatio ) {
			pMinWidth = b.minHeight * this.aspectRatio;
			pMinHeight = b.minWidth / this.aspectRatio;
			pMaxWidth = b.maxHeight * this.aspectRatio;
			pMaxHeight = b.maxWidth / this.aspectRatio;

			if ( pMinWidth > b.minWidth ) {
				b.minWidth = pMinWidth;
			}
			if ( pMinHeight > b.minHeight ) {
				b.minHeight = pMinHeight;
			}
			if ( pMaxWidth < b.maxWidth ) {
				b.maxWidth = pMaxWidth;
			}
			if ( pMaxHeight < b.maxHeight ) {
				b.maxHeight = pMaxHeight;
			}
		}
		this._vBoundaries = b;
	},

	_updateCache: function( data ) {
		this.offset = this.helper.offset();
		if ( this._isNumber( data.left ) ) {
			this.position.left = data.left;
		}
		if ( this._isNumber( data.top ) ) {
			this.position.top = data.top;
		}
		if ( this._isNumber( data.height ) ) {
			this.size.height = data.height;
		}
		if ( this._isNumber( data.width ) ) {
			this.size.width = data.width;
		}
	},

	_updateRatio: function( data ) {

		var cpos = this.position,
			csize = this.size,
			a = this.axis;

		if ( this._isNumber( data.height ) ) {
			data.width = ( data.height * this.aspectRatio );
		} else if ( this._isNumber( data.width ) ) {
			data.height = ( data.width / this.aspectRatio );
		}

		if ( a === "sw" ) {
			data.left = cpos.left + ( csize.width - data.width );
			data.top = null;
		}
		if ( a === "nw" ) {
			data.top = cpos.top + ( csize.height - data.height );
			data.left = cpos.left + ( csize.width - data.width );
		}

		return data;
	},

	_respectSize: function( data ) {

		var o = this._vBoundaries,
			a = this.axis,
			ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
			ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
			isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
			isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
			dw = this.originalPosition.left + this.originalSize.width,
			dh = this.originalPosition.top + this.originalSize.height,
			cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
		if ( isminw ) {
			data.width = o.minWidth;
		}
		if ( isminh ) {
			data.height = o.minHeight;
		}
		if ( ismaxw ) {
			data.width = o.maxWidth;
		}
		if ( ismaxh ) {
			data.height = o.maxHeight;
		}

		if ( isminw && cw ) {
			data.left = dw - o.minWidth;
		}
		if ( ismaxw && cw ) {
			data.left = dw - o.maxWidth;
		}
		if ( isminh && ch ) {
			data.top = dh - o.minHeight;
		}
		if ( ismaxh && ch ) {
			data.top = dh - o.maxHeight;
		}

		// Fixing jump error on top/left - bug #2330
		if ( !data.width && !data.height && !data.left && data.top ) {
			data.top = null;
		} else if ( !data.width && !data.height && !data.top && data.left ) {
			data.left = null;
		}

		return data;
	},

	_getPaddingPlusBorderDimensions: function( element ) {
		var i = 0,
			widths = [],
			borders = [
				element.css( "borderTopWidth" ),
				element.css( "borderRightWidth" ),
				element.css( "borderBottomWidth" ),
				element.css( "borderLeftWidth" )
			],
			paddings = [
				element.css( "paddingTop" ),
				element.css( "paddingRight" ),
				element.css( "paddingBottom" ),
				element.css( "paddingLeft" )
			];

		for ( ; i < 4; i++ ) {
			widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
			widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
		}

		return {
			height: widths[ 0 ] + widths[ 2 ],
			width: widths[ 1 ] + widths[ 3 ]
		};
	},

	_proportionallyResize: function() {

		if ( !this._proportionallyResizeElements.length ) {
			return;
		}

		var prel,
			i = 0,
			element = this.helper || this.element;

		for ( ; i < this._proportionallyResizeElements.length; i++ ) {

			prel = this._proportionallyResizeElements[ i ];

			// TODO: Seems like a bug to cache this.outerDimensions
			// considering that we are in a loop.
			if ( !this.outerDimensions ) {
				this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
			}

			prel.css( {
				height: ( element.height() - this.outerDimensions.height ) || 0,
				width: ( element.width() - this.outerDimensions.width ) || 0
			} );

		}

	},

	_renderProxy: function() {

		var el = this.element, o = this.options;
		this.elementOffset = el.offset();

		if ( this._helper ) {

			this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" );

			this._addClass( this.helper, this._helper );
			this.helper.css( {
				width: this.element.outerWidth(),
				height: this.element.outerHeight(),
				position: "absolute",
				left: this.elementOffset.left + "px",
				top: this.elementOffset.top + "px",
				zIndex: ++o.zIndex //TODO: Don't modify option
			} );

			this.helper
				.appendTo( "body" )
				.disableSelection();

		} else {
			this.helper = this.element;
		}

	},

	_change: {
		e: function( event, dx ) {
			return { width: this.originalSize.width + dx };
		},
		w: function( event, dx ) {
			var cs = this.originalSize, sp = this.originalPosition;
			return { left: sp.left + dx, width: cs.width - dx };
		},
		n: function( event, dx, dy ) {
			var cs = this.originalSize, sp = this.originalPosition;
			return { top: sp.top + dy, height: cs.height - dy };
		},
		s: function( event, dx, dy ) {
			return { height: this.originalSize.height + dy };
		},
		se: function( event, dx, dy ) {
			return $.extend( this._change.s.apply( this, arguments ),
				this._change.e.apply( this, [ event, dx, dy ] ) );
		},
		sw: function( event, dx, dy ) {
			return $.extend( this._change.s.apply( this, arguments ),
				this._change.w.apply( this, [ event, dx, dy ] ) );
		},
		ne: function( event, dx, dy ) {
			return $.extend( this._change.n.apply( this, arguments ),
				this._change.e.apply( this, [ event, dx, dy ] ) );
		},
		nw: function( event, dx, dy ) {
			return $.extend( this._change.n.apply( this, arguments ),
				this._change.w.apply( this, [ event, dx, dy ] ) );
		}
	},

	_propagate: function( n, event ) {
		$.ui.plugin.call( this, n, [ event, this.ui() ] );
		( n !== "resize" && this._trigger( n, event, this.ui() ) );
	},

	plugins: {},

	ui: function() {
		return {
			originalElement: this.originalElement,
			element: this.element,
			helper: this.helper,
			position: this.position,
			size: this.size,
			originalSize: this.originalSize,
			originalPosition: this.originalPosition
		};
	}

} );

/*
 * Resizable Extensions
 */

$.ui.plugin.add( "resizable", "animate", {

	stop: function( event ) {
		var that = $( this ).resizable( "instance" ),
			o = that.options,
			pr = that._proportionallyResizeElements,
			ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
			soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
			soffsetw = ista ? 0 : that.sizeDiff.width,
			style = {
				width: ( that.size.width - soffsetw ),
				height: ( that.size.height - soffseth )
			},
			left = ( parseFloat( that.element.css( "left" ) ) +
				( that.position.left - that.originalPosition.left ) ) || null,
			top = ( parseFloat( that.element.css( "top" ) ) +
				( that.position.top - that.originalPosition.top ) ) || null;

		that.element.animate(
			$.extend( style, top && left ? { top: top, left: left } : {} ), {
				duration: o.animateDuration,
				easing: o.animateEasing,
				step: function() {

					var data = {
						width: parseFloat( that.element.css( "width" ) ),
						height: parseFloat( that.element.css( "height" ) ),
						top: parseFloat( that.element.css( "top" ) ),
						left: parseFloat( that.element.css( "left" ) )
					};

					if ( pr && pr.length ) {
						$( pr[ 0 ] ).css( { width: data.width, height: data.height } );
					}

					// Propagating resize, and updating values for each animation step
					that._updateCache( data );
					that._propagate( "resize", event );

				}
			}
		);
	}

} );

$.ui.plugin.add( "resizable", "containment", {

	start: function() {
		var element, p, co, ch, cw, width, height,
			that = $( this ).resizable( "instance" ),
			o = that.options,
			el = that.element,
			oc = o.containment,
			ce = ( oc instanceof $ ) ?
				oc.get( 0 ) :
				( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;

		if ( !ce ) {
			return;
		}

		that.containerElement = $( ce );

		if ( /document/.test( oc ) || oc === document ) {
			that.containerOffset = {
				left: 0,
				top: 0
			};
			that.containerPosition = {
				left: 0,
				top: 0
			};

			that.parentData = {
				element: $( document ),
				left: 0,
				top: 0,
				width: $( document ).width(),
				height: $( document ).height() || document.body.parentNode.scrollHeight
			};
		} else {
			element = $( ce );
			p = [];
			$( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
				p[ i ] = that._num( element.css( "padding" + name ) );
			} );

			that.containerOffset = element.offset();
			that.containerPosition = element.position();
			that.containerSize = {
				height: ( element.innerHeight() - p[ 3 ] ),
				width: ( element.innerWidth() - p[ 1 ] )
			};

			co = that.containerOffset;
			ch = that.containerSize.height;
			cw = that.containerSize.width;
			width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
			height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;

			that.parentData = {
				element: ce,
				left: co.left,
				top: co.top,
				width: width,
				height: height
			};
		}
	},

	resize: function( event ) {
		var woset, hoset, isParent, isOffsetRelative,
			that = $( this ).resizable( "instance" ),
			o = that.options,
			co = that.containerOffset,
			cp = that.position,
			pRatio = that._aspectRatio || event.shiftKey,
			cop = {
				top: 0,
				left: 0
			},
			ce = that.containerElement,
			continueResize = true;

		if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
			cop = co;
		}

		if ( cp.left < ( that._helper ? co.left : 0 ) ) {
			that.size.width = that.size.width +
				( that._helper ?
					( that.position.left - co.left ) :
					( that.position.left - cop.left ) );

			if ( pRatio ) {
				that.size.height = that.size.width / that.aspectRatio;
				continueResize = false;
			}
			that.position.left = o.helper ? co.left : 0;
		}

		if ( cp.top < ( that._helper ? co.top : 0 ) ) {
			that.size.height = that.size.height +
				( that._helper ?
					( that.position.top - co.top ) :
					that.position.top );

			if ( pRatio ) {
				that.size.width = that.size.height * that.aspectRatio;
				continueResize = false;
			}
			that.position.top = that._helper ? co.top : 0;
		}

		isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
		isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );

		if ( isParent && isOffsetRelative ) {
			that.offset.left = that.parentData.left + that.position.left;
			that.offset.top = that.parentData.top + that.position.top;
		} else {
			that.offset.left = that.element.offset().left;
			that.offset.top = that.element.offset().top;
		}

		woset = Math.abs( that.sizeDiff.width +
			( that._helper ?
				that.offset.left - cop.left :
				( that.offset.left - co.left ) ) );

		hoset = Math.abs( that.sizeDiff.height +
			( that._helper ?
				that.offset.top - cop.top :
				( that.offset.top - co.top ) ) );

		if ( woset + that.size.width >= that.parentData.width ) {
			that.size.width = that.parentData.width - woset;
			if ( pRatio ) {
				that.size.height = that.size.width / that.aspectRatio;
				continueResize = false;
			}
		}

		if ( hoset + that.size.height >= that.parentData.height ) {
			that.size.height = that.parentData.height - hoset;
			if ( pRatio ) {
				that.size.width = that.size.height * that.aspectRatio;
				continueResize = false;
			}
		}

		if ( !continueResize ) {
			that.position.left = that.prevPosition.left;
			that.position.top = that.prevPosition.top;
			that.size.width = that.prevSize.width;
			that.size.height = that.prevSize.height;
		}
	},

	stop: function() {
		var that = $( this ).resizable( "instance" ),
			o = that.options,
			co = that.containerOffset,
			cop = that.containerPosition,
			ce = that.containerElement,
			helper = $( that.helper ),
			ho = helper.offset(),
			w = helper.outerWidth() - that.sizeDiff.width,
			h = helper.outerHeight() - that.sizeDiff.height;

		if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
			$( this ).css( {
				left: ho.left - cop.left - co.left,
				width: w,
				height: h
			} );
		}

		if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
			$( this ).css( {
				left: ho.left - cop.left - co.left,
				width: w,
				height: h
			} );
		}
	}
} );

$.ui.plugin.add( "resizable", "alsoResize", {

	start: function() {
		var that = $( this ).resizable( "instance" ),
			o = that.options;

		$( o.alsoResize ).each( function() {
			var el = $( this );
			el.data( "ui-resizable-alsoresize", {
				width: parseFloat( el.width() ), height: parseFloat( el.height() ),
				left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
			} );
		} );
	},

	resize: function( event, ui ) {
		var that = $( this ).resizable( "instance" ),
			o = that.options,
			os = that.originalSize,
			op = that.originalPosition,
			delta = {
				height: ( that.size.height - os.height ) || 0,
				width: ( that.size.width - os.width ) || 0,
				top: ( that.position.top - op.top ) || 0,
				left: ( that.position.left - op.left ) || 0
			};

			$( o.alsoResize ).each( function() {
				var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
					css = el.parents( ui.originalElement[ 0 ] ).length ?
							[ "width", "height" ] :
							[ "width", "height", "top", "left" ];

				$.each( css, function( i, prop ) {
					var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
					if ( sum && sum >= 0 ) {
						style[ prop ] = sum || null;
					}
				} );

				el.css( style );
			} );
	},

	stop: function() {
		$( this ).removeData( "ui-resizable-alsoresize" );
	}
} );

$.ui.plugin.add( "resizable", "ghost", {

	start: function() {

		var that = $( this ).resizable( "instance" ), cs = that.size;

		that.ghost = that.originalElement.clone();
		that.ghost.css( {
			opacity: 0.25,
			display: "block",
			position: "relative",
			height: cs.height,
			width: cs.width,
			margin: 0,
			left: 0,
			top: 0
		} );

		that._addClass( that.ghost, "ui-resizable-ghost" );

		// DEPRECATED
		// TODO: remove after 1.12
		if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {

			// Ghost option
			that.ghost.addClass( this.options.ghost );
		}

		that.ghost.appendTo( that.helper );

	},

	resize: function() {
		var that = $( this ).resizable( "instance" );
		if ( that.ghost ) {
			that.ghost.css( {
				position: "relative",
				height: that.size.height,
				width: that.size.width
			} );
		}
	},

	stop: function() {
		var that = $( this ).resizable( "instance" );
		if ( that.ghost && that.helper ) {
			that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
		}
	}

} );

$.ui.plugin.add( "resizable", "grid", {

	resize: function() {
		var outerDimensions,
			that = $( this ).resizable( "instance" ),
			o = that.options,
			cs = that.size,
			os = that.originalSize,
			op = that.originalPosition,
			a = that.axis,
			grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
			gridX = ( grid[ 0 ] || 1 ),
			gridY = ( grid[ 1 ] || 1 ),
			ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
			oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
			newWidth = os.width + ox,
			newHeight = os.height + oy,
			isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
			isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
			isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
			isMinHeight = o.minHeight && ( o.minHeight > newHeight );

		o.grid = grid;

		if ( isMinWidth ) {
			newWidth += gridX;
		}
		if ( isMinHeight ) {
			newHeight += gridY;
		}
		if ( isMaxWidth ) {
			newWidth -= gridX;
		}
		if ( isMaxHeight ) {
			newHeight -= gridY;
		}

		if ( /^(se|s|e)$/.test( a ) ) {
			that.size.width = newWidth;
			that.size.height = newHeight;
		} else if ( /^(ne)$/.test( a ) ) {
			that.size.width = newWidth;
			that.size.height = newHeight;
			that.position.top = op.top - oy;
		} else if ( /^(sw)$/.test( a ) ) {
			that.size.width = newWidth;
			that.size.height = newHeight;
			that.position.left = op.left - ox;
		} else {
			if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
				outerDimensions = that._getPaddingPlusBorderDimensions( this );
			}

			if ( newHeight - gridY > 0 ) {
				that.size.height = newHeight;
				that.position.top = op.top - oy;
			} else {
				newHeight = gridY - outerDimensions.height;
				that.size.height = newHeight;
				that.position.top = op.top + os.height - newHeight;
			}
			if ( newWidth - gridX > 0 ) {
				that.size.width = newWidth;
				that.position.left = op.left - ox;
			} else {
				newWidth = gridX - outerDimensions.width;
				that.size.width = newWidth;
				that.position.left = op.left + os.width - newWidth;
			}
		}
	}

} );

var widgetsResizable = $.ui.resizable;


/*!
 * jQuery UI Dialog 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Dialog
//>>group: Widgets
//>>description: Displays customizable dialog windows.
//>>docs: http://api.jqueryui.com/dialog/
//>>demos: http://jqueryui.com/dialog/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/dialog.css
//>>css.theme: ../../themes/base/theme.css



$.widget( "ui.dialog", {
	version: "1.12.1",
	options: {
		appendTo: "body",
		autoOpen: true,
		buttons: [],
		classes: {
			"ui-dialog": "ui-corner-all",
			"ui-dialog-titlebar": "ui-corner-all"
		},
		closeOnEscape: true,
		closeText: "Close",
		draggable: true,
		hide: null,
		height: "auto",
		maxHeight: null,
		maxWidth: null,
		minHeight: 150,
		minWidth: 150,
		modal: false,
		position: {
			my: "center",
			at: "center",
			of: window,
			collision: "fit",

			// Ensure the titlebar is always visible
			using: function( pos ) {
				var topOffset = $( this ).css( pos ).offset().top;
				if ( topOffset < 0 ) {
					$( this ).css( "top", pos.top - topOffset );
				}
			}
		},
		resizable: true,
		show: null,
		title: null,
		width: 300,

		// Callbacks
		beforeClose: null,
		close: null,
		drag: null,
		dragStart: null,
		dragStop: null,
		focus: null,
		open: null,
		resize: null,
		resizeStart: null,
		resizeStop: null
	},

	sizeRelatedOptions: {
		buttons: true,
		height: true,
		maxHeight: true,
		maxWidth: true,
		minHeight: true,
		minWidth: true,
		width: true
	},

	resizableRelatedOptions: {
		maxHeight: true,
		maxWidth: true,
		minHeight: true,
		minWidth: true
	},

	_create: function() {
		this.originalCss = {
			display: this.element[ 0 ].style.display,
			width: this.element[ 0 ].style.width,
			minHeight: this.element[ 0 ].style.minHeight,
			maxHeight: this.element[ 0 ].style.maxHeight,
			height: this.element[ 0 ].style.height
		};
		this.originalPosition = {
			parent: this.element.parent(),
			index: this.element.parent().children().index( this.element )
		};
		this.originalTitle = this.element.attr( "title" );
		if ( this.options.title == null && this.originalTitle != null ) {
			this.options.title = this.originalTitle;
		}

		// Dialogs can't be disabled
		if ( this.options.disabled ) {
			this.options.disabled = false;
		}

		this._createWrapper();

		this.element
			.show()
			.removeAttr( "title" )
			.appendTo( this.uiDialog );

		this._addClass( "ui-dialog-content", "ui-widget-content" );

		this._createTitlebar();
		this._createButtonPane();

		if ( this.options.draggable && $.fn.draggable ) {
			this._makeDraggable();
		}
		if ( this.options.resizable && $.fn.resizable ) {
			this._makeResizable();
		}

		this._isOpen = false;

		this._trackFocus();
	},

	_init: function() {
		if ( this.options.autoOpen ) {
			this.open();
		}
	},

	_appendTo: function() {
		var element = this.options.appendTo;
		if ( element && ( element.jquery || element.nodeType ) ) {
			return $( element );
		}
		return this.document.find( element || "body" ).eq( 0 );
	},

	_destroy: function() {
		var next,
			originalPosition = this.originalPosition;

		this._untrackInstance();
		this._destroyOverlay();

		this.element
			.removeUniqueId()
			.css( this.originalCss )

			// Without detaching first, the following becomes really slow
			.detach();

		this.uiDialog.remove();

		if ( this.originalTitle ) {
			this.element.attr( "title", this.originalTitle );
		}

		next = originalPosition.parent.children().eq( originalPosition.index );

		// Don't try to place the dialog next to itself (#8613)
		if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
			next.before( this.element );
		} else {
			originalPosition.parent.append( this.element );
		}
	},

	widget: function() {
		return this.uiDialog;
	},

	disable: $.noop,
	enable: $.noop,

	close: function( event ) {
		var that = this;

		if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
			return;
		}

		this._isOpen = false;
		this._focusedElement = null;
		this._destroyOverlay();
		this._untrackInstance();

		if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {

			// Hiding a focused element doesn't trigger blur in WebKit
			// so in case we have nothing to focus on, explicitly blur the active element
			// https://bugs.webkit.org/show_bug.cgi?id=47182
			$.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
		}

		this._hide( this.uiDialog, this.options.hide, function() {
			that._trigger( "close", event );
		} );
	},

	isOpen: function() {
		return this._isOpen;
	},

	moveToTop: function() {
		this._moveToTop();
	},

	_moveToTop: function( event, silent ) {
		var moved = false,
			zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
				return +$( this ).css( "z-index" );
			} ).get(),
			zIndexMax = Math.max.apply( null, zIndices );

		if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
			this.uiDialog.css( "z-index", zIndexMax + 1 );
			moved = true;
		}

		if ( moved && !silent ) {
			this._trigger( "focus", event );
		}
		return moved;
	},

	open: function() {
		var that = this;
		if ( this._isOpen ) {
			if ( this._moveToTop() ) {
				this._focusTabbable();
			}
			return;
		}

		this._isOpen = true;
		this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );

		this._size();
		this._position();
		this._createOverlay();
		this._moveToTop( null, true );

		// Ensure the overlay is moved to the top with the dialog, but only when
		// opening. The overlay shouldn't move after the dialog is open so that
		// modeless dialogs opened after the modal dialog stack properly.
		if ( this.overlay ) {
			this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
		}

		this._show( this.uiDialog, this.options.show, function() {
			that._focusTabbable();
			that._trigger( "focus" );
		} );

		// Track the dialog immediately upon openening in case a focus event
		// somehow occurs outside of the dialog before an element inside the
		// dialog is focused (#10152)
		this._makeFocusTarget();

		this._trigger( "open" );
	},

	_focusTabbable: function() {

		// Set focus to the first match:
		// 1. An element that was focused previously
		// 2. First element inside the dialog matching [autofocus]
		// 3. Tabbable element inside the content element
		// 4. Tabbable element inside the buttonpane
		// 5. The close button
		// 6. The dialog itself
		var hasFocus = this._focusedElement;
		if ( !hasFocus ) {
			hasFocus = this.element.find( "[autofocus]" );
		}
		if ( !hasFocus.length ) {
			hasFocus = this.element.find( ":tabbable" );
		}
		if ( !hasFocus.length ) {
			hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
		}
		if ( !hasFocus.length ) {
			hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
		}
		if ( !hasFocus.length ) {
			hasFocus = this.uiDialog;
		}
		hasFocus.eq( 0 ).trigger( "focus" );
	},

	_keepFocus: function( event ) {
		function checkFocus() {
			var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
				isActive = this.uiDialog[ 0 ] === activeElement ||
					$.contains( this.uiDialog[ 0 ], activeElement );
			if ( !isActive ) {
				this._focusTabbable();
			}
		}
		event.preventDefault();
		checkFocus.call( this );

		// support: IE
		// IE <= 8 doesn't prevent moving focus even with event.preventDefault()
		// so we check again later
		this._delay( checkFocus );
	},

	_createWrapper: function() {
		this.uiDialog = $( "<div>" )
			.hide()
			.attr( {

				// Setting tabIndex makes the div focusable
				tabIndex: -1,
				role: "dialog"
			} )
			.appendTo( this._appendTo() );

		this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
		this._on( this.uiDialog, {
			keydown: function( event ) {
				if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
						event.keyCode === $.ui.keyCode.ESCAPE ) {
					event.preventDefault();
					this.close( event );
					return;
				}

				// Prevent tabbing out of dialogs
				if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
					return;
				}
				var tabbables = this.uiDialog.find( ":tabbable" ),
					first = tabbables.filter( ":first" ),
					last = tabbables.filter( ":last" );

				if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
						!event.shiftKey ) {
					this._delay( function() {
						first.trigger( "focus" );
					} );
					event.preventDefault();
				} else if ( ( event.target === first[ 0 ] ||
						event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
					this._delay( function() {
						last.trigger( "focus" );
					} );
					event.preventDefault();
				}
			},
			mousedown: function( event ) {
				if ( this._moveToTop( event ) ) {
					this._focusTabbable();
				}
			}
		} );

		// We assume that any existing aria-describedby attribute means
		// that the dialog content is marked up properly
		// otherwise we brute force the content as the description
		if ( !this.element.find( "[aria-describedby]" ).length ) {
			this.uiDialog.attr( {
				"aria-describedby": this.element.uniqueId().attr( "id" )
			} );
		}
	},

	_createTitlebar: function() {
		var uiDialogTitle;

		this.uiDialogTitlebar = $( "<div>" );
		this._addClass( this.uiDialogTitlebar,
			"ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
		this._on( this.uiDialogTitlebar, {
			mousedown: function( event ) {

				// Don't prevent click on close button (#8838)
				// Focusing a dialog that is partially scrolled out of view
				// causes the browser to scroll it into view, preventing the click event
				if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {

					// Dialog isn't getting focus when dragging (#8063)
					this.uiDialog.trigger( "focus" );
				}
			}
		} );

		// Support: IE
		// Use type="button" to prevent enter keypresses in textboxes from closing the
		// dialog in IE (#9312)
		this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
			.button( {
				label: $( "<a>" ).text( this.options.closeText ).html(),
				icon: "ui-icon-closethick",
				showLabel: false
			} )
			.appendTo( this.uiDialogTitlebar );

		this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
		this._on( this.uiDialogTitlebarClose, {
			click: function( event ) {
				event.preventDefault();
				this.close( event );
			}
		} );

		uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
		this._addClass( uiDialogTitle, "ui-dialog-title" );
		this._title( uiDialogTitle );

		this.uiDialogTitlebar.prependTo( this.uiDialog );

		this.uiDialog.attr( {
			"aria-labelledby": uiDialogTitle.attr( "id" )
		} );
	},

	_title: function( title ) {
		if ( this.options.title ) {
			title.text( this.options.title );
		} else {
			title.html( "&#160;" );
		}
	},

	_createButtonPane: function() {
		this.uiDialogButtonPane = $( "<div>" );
		this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
			"ui-widget-content ui-helper-clearfix" );

		this.uiButtonSet = $( "<div>" )
			.appendTo( this.uiDialogButtonPane );
		this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );

		this._createButtons();
	},

	_createButtons: function() {
		var that = this,
			buttons = this.options.buttons;

		// If we already have a button pane, remove it
		this.uiDialogButtonPane.remove();
		this.uiButtonSet.empty();

		if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
			this._removeClass( this.uiDialog, "ui-dialog-buttons" );
			return;
		}

		$.each( buttons, function( name, props ) {
			var click, buttonOptions;
			props = $.isFunction( props ) ?
				{ click: props, text: name } :
				props;

			// Default to a non-submitting button
			props = $.extend( { type: "button" }, props );

			// Change the context for the click callback to be the main element
			click = props.click;
			buttonOptions = {
				icon: props.icon,
				iconPosition: props.iconPosition,
				showLabel: props.showLabel,

				// Deprecated options
				icons: props.icons,
				text: props.text
			};

			delete props.click;
			delete props.icon;
			delete props.iconPosition;
			delete props.showLabel;

			// Deprecated options
			delete props.icons;
			if ( typeof props.text === "boolean" ) {
				delete props.text;
			}

			$( "<button></button>", props )
				.button( buttonOptions )
				.appendTo( that.uiButtonSet )
				.on( "click", function() {
					click.apply( that.element[ 0 ], arguments );
				} );
		} );
		this._addClass( this.uiDialog, "ui-dialog-buttons" );
		this.uiDialogButtonPane.appendTo( this.uiDialog );
	},

	_makeDraggable: function() {
		var that = this,
			options = this.options;

		function filteredUi( ui ) {
			return {
				position: ui.position,
				offset: ui.offset
			};
		}

		this.uiDialog.draggable( {
			cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
			handle: ".ui-dialog-titlebar",
			containment: "document",
			start: function( event, ui ) {
				that._addClass( $( this ), "ui-dialog-dragging" );
				that._blockFrames();
				that._trigger( "dragStart", event, filteredUi( ui ) );
			},
			drag: function( event, ui ) {
				that._trigger( "drag", event, filteredUi( ui ) );
			},
			stop: function( event, ui ) {
				var left = ui.offset.left - that.document.scrollLeft(),
					top = ui.offset.top - that.document.scrollTop();

				options.position = {
					my: "left top",
					at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
						"top" + ( top >= 0 ? "+" : "" ) + top,
					of: that.window
				};
				that._removeClass( $( this ), "ui-dialog-dragging" );
				that._unblockFrames();
				that._trigger( "dragStop", event, filteredUi( ui ) );
			}
		} );
	},

	_makeResizable: function() {
		var that = this,
			options = this.options,
			handles = options.resizable,

			// .ui-resizable has position: relative defined in the stylesheet
			// but dialogs have to use absolute or fixed positioning
			position = this.uiDialog.css( "position" ),
			resizeHandles = typeof handles === "string" ?
				handles :
				"n,e,s,w,se,sw,ne,nw";

		function filteredUi( ui ) {
			return {
				originalPosition: ui.originalPosition,
				originalSize: ui.originalSize,
				position: ui.position,
				size: ui.size
			};
		}

		this.uiDialog.resizable( {
			cancel: ".ui-dialog-content",
			containment: "document",
			alsoResize: this.element,
			maxWidth: options.maxWidth,
			maxHeight: options.maxHeight,
			minWidth: options.minWidth,
			minHeight: this._minHeight(),
			handles: resizeHandles,
			start: function( event, ui ) {
				that._addClass( $( this ), "ui-dialog-resizing" );
				that._blockFrames();
				that._trigger( "resizeStart", event, filteredUi( ui ) );
			},
			resize: function( event, ui ) {
				that._trigger( "resize", event, filteredUi( ui ) );
			},
			stop: function( event, ui ) {
				var offset = that.uiDialog.offset(),
					left = offset.left - that.document.scrollLeft(),
					top = offset.top - that.document.scrollTop();

				options.height = that.uiDialog.height();
				options.width = that.uiDialog.width();
				options.position = {
					my: "left top",
					at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
						"top" + ( top >= 0 ? "+" : "" ) + top,
					of: that.window
				};
				that._removeClass( $( this ), "ui-dialog-resizing" );
				that._unblockFrames();
				that._trigger( "resizeStop", event, filteredUi( ui ) );
			}
		} )
			.css( "position", position );
	},

	_trackFocus: function() {
		this._on( this.widget(), {
			focusin: function( event ) {
				this._makeFocusTarget();
				this._focusedElement = $( event.target );
			}
		} );
	},

	_makeFocusTarget: function() {
		this._untrackInstance();
		this._trackingInstances().unshift( this );
	},

	_untrackInstance: function() {
		var instances = this._trackingInstances(),
			exists = $.inArray( this, instances );
		if ( exists !== -1 ) {
			instances.splice( exists, 1 );
		}
	},

	_trackingInstances: function() {
		var instances = this.document.data( "ui-dialog-instances" );
		if ( !instances ) {
			instances = [];
			this.document.data( "ui-dialog-instances", instances );
		}
		return instances;
	},

	_minHeight: function() {
		var options = this.options;

		return options.height === "auto" ?
			options.minHeight :
			Math.min( options.minHeight, options.height );
	},

	_position: function() {

		// Need to show the dialog to get the actual offset in the position plugin
		var isVisible = this.uiDialog.is( ":visible" );
		if ( !isVisible ) {
			this.uiDialog.show();
		}
		this.uiDialog.position( this.options.position );
		if ( !isVisible ) {
			this.uiDialog.hide();
		}
	},

	_setOptions: function( options ) {
		var that = this,
			resize = false,
			resizableOptions = {};

		$.each( options, function( key, value ) {
			that._setOption( key, value );

			if ( key in that.sizeRelatedOptions ) {
				resize = true;
			}
			if ( key in that.resizableRelatedOptions ) {
				resizableOptions[ key ] = value;
			}
		} );

		if ( resize ) {
			this._size();
			this._position();
		}
		if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
			this.uiDialog.resizable( "option", resizableOptions );
		}
	},

	_setOption: function( key, value ) {
		var isDraggable, isResizable,
			uiDialog = this.uiDialog;

		if ( key === "disabled" ) {
			return;
		}

		this._super( key, value );

		if ( key === "appendTo" ) {
			this.uiDialog.appendTo( this._appendTo() );
		}

		if ( key === "buttons" ) {
			this._createButtons();
		}

		if ( key === "closeText" ) {
			this.uiDialogTitlebarClose.button( {

				// Ensure that we always pass a string
				label: $( "<a>" ).text( "" + this.options.closeText ).html()
			} );
		}

		if ( key === "draggable" ) {
			isDraggable = uiDialog.is( ":data(ui-draggable)" );
			if ( isDraggable && !value ) {
				uiDialog.draggable( "destroy" );
			}

			if ( !isDraggable && value ) {
				this._makeDraggable();
			}
		}

		if ( key === "position" ) {
			this._position();
		}

		if ( key === "resizable" ) {

			// currently resizable, becoming non-resizable
			isResizable = uiDialog.is( ":data(ui-resizable)" );
			if ( isResizable && !value ) {
				uiDialog.resizable( "destroy" );
			}

			// Currently resizable, changing handles
			if ( isResizable && typeof value === "string" ) {
				uiDialog.resizable( "option", "handles", value );
			}

			// Currently non-resizable, becoming resizable
			if ( !isResizable && value !== false ) {
				this._makeResizable();
			}
		}

		if ( key === "title" ) {
			this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
		}
	},

	_size: function() {

		// If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
		// divs will both have width and height set, so we need to reset them
		var nonContentHeight, minContentHeight, maxContentHeight,
			options = this.options;

		// Reset content sizing
		this.element.show().css( {
			width: "auto",
			minHeight: 0,
			maxHeight: "none",
			height: 0
		} );

		if ( options.minWidth > options.width ) {
			options.width = options.minWidth;
		}

		// Reset wrapper sizing
		// determine the height of all the non-content elements
		nonContentHeight = this.uiDialog.css( {
			height: "auto",
			width: options.width
		} )
			.outerHeight();
		minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
		maxContentHeight = typeof options.maxHeight === "number" ?
			Math.max( 0, options.maxHeight - nonContentHeight ) :
			"none";

		if ( options.height === "auto" ) {
			this.element.css( {
				minHeight: minContentHeight,
				maxHeight: maxContentHeight,
				height: "auto"
			} );
		} else {
			this.element.height( Math.max( 0, options.height - nonContentHeight ) );
		}

		if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
			this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
		}
	},

	_blockFrames: function() {
		this.iframeBlocks = this.document.find( "iframe" ).map( function() {
			var iframe = $( this );

			return $( "<div>" )
				.css( {
					position: "absolute",
					width: iframe.outerWidth(),
					height: iframe.outerHeight()
				} )
				.appendTo( iframe.parent() )
				.offset( iframe.offset() )[ 0 ];
		} );
	},

	_unblockFrames: function() {
		if ( this.iframeBlocks ) {
			this.iframeBlocks.remove();
			delete this.iframeBlocks;
		}
	},

	_allowInteraction: function( event ) {
		if ( $( event.target ).closest( ".ui-dialog" ).length ) {
			return true;
		}

		// TODO: Remove hack when datepicker implements
		// the .ui-front logic (#8989)
		return !!$( event.target ).closest( ".ui-datepicker" ).length;
	},

	_createOverlay: function() {
		if ( !this.options.modal ) {
			return;
		}

		// We use a delay in case the overlay is created from an
		// event that we're going to be cancelling (#2804)
		var isOpening = true;
		this._delay( function() {
			isOpening = false;
		} );

		if ( !this.document.data( "ui-dialog-overlays" ) ) {

			// Prevent use of anchors and inputs
			// Using _on() for an event handler shared across many instances is
			// safe because the dialogs stack and must be closed in reverse order
			this._on( this.document, {
				focusin: function( event ) {
					if ( isOpening ) {
						return;
					}

					if ( !this._allowInteraction( event ) ) {
						event.preventDefault();
						this._trackingInstances()[ 0 ]._focusTabbable();
					}
				}
			} );
		}

		this.overlay = $( "<div>" )
			.appendTo( this._appendTo() );

		this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
		this._on( this.overlay, {
			mousedown: "_keepFocus"
		} );
		this.document.data( "ui-dialog-overlays",
			( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
	},

	_destroyOverlay: function() {
		if ( !this.options.modal ) {
			return;
		}

		if ( this.overlay ) {
			var overlays = this.document.data( "ui-dialog-overlays" ) - 1;

			if ( !overlays ) {
				this._off( this.document, "focusin" );
				this.document.removeData( "ui-dialog-overlays" );
			} else {
				this.document.data( "ui-dialog-overlays", overlays );
			}

			this.overlay.remove();
			this.overlay = null;
		}
	}
} );

// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for dialogClass option
	$.widget( "ui.dialog", $.ui.dialog, {
		options: {
			dialogClass: ""
		},
		_createWrapper: function() {
			this._super();
			this.uiDialog.addClass( this.options.dialogClass );
		},
		_setOption: function( key, value ) {
			if ( key === "dialogClass" ) {
				this.uiDialog
					.removeClass( this.options.dialogClass )
					.addClass( value );
			}
			this._superApply( arguments );
		}
	} );
}

var widgetsDialog = $.ui.dialog;


/*!
 * jQuery UI Droppable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Droppable
//>>group: Interactions
//>>description: Enables drop targets for draggable elements.
//>>docs: http://api.jqueryui.com/droppable/
//>>demos: http://jqueryui.com/droppable/



$.widget( "ui.droppable", {
	version: "1.12.1",
	widgetEventPrefix: "drop",
	options: {
		accept: "*",
		addClasses: true,
		greedy: false,
		scope: "default",
		tolerance: "intersect",

		// Callbacks
		activate: null,
		deactivate: null,
		drop: null,
		out: null,
		over: null
	},
	_create: function() {

		var proportions,
			o = this.options,
			accept = o.accept;

		this.isover = false;
		this.isout = true;

		this.accept = $.isFunction( accept ) ? accept : function( d ) {
			return d.is( accept );
		};

		this.proportions = function( /* valueToWrite */ ) {
			if ( arguments.length ) {

				// Store the droppable's proportions
				proportions = arguments[ 0 ];
			} else {

				// Retrieve or derive the droppable's proportions
				return proportions ?
					proportions :
					proportions = {
						width: this.element[ 0 ].offsetWidth,
						height: this.element[ 0 ].offsetHeight
					};
			}
		};

		this._addToManager( o.scope );

		o.addClasses && this._addClass( "ui-droppable" );

	},

	_addToManager: function( scope ) {

		// Add the reference and positions to the manager
		$.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
		$.ui.ddmanager.droppables[ scope ].push( this );
	},

	_splice: function( drop ) {
		var i = 0;
		for ( ; i < drop.length; i++ ) {
			if ( drop[ i ] === this ) {
				drop.splice( i, 1 );
			}
		}
	},

	_destroy: function() {
		var drop = $.ui.ddmanager.droppables[ this.options.scope ];

		this._splice( drop );
	},

	_setOption: function( key, value ) {

		if ( key === "accept" ) {
			this.accept = $.isFunction( value ) ? value : function( d ) {
				return d.is( value );
			};
		} else if ( key === "scope" ) {
			var drop = $.ui.ddmanager.droppables[ this.options.scope ];

			this._splice( drop );
			this._addToManager( value );
		}

		this._super( key, value );
	},

	_activate: function( event ) {
		var draggable = $.ui.ddmanager.current;

		this._addActiveClass();
		if ( draggable ) {
			this._trigger( "activate", event, this.ui( draggable ) );
		}
	},

	_deactivate: function( event ) {
		var draggable = $.ui.ddmanager.current;

		this._removeActiveClass();
		if ( draggable ) {
			this._trigger( "deactivate", event, this.ui( draggable ) );
		}
	},

	_over: function( event ) {

		var draggable = $.ui.ddmanager.current;

		// Bail if draggable and droppable are same element
		if ( !draggable || ( draggable.currentItem ||
				draggable.element )[ 0 ] === this.element[ 0 ] ) {
			return;
		}

		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
				draggable.element ) ) ) {
			this._addHoverClass();
			this._trigger( "over", event, this.ui( draggable ) );
		}

	},

	_out: function( event ) {

		var draggable = $.ui.ddmanager.current;

		// Bail if draggable and droppable are same element
		if ( !draggable || ( draggable.currentItem ||
				draggable.element )[ 0 ] === this.element[ 0 ] ) {
			return;
		}

		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
				draggable.element ) ) ) {
			this._removeHoverClass();
			this._trigger( "out", event, this.ui( draggable ) );
		}

	},

	_drop: function( event, custom ) {

		var draggable = custom || $.ui.ddmanager.current,
			childrenIntersection = false;

		// Bail if draggable and droppable are same element
		if ( !draggable || ( draggable.currentItem ||
				draggable.element )[ 0 ] === this.element[ 0 ] ) {
			return false;
		}

		this.element
			.find( ":data(ui-droppable)" )
			.not( ".ui-draggable-dragging" )
			.each( function() {
				var inst = $( this ).droppable( "instance" );
				if (
					inst.options.greedy &&
					!inst.options.disabled &&
					inst.options.scope === draggable.options.scope &&
					inst.accept.call(
						inst.element[ 0 ], ( draggable.currentItem || draggable.element )
					) &&
					intersect(
						draggable,
						$.extend( inst, { offset: inst.element.offset() } ),
						inst.options.tolerance, event
					)
				) {
					childrenIntersection = true;
					return false; }
			} );
		if ( childrenIntersection ) {
			return false;
		}

		if ( this.accept.call( this.element[ 0 ],
				( draggable.currentItem || draggable.element ) ) ) {
			this._removeActiveClass();
			this._removeHoverClass();

			this._trigger( "drop", event, this.ui( draggable ) );
			return this.element;
		}

		return false;

	},

	ui: function( c ) {
		return {
			draggable: ( c.currentItem || c.element ),
			helper: c.helper,
			position: c.position,
			offset: c.positionAbs
		};
	},

	// Extension points just to make backcompat sane and avoid duplicating logic
	// TODO: Remove in 1.13 along with call to it below
	_addHoverClass: function() {
		this._addClass( "ui-droppable-hover" );
	},

	_removeHoverClass: function() {
		this._removeClass( "ui-droppable-hover" );
	},

	_addActiveClass: function() {
		this._addClass( "ui-droppable-active" );
	},

	_removeActiveClass: function() {
		this._removeClass( "ui-droppable-active" );
	}
} );

var intersect = $.ui.intersect = ( function() {
	function isOverAxis( x, reference, size ) {
		return ( x >= reference ) && ( x < ( reference + size ) );
	}

	return function( draggable, droppable, toleranceMode, event ) {

		if ( !droppable.offset ) {
			return false;
		}

		var x1 = ( draggable.positionAbs ||
				draggable.position.absolute ).left + draggable.margins.left,
			y1 = ( draggable.positionAbs ||
				draggable.position.absolute ).top + draggable.margins.top,
			x2 = x1 + draggable.helperProportions.width,
			y2 = y1 + draggable.helperProportions.height,
			l = droppable.offset.left,
			t = droppable.offset.top,
			r = l + droppable.proportions().width,
			b = t + droppable.proportions().height;

		switch ( toleranceMode ) {
		case "fit":
			return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
		case "intersect":
			return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
				x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
				t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
				y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
		case "pointer":
			return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
				isOverAxis( event.pageX, l, droppable.proportions().width );
		case "touch":
			return (
				( y1 >= t && y1 <= b ) || // Top edge touching
				( y2 >= t && y2 <= b ) || // Bottom edge touching
				( y1 < t && y2 > b ) // Surrounded vertically
			) && (
				( x1 >= l && x1 <= r ) || // Left edge touching
				( x2 >= l && x2 <= r ) || // Right edge touching
				( x1 < l && x2 > r ) // Surrounded horizontally
			);
		default:
			return false;
		}
	};
} )();

/*
	This manager tracks offsets of draggables and droppables
*/
$.ui.ddmanager = {
	current: null,
	droppables: { "default": [] },
	prepareOffsets: function( t, event ) {

		var i, j,
			m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
			type = event ? event.type : null, // workaround for #2317
			list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();

		droppablesLoop: for ( i = 0; i < m.length; i++ ) {

			// No disabled and non-accepted
			if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
					( t.currentItem || t.element ) ) ) ) {
				continue;
			}

			// Filter out elements in the current dragged item
			for ( j = 0; j < list.length; j++ ) {
				if ( list[ j ] === m[ i ].element[ 0 ] ) {
					m[ i ].proportions().height = 0;
					continue droppablesLoop;
				}
			}

			m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
			if ( !m[ i ].visible ) {
				continue;
			}

			// Activate the droppable if used directly from draggables
			if ( type === "mousedown" ) {
				m[ i ]._activate.call( m[ i ], event );
			}

			m[ i ].offset = m[ i ].element.offset();
			m[ i ].proportions( {
				width: m[ i ].element[ 0 ].offsetWidth,
				height: m[ i ].element[ 0 ].offsetHeight
			} );

		}

	},
	drop: function( draggable, event ) {

		var dropped = false;

		// Create a copy of the droppables in case the list changes during the drop (#9116)
		$.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {

			if ( !this.options ) {
				return;
			}
			if ( !this.options.disabled && this.visible &&
					intersect( draggable, this, this.options.tolerance, event ) ) {
				dropped = this._drop.call( this, event ) || dropped;
			}

			if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
					( draggable.currentItem || draggable.element ) ) ) {
				this.isout = true;
				this.isover = false;
				this._deactivate.call( this, event );
			}

		} );
		return dropped;

	},
	dragStart: function( draggable, event ) {

		// Listen for scrolling so that if the dragging causes scrolling the position of the
		// droppables can be recalculated (see #5003)
		draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
			if ( !draggable.options.refreshPositions ) {
				$.ui.ddmanager.prepareOffsets( draggable, event );
			}
		} );
	},
	drag: function( draggable, event ) {

		// If you have a highly dynamic page, you might try this option. It renders positions
		// every time you move the mouse.
		if ( draggable.options.refreshPositions ) {
			$.ui.ddmanager.prepareOffsets( draggable, event );
		}

		// Run through all droppables and check their positions based on specific tolerance options
		$.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {

			if ( this.options.disabled || this.greedyChild || !this.visible ) {
				return;
			}

			var parentInstance, scope, parent,
				intersects = intersect( draggable, this, this.options.tolerance, event ),
				c = !intersects && this.isover ?
					"isout" :
					( intersects && !this.isover ? "isover" : null );
			if ( !c ) {
				return;
			}

			if ( this.options.greedy ) {

				// find droppable parents with same scope
				scope = this.options.scope;
				parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
					return $( this ).droppable( "instance" ).options.scope === scope;
				} );

				if ( parent.length ) {
					parentInstance = $( parent[ 0 ] ).droppable( "instance" );
					parentInstance.greedyChild = ( c === "isover" );
				}
			}

			// We just moved into a greedy child
			if ( parentInstance && c === "isover" ) {
				parentInstance.isover = false;
				parentInstance.isout = true;
				parentInstance._out.call( parentInstance, event );
			}

			this[ c ] = true;
			this[ c === "isout" ? "isover" : "isout" ] = false;
			this[ c === "isover" ? "_over" : "_out" ].call( this, event );

			// We just moved out of a greedy child
			if ( parentInstance && c === "isout" ) {
				parentInstance.isout = false;
				parentInstance.isover = true;
				parentInstance._over.call( parentInstance, event );
			}
		} );

	},
	dragStop: function( draggable, event ) {
		draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );

		// Call prepareOffsets one final time since IE does not fire return scroll events when
		// overflow was caused by drag (see #5003)
		if ( !draggable.options.refreshPositions ) {
			$.ui.ddmanager.prepareOffsets( draggable, event );
		}
	}
};

// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for activeClass and hoverClass options
	$.widget( "ui.droppable", $.ui.droppable, {
		options: {
			hoverClass: false,
			activeClass: false
		},
		_addActiveClass: function() {
			this._super();
			if ( this.options.activeClass ) {
				this.element.addClass( this.options.activeClass );
			}
		},
		_removeActiveClass: function() {
			this._super();
			if ( this.options.activeClass ) {
				this.element.removeClass( this.options.activeClass );
			}
		},
		_addHoverClass: function() {
			this._super();
			if ( this.options.hoverClass ) {
				this.element.addClass( this.options.hoverClass );
			}
		},
		_removeHoverClass: function() {
			this._super();
			if ( this.options.hoverClass ) {
				this.element.removeClass( this.options.hoverClass );
			}
		}
	} );
}

var widgetsDroppable = $.ui.droppable;


/*!
 * jQuery UI Progressbar 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Progressbar
//>>group: Widgets
// jscs:disable maximumLineLength
//>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/progressbar/
//>>demos: http://jqueryui.com/progressbar/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/progressbar.css
//>>css.theme: ../../themes/base/theme.css



var widgetsProgressbar = $.widget( "ui.progressbar", {
	version: "1.12.1",
	options: {
		classes: {
			"ui-progressbar": "ui-corner-all",
			"ui-progressbar-value": "ui-corner-left",
			"ui-progressbar-complete": "ui-corner-right"
		},
		max: 100,
		value: 0,

		change: null,
		complete: null
	},

	min: 0,

	_create: function() {

		// Constrain initial value
		this.oldValue = this.options.value = this._constrainedValue();

		this.element.attr( {

			// Only set static values; aria-valuenow and aria-valuemax are
			// set inside _refreshValue()
			role: "progressbar",
			"aria-valuemin": this.min
		} );
		this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );

		this.valueDiv = $( "<div>" ).appendTo( this.element );
		this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
		this._refreshValue();
	},

	_destroy: function() {
		this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );

		this.valueDiv.remove();
	},

	value: function( newValue ) {
		if ( newValue === undefined ) {
			return this.options.value;
		}

		this.options.value = this._constrainedValue( newValue );
		this._refreshValue();
	},

	_constrainedValue: function( newValue ) {
		if ( newValue === undefined ) {
			newValue = this.options.value;
		}

		this.indeterminate = newValue === false;

		// Sanitize value
		if ( typeof newValue !== "number" ) {
			newValue = 0;
		}

		return this.indeterminate ? false :
			Math.min( this.options.max, Math.max( this.min, newValue ) );
	},

	_setOptions: function( options ) {

		// Ensure "value" option is set after other values (like max)
		var value = options.value;
		delete options.value;

		this._super( options );

		this.options.value = this._constrainedValue( value );
		this._refreshValue();
	},

	_setOption: function( key, value ) {
		if ( key === "max" ) {

			// Don't allow a max less than min
			value = Math.max( this.min, value );
		}
		this._super( key, value );
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this.element.attr( "aria-disabled", value );
		this._toggleClass( null, "ui-state-disabled", !!value );
	},

	_percentage: function() {
		return this.indeterminate ?
			100 :
			100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
	},

	_refreshValue: function() {
		var value = this.options.value,
			percentage = this._percentage();

		this.valueDiv
			.toggle( this.indeterminate || value > this.min )
			.width( percentage.toFixed( 0 ) + "%" );

		this
			._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
				value === this.options.max )
			._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );

		if ( this.indeterminate ) {
			this.element.removeAttr( "aria-valuenow" );
			if ( !this.overlayDiv ) {
				this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
				this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
			}
		} else {
			this.element.attr( {
				"aria-valuemax": this.options.max,
				"aria-valuenow": value
			} );
			if ( this.overlayDiv ) {
				this.overlayDiv.remove();
				this.overlayDiv = null;
			}
		}

		if ( this.oldValue !== value ) {
			this.oldValue = value;
			this._trigger( "change" );
		}
		if ( value === this.options.max ) {
			this._trigger( "complete" );
		}
	}
} );


/*!
 * jQuery UI Selectable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Selectable
//>>group: Interactions
//>>description: Allows groups of elements to be selected with the mouse.
//>>docs: http://api.jqueryui.com/selectable/
//>>demos: http://jqueryui.com/selectable/
//>>css.structure: ../../themes/base/selectable.css



var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
	version: "1.12.1",
	options: {
		appendTo: "body",
		autoRefresh: true,
		distance: 0,
		filter: "*",
		tolerance: "touch",

		// Callbacks
		selected: null,
		selecting: null,
		start: null,
		stop: null,
		unselected: null,
		unselecting: null
	},
	_create: function() {
		var that = this;

		this._addClass( "ui-selectable" );

		this.dragged = false;

		// Cache selectee children based on filter
		this.refresh = function() {
			that.elementPos = $( that.element[ 0 ] ).offset();
			that.selectees = $( that.options.filter, that.element[ 0 ] );
			that._addClass( that.selectees, "ui-selectee" );
			that.selectees.each( function() {
				var $this = $( this ),
					selecteeOffset = $this.offset(),
					pos = {
						left: selecteeOffset.left - that.elementPos.left,
						top: selecteeOffset.top - that.elementPos.top
					};
				$.data( this, "selectable-item", {
					element: this,
					$element: $this,
					left: pos.left,
					top: pos.top,
					right: pos.left + $this.outerWidth(),
					bottom: pos.top + $this.outerHeight(),
					startselected: false,
					selected: $this.hasClass( "ui-selected" ),
					selecting: $this.hasClass( "ui-selecting" ),
					unselecting: $this.hasClass( "ui-unselecting" )
				} );
			} );
		};
		this.refresh();

		this._mouseInit();

		this.helper = $( "<div>" );
		this._addClass( this.helper, "ui-selectable-helper" );
	},

	_destroy: function() {
		this.selectees.removeData( "selectable-item" );
		this._mouseDestroy();
	},

	_mouseStart: function( event ) {
		var that = this,
			options = this.options;

		this.opos = [ event.pageX, event.pageY ];
		this.elementPos = $( this.element[ 0 ] ).offset();

		if ( this.options.disabled ) {
			return;
		}

		this.selectees = $( options.filter, this.element[ 0 ] );

		this._trigger( "start", event );

		$( options.appendTo ).append( this.helper );

		// position helper (lasso)
		this.helper.css( {
			"left": event.pageX,
			"top": event.pageY,
			"width": 0,
			"height": 0
		} );

		if ( options.autoRefresh ) {
			this.refresh();
		}

		this.selectees.filter( ".ui-selected" ).each( function() {
			var selectee = $.data( this, "selectable-item" );
			selectee.startselected = true;
			if ( !event.metaKey && !event.ctrlKey ) {
				that._removeClass( selectee.$element, "ui-selected" );
				selectee.selected = false;
				that._addClass( selectee.$element, "ui-unselecting" );
				selectee.unselecting = true;

				// selectable UNSELECTING callback
				that._trigger( "unselecting", event, {
					unselecting: selectee.element
				} );
			}
		} );

		$( event.target ).parents().addBack().each( function() {
			var doSelect,
				selectee = $.data( this, "selectable-item" );
			if ( selectee ) {
				doSelect = ( !event.metaKey && !event.ctrlKey ) ||
					!selectee.$element.hasClass( "ui-selected" );
				that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
					._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
				selectee.unselecting = !doSelect;
				selectee.selecting = doSelect;
				selectee.selected = doSelect;

				// selectable (UN)SELECTING callback
				if ( doSelect ) {
					that._trigger( "selecting", event, {
						selecting: selectee.element
					} );
				} else {
					that._trigger( "unselecting", event, {
						unselecting: selectee.element
					} );
				}
				return false;
			}
		} );

	},

	_mouseDrag: function( event ) {

		this.dragged = true;

		if ( this.options.disabled ) {
			return;
		}

		var tmp,
			that = this,
			options = this.options,
			x1 = this.opos[ 0 ],
			y1 = this.opos[ 1 ],
			x2 = event.pageX,
			y2 = event.pageY;

		if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; }
		if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; }
		this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );

		this.selectees.each( function() {
			var selectee = $.data( this, "selectable-item" ),
				hit = false,
				offset = {};

			//prevent helper from being selected if appendTo: selectable
			if ( !selectee || selectee.element === that.element[ 0 ] ) {
				return;
			}

			offset.left   = selectee.left   + that.elementPos.left;
			offset.right  = selectee.right  + that.elementPos.left;
			offset.top    = selectee.top    + that.elementPos.top;
			offset.bottom = selectee.bottom + that.elementPos.top;

			if ( options.tolerance === "touch" ) {
				hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
                    offset.bottom < y1 ) );
			} else if ( options.tolerance === "fit" ) {
				hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
                    offset.bottom < y2 );
			}

			if ( hit ) {

				// SELECT
				if ( selectee.selected ) {
					that._removeClass( selectee.$element, "ui-selected" );
					selectee.selected = false;
				}
				if ( selectee.unselecting ) {
					that._removeClass( selectee.$element, "ui-unselecting" );
					selectee.unselecting = false;
				}
				if ( !selectee.selecting ) {
					that._addClass( selectee.$element, "ui-selecting" );
					selectee.selecting = true;

					// selectable SELECTING callback
					that._trigger( "selecting", event, {
						selecting: selectee.element
					} );
				}
			} else {

				// UNSELECT
				if ( selectee.selecting ) {
					if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
						that._removeClass( selectee.$element, "ui-selecting" );
						selectee.selecting = false;
						that._addClass( selectee.$element, "ui-selected" );
						selectee.selected = true;
					} else {
						that._removeClass( selectee.$element, "ui-selecting" );
						selectee.selecting = false;
						if ( selectee.startselected ) {
							that._addClass( selectee.$element, "ui-unselecting" );
							selectee.unselecting = true;
						}

						// selectable UNSELECTING callback
						that._trigger( "unselecting", event, {
							unselecting: selectee.element
						} );
					}
				}
				if ( selectee.selected ) {
					if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
						that._removeClass( selectee.$element, "ui-selected" );
						selectee.selected = false;

						that._addClass( selectee.$element, "ui-unselecting" );
						selectee.unselecting = true;

						// selectable UNSELECTING callback
						that._trigger( "unselecting", event, {
							unselecting: selectee.element
						} );
					}
				}
			}
		} );

		return false;
	},

	_mouseStop: function( event ) {
		var that = this;

		this.dragged = false;

		$( ".ui-unselecting", this.element[ 0 ] ).each( function() {
			var selectee = $.data( this, "selectable-item" );
			that._removeClass( selectee.$element, "ui-unselecting" );
			selectee.unselecting = false;
			selectee.startselected = false;
			that._trigger( "unselected", event, {
				unselected: selectee.element
			} );
		} );
		$( ".ui-selecting", this.element[ 0 ] ).each( function() {
			var selectee = $.data( this, "selectable-item" );
			that._removeClass( selectee.$element, "ui-selecting" )
				._addClass( selectee.$element, "ui-selected" );
			selectee.selecting = false;
			selectee.selected = true;
			selectee.startselected = true;
			that._trigger( "selected", event, {
				selected: selectee.element
			} );
		} );
		this._trigger( "stop", event );

		this.helper.remove();

		return false;
	}

} );


/*!
 * jQuery UI Selectmenu 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Selectmenu
//>>group: Widgets
// jscs:disable maximumLineLength
//>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/selectmenu/
//>>demos: http://jqueryui.com/selectmenu/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
//>>css.theme: ../../themes/base/theme.css



var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
	version: "1.12.1",
	defaultElement: "<select>",
	options: {
		appendTo: null,
		classes: {
			"ui-selectmenu-button-open": "ui-corner-top",
			"ui-selectmenu-button-closed": "ui-corner-all"
		},
		disabled: null,
		icons: {
			button: "ui-icon-triangle-1-s"
		},
		position: {
			my: "left top",
			at: "left bottom",
			collision: "none"
		},
		width: false,

		// Callbacks
		change: null,
		close: null,
		focus: null,
		open: null,
		select: null
	},

	_create: function() {
		var selectmenuId = this.element.uniqueId().attr( "id" );
		this.ids = {
			element: selectmenuId,
			button: selectmenuId + "-button",
			menu: selectmenuId + "-menu"
		};

		this._drawButton();
		this._drawMenu();
		this._bindFormResetHandler();

		this._rendered = false;
		this.menuItems = $();
	},

	_drawButton: function() {
		var icon,
			that = this,
			item = this._parseOption(
				this.element.find( "option:selected" ),
				this.element[ 0 ].selectedIndex
			);

		// Associate existing label with the new button
		this.labels = this.element.labels().attr( "for", this.ids.button );
		this._on( this.labels, {
			click: function( event ) {
				this.button.focus();
				event.preventDefault();
			}
		} );

		// Hide original select element
		this.element.hide();

		// Create button
		this.button = $( "<span>", {
			tabindex: this.options.disabled ? -1 : 0,
			id: this.ids.button,
			role: "combobox",
			"aria-expanded": "false",
			"aria-autocomplete": "list",
			"aria-owns": this.ids.menu,
			"aria-haspopup": "true",
			title: this.element.attr( "title" )
		} )
			.insertAfter( this.element );

		this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
			"ui-button ui-widget" );

		icon = $( "<span>" ).appendTo( this.button );
		this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
		this.buttonItem = this._renderButtonItem( item )
			.appendTo( this.button );

		if ( this.options.width !== false ) {
			this._resizeButton();
		}

		this._on( this.button, this._buttonEvents );
		this.button.one( "focusin", function() {

			// Delay rendering the menu items until the button receives focus.
			// The menu may have already been rendered via a programmatic open.
			if ( !that._rendered ) {
				that._refreshMenu();
			}
		} );
	},

	_drawMenu: function() {
		var that = this;

		// Create menu
		this.menu = $( "<ul>", {
			"aria-hidden": "true",
			"aria-labelledby": this.ids.button,
			id: this.ids.menu
		} );

		// Wrap menu
		this.menuWrap = $( "<div>" ).append( this.menu );
		this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
		this.menuWrap.appendTo( this._appendTo() );

		// Initialize menu widget
		this.menuInstance = this.menu
			.menu( {
				classes: {
					"ui-menu": "ui-corner-bottom"
				},
				role: "listbox",
				select: function( event, ui ) {
					event.preventDefault();

					// Support: IE8
					// If the item was selected via a click, the text selection
					// will be destroyed in IE
					that._setSelection();

					that._select( ui.item.data( "ui-selectmenu-item" ), event );
				},
				focus: function( event, ui ) {
					var item = ui.item.data( "ui-selectmenu-item" );

					// Prevent inital focus from firing and check if its a newly focused item
					if ( that.focusIndex != null && item.index !== that.focusIndex ) {
						that._trigger( "focus", event, { item: item } );
						if ( !that.isOpen ) {
							that._select( item, event );
						}
					}
					that.focusIndex = item.index;

					that.button.attr( "aria-activedescendant",
						that.menuItems.eq( item.index ).attr( "id" ) );
				}
			} )
			.menu( "instance" );

		// Don't close the menu on mouseleave
		this.menuInstance._off( this.menu, "mouseleave" );

		// Cancel the menu's collapseAll on document click
		this.menuInstance._closeOnDocumentClick = function() {
			return false;
		};

		// Selects often contain empty items, but never contain dividers
		this.menuInstance._isDivider = function() {
			return false;
		};
	},

	refresh: function() {
		this._refreshMenu();
		this.buttonItem.replaceWith(
			this.buttonItem = this._renderButtonItem(

				// Fall back to an empty object in case there are no options
				this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
			)
		);
		if ( this.options.width === null ) {
			this._resizeButton();
		}
	},

	_refreshMenu: function() {
		var item,
			options = this.element.find( "option" );

		this.menu.empty();

		this._parseOptions( options );
		this._renderMenu( this.menu, this.items );

		this.menuInstance.refresh();
		this.menuItems = this.menu.find( "li" )
			.not( ".ui-selectmenu-optgroup" )
				.find( ".ui-menu-item-wrapper" );

		this._rendered = true;

		if ( !options.length ) {
			return;
		}

		item = this._getSelectedItem();

		// Update the menu to have the correct item focused
		this.menuInstance.focus( null, item );
		this._setAria( item.data( "ui-selectmenu-item" ) );

		// Set disabled state
		this._setOption( "disabled", this.element.prop( "disabled" ) );
	},

	open: function( event ) {
		if ( this.options.disabled ) {
			return;
		}

		// If this is the first time the menu is being opened, render the items
		if ( !this._rendered ) {
			this._refreshMenu();
		} else {

			// Menu clears focus on close, reset focus to selected item
			this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
			this.menuInstance.focus( null, this._getSelectedItem() );
		}

		// If there are no options, don't open the menu
		if ( !this.menuItems.length ) {
			return;
		}

		this.isOpen = true;
		this._toggleAttr();
		this._resizeMenu();
		this._position();

		this._on( this.document, this._documentClick );

		this._trigger( "open", event );
	},

	_position: function() {
		this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
	},

	close: function( event ) {
		if ( !this.isOpen ) {
			return;
		}

		this.isOpen = false;
		this._toggleAttr();

		this.range = null;
		this._off( this.document );

		this._trigger( "close", event );
	},

	widget: function() {
		return this.button;
	},

	menuWidget: function() {
		return this.menu;
	},

	_renderButtonItem: function( item ) {
		var buttonItem = $( "<span>" );

		this._setText( buttonItem, item.label );
		this._addClass( buttonItem, "ui-selectmenu-text" );

		return buttonItem;
	},

	_renderMenu: function( ul, items ) {
		var that = this,
			currentOptgroup = "";

		$.each( items, function( index, item ) {
			var li;

			if ( item.optgroup !== currentOptgroup ) {
				li = $( "<li>", {
					text: item.optgroup
				} );
				that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
					( item.element.parent( "optgroup" ).prop( "disabled" ) ?
						" ui-state-disabled" :
						"" ) );

				li.appendTo( ul );

				currentOptgroup = item.optgroup;
			}

			that._renderItemData( ul, item );
		} );
	},

	_renderItemData: function( ul, item ) {
		return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
	},

	_renderItem: function( ul, item ) {
		var li = $( "<li>" ),
			wrapper = $( "<div>", {
				title: item.element.attr( "title" )
			} );

		if ( item.disabled ) {
			this._addClass( li, null, "ui-state-disabled" );
		}
		this._setText( wrapper, item.label );

		return li.append( wrapper ).appendTo( ul );
	},

	_setText: function( element, value ) {
		if ( value ) {
			element.text( value );
		} else {
			element.html( "&#160;" );
		}
	},

	_move: function( direction, event ) {
		var item, next,
			filter = ".ui-menu-item";

		if ( this.isOpen ) {
			item = this.menuItems.eq( this.focusIndex ).parent( "li" );
		} else {
			item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
			filter += ":not(.ui-state-disabled)";
		}

		if ( direction === "first" || direction === "last" ) {
			next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
		} else {
			next = item[ direction + "All" ]( filter ).eq( 0 );
		}

		if ( next.length ) {
			this.menuInstance.focus( event, next );
		}
	},

	_getSelectedItem: function() {
		return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
	},

	_toggle: function( event ) {
		this[ this.isOpen ? "close" : "open" ]( event );
	},

	_setSelection: function() {
		var selection;

		if ( !this.range ) {
			return;
		}

		if ( window.getSelection ) {
			selection = window.getSelection();
			selection.removeAllRanges();
			selection.addRange( this.range );

		// Support: IE8
		} else {
			this.range.select();
		}

		// Support: IE
		// Setting the text selection kills the button focus in IE, but
		// restoring the focus doesn't kill the selection.
		this.button.focus();
	},

	_documentClick: {
		mousedown: function( event ) {
			if ( !this.isOpen ) {
				return;
			}

			if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
					$.ui.escapeSelector( this.ids.button ) ).length ) {
				this.close( event );
			}
		}
	},

	_buttonEvents: {

		// Prevent text selection from being reset when interacting with the selectmenu (#10144)
		mousedown: function() {
			var selection;

			if ( window.getSelection ) {
				selection = window.getSelection();
				if ( selection.rangeCount ) {
					this.range = selection.getRangeAt( 0 );
				}

			// Support: IE8
			} else {
				this.range = document.selection.createRange();
			}
		},

		click: function( event ) {
			this._setSelection();
			this._toggle( event );
		},

		keydown: function( event ) {
			var preventDefault = true;
			switch ( event.keyCode ) {
			case $.ui.keyCode.TAB:
			case $.ui.keyCode.ESCAPE:
				this.close( event );
				preventDefault = false;
				break;
			case $.ui.keyCode.ENTER:
				if ( this.isOpen ) {
					this._selectFocusedItem( event );
				}
				break;
			case $.ui.keyCode.UP:
				if ( event.altKey ) {
					this._toggle( event );
				} else {
					this._move( "prev", event );
				}
				break;
			case $.ui.keyCode.DOWN:
				if ( event.altKey ) {
					this._toggle( event );
				} else {
					this._move( "next", event );
				}
				break;
			case $.ui.keyCode.SPACE:
				if ( this.isOpen ) {
					this._selectFocusedItem( event );
				} else {
					this._toggle( event );
				}
				break;
			case $.ui.keyCode.LEFT:
				this._move( "prev", event );
				break;
			case $.ui.keyCode.RIGHT:
				this._move( "next", event );
				break;
			case $.ui.keyCode.HOME:
			case $.ui.keyCode.PAGE_UP:
				this._move( "first", event );
				break;
			case $.ui.keyCode.END:
			case $.ui.keyCode.PAGE_DOWN:
				this._move( "last", event );
				break;
			default:
				this.menu.trigger( event );
				preventDefault = false;
			}

			if ( preventDefault ) {
				event.preventDefault();
			}
		}
	},

	_selectFocusedItem: function( event ) {
		var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
		if ( !item.hasClass( "ui-state-disabled" ) ) {
			this._select( item.data( "ui-selectmenu-item" ), event );
		}
	},

	_select: function( item, event ) {
		var oldIndex = this.element[ 0 ].selectedIndex;

		// Change native select element
		this.element[ 0 ].selectedIndex = item.index;
		this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
		this._setAria( item );
		this._trigger( "select", event, { item: item } );

		if ( item.index !== oldIndex ) {
			this._trigger( "change", event, { item: item } );
		}

		this.close( event );
	},

	_setAria: function( item ) {
		var id = this.menuItems.eq( item.index ).attr( "id" );

		this.button.attr( {
			"aria-labelledby": id,
			"aria-activedescendant": id
		} );
		this.menu.attr( "aria-activedescendant", id );
	},

	_setOption: function( key, value ) {
		if ( key === "icons" ) {
			var icon = this.button.find( "span.ui-icon" );
			this._removeClass( icon, null, this.options.icons.button )
				._addClass( icon, null, value.button );
		}

		this._super( key, value );

		if ( key === "appendTo" ) {
			this.menuWrap.appendTo( this._appendTo() );
		}

		if ( key === "width" ) {
			this._resizeButton();
		}
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this.menuInstance.option( "disabled", value );
		this.button.attr( "aria-disabled", value );
		this._toggleClass( this.button, null, "ui-state-disabled", value );

		this.element.prop( "disabled", value );
		if ( value ) {
			this.button.attr( "tabindex", -1 );
			this.close();
		} else {
			this.button.attr( "tabindex", 0 );
		}
	},

	_appendTo: function() {
		var element = this.options.appendTo;

		if ( element ) {
			element = element.jquery || element.nodeType ?
				$( element ) :
				this.document.find( element ).eq( 0 );
		}

		if ( !element || !element[ 0 ] ) {
			element = this.element.closest( ".ui-front, dialog" );
		}

		if ( !element.length ) {
			element = this.document[ 0 ].body;
		}

		return element;
	},

	_toggleAttr: function() {
		this.button.attr( "aria-expanded", this.isOpen );

		// We can't use two _toggleClass() calls here, because we need to make sure
		// we always remove classes first and add them second, otherwise if both classes have the
		// same theme class, it will be removed after we add it.
		this._removeClass( this.button, "ui-selectmenu-button-" +
			( this.isOpen ? "closed" : "open" ) )
			._addClass( this.button, "ui-selectmenu-button-" +
				( this.isOpen ? "open" : "closed" ) )
			._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );

		this.menu.attr( "aria-hidden", !this.isOpen );
	},

	_resizeButton: function() {
		var width = this.options.width;

		// For `width: false`, just remove inline style and stop
		if ( width === false ) {
			this.button.css( "width", "" );
			return;
		}

		// For `width: null`, match the width of the original element
		if ( width === null ) {
			width = this.element.show().outerWidth();
			this.element.hide();
		}

		this.button.outerWidth( width );
	},

	_resizeMenu: function() {
		this.menu.outerWidth( Math.max(
			this.button.outerWidth(),

			// Support: IE10
			// IE10 wraps long text (possibly a rounding bug)
			// so we add 1px to avoid the wrapping
			this.menu.width( "" ).outerWidth() + 1
		) );
	},

	_getCreateOptions: function() {
		var options = this._super();

		options.disabled = this.element.prop( "disabled" );

		return options;
	},

	_parseOptions: function( options ) {
		var that = this,
			data = [];
		options.each( function( index, item ) {
			data.push( that._parseOption( $( item ), index ) );
		} );
		this.items = data;
	},

	_parseOption: function( option, index ) {
		var optgroup = option.parent( "optgroup" );

		return {
			element: option,
			index: index,
			value: option.val(),
			label: option.text(),
			optgroup: optgroup.attr( "label" ) || "",
			disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
		};
	},

	_destroy: function() {
		this._unbindFormResetHandler();
		this.menuWrap.remove();
		this.button.remove();
		this.element.show();
		this.element.removeUniqueId();
		this.labels.attr( "for", this.ids.element );
	}
} ] );


/*!
 * jQuery UI Slider 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Slider
//>>group: Widgets
//>>description: Displays a flexible slider with ranges and accessibility via keyboard.
//>>docs: http://api.jqueryui.com/slider/
//>>demos: http://jqueryui.com/slider/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/slider.css
//>>css.theme: ../../themes/base/theme.css



var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
	version: "1.12.1",
	widgetEventPrefix: "slide",

	options: {
		animate: false,
		classes: {
			"ui-slider": "ui-corner-all",
			"ui-slider-handle": "ui-corner-all",

			// Note: ui-widget-header isn't the most fittingly semantic framework class for this
			// element, but worked best visually with a variety of themes
			"ui-slider-range": "ui-corner-all ui-widget-header"
		},
		distance: 0,
		max: 100,
		min: 0,
		orientation: "horizontal",
		range: false,
		step: 1,
		value: 0,
		values: null,

		// Callbacks
		change: null,
		slide: null,
		start: null,
		stop: null
	},

	// Number of pages in a slider
	// (how many times can you page up/down to go through the whole range)
	numPages: 5,

	_create: function() {
		this._keySliding = false;
		this._mouseSliding = false;
		this._animateOff = true;
		this._handleIndex = null;
		this._detectOrientation();
		this._mouseInit();
		this._calculateNewMax();

		this._addClass( "ui-slider ui-slider-" + this.orientation,
			"ui-widget ui-widget-content" );

		this._refresh();

		this._animateOff = false;
	},

	_refresh: function() {
		this._createRange();
		this._createHandles();
		this._setupEvents();
		this._refreshValue();
	},

	_createHandles: function() {
		var i, handleCount,
			options = this.options,
			existingHandles = this.element.find( ".ui-slider-handle" ),
			handle = "<span tabindex='0'></span>",
			handles = [];

		handleCount = ( options.values && options.values.length ) || 1;

		if ( existingHandles.length > handleCount ) {
			existingHandles.slice( handleCount ).remove();
			existingHandles = existingHandles.slice( 0, handleCount );
		}

		for ( i = existingHandles.length; i < handleCount; i++ ) {
			handles.push( handle );
		}

		this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );

		this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );

		this.handle = this.handles.eq( 0 );

		this.handles.each( function( i ) {
			$( this )
				.data( "ui-slider-handle-index", i )
				.attr( "tabIndex", 0 );
		} );
	},

	_createRange: function() {
		var options = this.options;

		if ( options.range ) {
			if ( options.range === true ) {
				if ( !options.values ) {
					options.values = [ this._valueMin(), this._valueMin() ];
				} else if ( options.values.length && options.values.length !== 2 ) {
					options.values = [ options.values[ 0 ], options.values[ 0 ] ];
				} else if ( $.isArray( options.values ) ) {
					options.values = options.values.slice( 0 );
				}
			}

			if ( !this.range || !this.range.length ) {
				this.range = $( "<div>" )
					.appendTo( this.element );

				this._addClass( this.range, "ui-slider-range" );
			} else {
				this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );

				// Handle range switching from true to min/max
				this.range.css( {
					"left": "",
					"bottom": ""
				} );
			}
			if ( options.range === "min" || options.range === "max" ) {
				this._addClass( this.range, "ui-slider-range-" + options.range );
			}
		} else {
			if ( this.range ) {
				this.range.remove();
			}
			this.range = null;
		}
	},

	_setupEvents: function() {
		this._off( this.handles );
		this._on( this.handles, this._handleEvents );
		this._hoverable( this.handles );
		this._focusable( this.handles );
	},

	_destroy: function() {
		this.handles.remove();
		if ( this.range ) {
			this.range.remove();
		}

		this._mouseDestroy();
	},

	_mouseCapture: function( event ) {
		var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
			that = this,
			o = this.options;

		if ( o.disabled ) {
			return false;
		}

		this.elementSize = {
			width: this.element.outerWidth(),
			height: this.element.outerHeight()
		};
		this.elementOffset = this.element.offset();

		position = { x: event.pageX, y: event.pageY };
		normValue = this._normValueFromMouse( position );
		distance = this._valueMax() - this._valueMin() + 1;
		this.handles.each( function( i ) {
			var thisDistance = Math.abs( normValue - that.values( i ) );
			if ( ( distance > thisDistance ) ||
				( distance === thisDistance &&
					( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
				distance = thisDistance;
				closestHandle = $( this );
				index = i;
			}
		} );

		allowed = this._start( event, index );
		if ( allowed === false ) {
			return false;
		}
		this._mouseSliding = true;

		this._handleIndex = index;

		this._addClass( closestHandle, null, "ui-state-active" );
		closestHandle.trigger( "focus" );

		offset = closestHandle.offset();
		mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
		this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
			left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
			top: event.pageY - offset.top -
				( closestHandle.height() / 2 ) -
				( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
				( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
				( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
		};

		if ( !this.handles.hasClass( "ui-state-hover" ) ) {
			this._slide( event, index, normValue );
		}
		this._animateOff = true;
		return true;
	},

	_mouseStart: function() {
		return true;
	},

	_mouseDrag: function( event ) {
		var position = { x: event.pageX, y: event.pageY },
			normValue = this._normValueFromMouse( position );

		this._slide( event, this._handleIndex, normValue );

		return false;
	},

	_mouseStop: function( event ) {
		this._removeClass( this.handles, null, "ui-state-active" );
		this._mouseSliding = false;

		this._stop( event, this._handleIndex );
		this._change( event, this._handleIndex );

		this._handleIndex = null;
		this._clickOffset = null;
		this._animateOff = false;

		return false;
	},

	_detectOrientation: function() {
		this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
	},

	_normValueFromMouse: function( position ) {
		var pixelTotal,
			pixelMouse,
			percentMouse,
			valueTotal,
			valueMouse;

		if ( this.orientation === "horizontal" ) {
			pixelTotal = this.elementSize.width;
			pixelMouse = position.x - this.elementOffset.left -
				( this._clickOffset ? this._clickOffset.left : 0 );
		} else {
			pixelTotal = this.elementSize.height;
			pixelMouse = position.y - this.elementOffset.top -
				( this._clickOffset ? this._clickOffset.top : 0 );
		}

		percentMouse = ( pixelMouse / pixelTotal );
		if ( percentMouse > 1 ) {
			percentMouse = 1;
		}
		if ( percentMouse < 0 ) {
			percentMouse = 0;
		}
		if ( this.orientation === "vertical" ) {
			percentMouse = 1 - percentMouse;
		}

		valueTotal = this._valueMax() - this._valueMin();
		valueMouse = this._valueMin() + percentMouse * valueTotal;

		return this._trimAlignValue( valueMouse );
	},

	_uiHash: function( index, value, values ) {
		var uiHash = {
			handle: this.handles[ index ],
			handleIndex: index,
			value: value !== undefined ? value : this.value()
		};

		if ( this._hasMultipleValues() ) {
			uiHash.value = value !== undefined ? value : this.values( index );
			uiHash.values = values || this.values();
		}

		return uiHash;
	},

	_hasMultipleValues: function() {
		return this.options.values && this.options.values.length;
	},

	_start: function( event, index ) {
		return this._trigger( "start", event, this._uiHash( index ) );
	},

	_slide: function( event, index, newVal ) {
		var allowed, otherVal,
			currentValue = this.value(),
			newValues = this.values();

		if ( this._hasMultipleValues() ) {
			otherVal = this.values( index ? 0 : 1 );
			currentValue = this.values( index );

			if ( this.options.values.length === 2 && this.options.range === true ) {
				newVal =  index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
			}

			newValues[ index ] = newVal;
		}

		if ( newVal === currentValue ) {
			return;
		}

		allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );

		// A slide can be canceled by returning false from the slide callback
		if ( allowed === false ) {
			return;
		}

		if ( this._hasMultipleValues() ) {
			this.values( index, newVal );
		} else {
			this.value( newVal );
		}
	},

	_stop: function( event, index ) {
		this._trigger( "stop", event, this._uiHash( index ) );
	},

	_change: function( event, index ) {
		if ( !this._keySliding && !this._mouseSliding ) {

			//store the last changed value index for reference when handles overlap
			this._lastChangedValue = index;
			this._trigger( "change", event, this._uiHash( index ) );
		}
	},

	value: function( newValue ) {
		if ( arguments.length ) {
			this.options.value = this._trimAlignValue( newValue );
			this._refreshValue();
			this._change( null, 0 );
			return;
		}

		return this._value();
	},

	values: function( index, newValue ) {
		var vals,
			newValues,
			i;

		if ( arguments.length > 1 ) {
			this.options.values[ index ] = this._trimAlignValue( newValue );
			this._refreshValue();
			this._change( null, index );
			return;
		}

		if ( arguments.length ) {
			if ( $.isArray( arguments[ 0 ] ) ) {
				vals = this.options.values;
				newValues = arguments[ 0 ];
				for ( i = 0; i < vals.length; i += 1 ) {
					vals[ i ] = this._trimAlignValue( newValues[ i ] );
					this._change( null, i );
				}
				this._refreshValue();
			} else {
				if ( this._hasMultipleValues() ) {
					return this._values( index );
				} else {
					return this.value();
				}
			}
		} else {
			return this._values();
		}
	},

	_setOption: function( key, value ) {
		var i,
			valsLength = 0;

		if ( key === "range" && this.options.range === true ) {
			if ( value === "min" ) {
				this.options.value = this._values( 0 );
				this.options.values = null;
			} else if ( value === "max" ) {
				this.options.value = this._values( this.options.values.length - 1 );
				this.options.values = null;
			}
		}

		if ( $.isArray( this.options.values ) ) {
			valsLength = this.options.values.length;
		}

		this._super( key, value );

		switch ( key ) {
			case "orientation":
				this._detectOrientation();
				this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
					._addClass( "ui-slider-" + this.orientation );
				this._refreshValue();
				if ( this.options.range ) {
					this._refreshRange( value );
				}

				// Reset positioning from previous orientation
				this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
				break;
			case "value":
				this._animateOff = true;
				this._refreshValue();
				this._change( null, 0 );
				this._animateOff = false;
				break;
			case "values":
				this._animateOff = true;
				this._refreshValue();

				// Start from the last handle to prevent unreachable handles (#9046)
				for ( i = valsLength - 1; i >= 0; i-- ) {
					this._change( null, i );
				}
				this._animateOff = false;
				break;
			case "step":
			case "min":
			case "max":
				this._animateOff = true;
				this._calculateNewMax();
				this._refreshValue();
				this._animateOff = false;
				break;
			case "range":
				this._animateOff = true;
				this._refresh();
				this._animateOff = false;
				break;
		}
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this._toggleClass( null, "ui-state-disabled", !!value );
	},

	//internal value getter
	// _value() returns value trimmed by min and max, aligned by step
	_value: function() {
		var val = this.options.value;
		val = this._trimAlignValue( val );

		return val;
	},

	//internal values getter
	// _values() returns array of values trimmed by min and max, aligned by step
	// _values( index ) returns single value trimmed by min and max, aligned by step
	_values: function( index ) {
		var val,
			vals,
			i;

		if ( arguments.length ) {
			val = this.options.values[ index ];
			val = this._trimAlignValue( val );

			return val;
		} else if ( this._hasMultipleValues() ) {

			// .slice() creates a copy of the array
			// this copy gets trimmed by min and max and then returned
			vals = this.options.values.slice();
			for ( i = 0; i < vals.length; i += 1 ) {
				vals[ i ] = this._trimAlignValue( vals[ i ] );
			}

			return vals;
		} else {
			return [];
		}
	},

	// Returns the step-aligned value that val is closest to, between (inclusive) min and max
	_trimAlignValue: function( val ) {
		if ( val <= this._valueMin() ) {
			return this._valueMin();
		}
		if ( val >= this._valueMax() ) {
			return this._valueMax();
		}
		var step = ( this.options.step > 0 ) ? this.options.step : 1,
			valModStep = ( val - this._valueMin() ) % step,
			alignValue = val - valModStep;

		if ( Math.abs( valModStep ) * 2 >= step ) {
			alignValue += ( valModStep > 0 ) ? step : ( -step );
		}

		// Since JavaScript has problems with large floats, round
		// the final value to 5 digits after the decimal point (see #4124)
		return parseFloat( alignValue.toFixed( 5 ) );
	},

	_calculateNewMax: function() {
		var max = this.options.max,
			min = this._valueMin(),
			step = this.options.step,
			aboveMin = Math.round( ( max - min ) / step ) * step;
		max = aboveMin + min;
		if ( max > this.options.max ) {

			//If max is not divisible by step, rounding off may increase its value
			max -= step;
		}
		this.max = parseFloat( max.toFixed( this._precision() ) );
	},

	_precision: function() {
		var precision = this._precisionOf( this.options.step );
		if ( this.options.min !== null ) {
			precision = Math.max( precision, this._precisionOf( this.options.min ) );
		}
		return precision;
	},

	_precisionOf: function( num ) {
		var str = num.toString(),
			decimal = str.indexOf( "." );
		return decimal === -1 ? 0 : str.length - decimal - 1;
	},

	_valueMin: function() {
		return this.options.min;
	},

	_valueMax: function() {
		return this.max;
	},

	_refreshRange: function( orientation ) {
		if ( orientation === "vertical" ) {
			this.range.css( { "width": "", "left": "" } );
		}
		if ( orientation === "horizontal" ) {
			this.range.css( { "height": "", "bottom": "" } );
		}
	},

	_refreshValue: function() {
		var lastValPercent, valPercent, value, valueMin, valueMax,
			oRange = this.options.range,
			o = this.options,
			that = this,
			animate = ( !this._animateOff ) ? o.animate : false,
			_set = {};

		if ( this._hasMultipleValues() ) {
			this.handles.each( function( i ) {
				valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
					that._valueMin() ) * 100;
				_set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
				$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
				if ( that.options.range === true ) {
					if ( that.orientation === "horizontal" ) {
						if ( i === 0 ) {
							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
								left: valPercent + "%"
							}, o.animate );
						}
						if ( i === 1 ) {
							that.range[ animate ? "animate" : "css" ]( {
								width: ( valPercent - lastValPercent ) + "%"
							}, {
								queue: false,
								duration: o.animate
							} );
						}
					} else {
						if ( i === 0 ) {
							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
								bottom: ( valPercent ) + "%"
							}, o.animate );
						}
						if ( i === 1 ) {
							that.range[ animate ? "animate" : "css" ]( {
								height: ( valPercent - lastValPercent ) + "%"
							}, {
								queue: false,
								duration: o.animate
							} );
						}
					}
				}
				lastValPercent = valPercent;
			} );
		} else {
			value = this.value();
			valueMin = this._valueMin();
			valueMax = this._valueMax();
			valPercent = ( valueMax !== valueMin ) ?
					( value - valueMin ) / ( valueMax - valueMin ) * 100 :
					0;
			_set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
			this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );

			if ( oRange === "min" && this.orientation === "horizontal" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
					width: valPercent + "%"
				}, o.animate );
			}
			if ( oRange === "max" && this.orientation === "horizontal" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
					width: ( 100 - valPercent ) + "%"
				}, o.animate );
			}
			if ( oRange === "min" && this.orientation === "vertical" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
					height: valPercent + "%"
				}, o.animate );
			}
			if ( oRange === "max" && this.orientation === "vertical" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
					height: ( 100 - valPercent ) + "%"
				}, o.animate );
			}
		}
	},

	_handleEvents: {
		keydown: function( event ) {
			var allowed, curVal, newVal, step,
				index = $( event.target ).data( "ui-slider-handle-index" );

			switch ( event.keyCode ) {
				case $.ui.keyCode.HOME:
				case $.ui.keyCode.END:
				case $.ui.keyCode.PAGE_UP:
				case $.ui.keyCode.PAGE_DOWN:
				case $.ui.keyCode.UP:
				case $.ui.keyCode.RIGHT:
				case $.ui.keyCode.DOWN:
				case $.ui.keyCode.LEFT:
					event.preventDefault();
					if ( !this._keySliding ) {
						this._keySliding = true;
						this._addClass( $( event.target ), null, "ui-state-active" );
						allowed = this._start( event, index );
						if ( allowed === false ) {
							return;
						}
					}
					break;
			}

			step = this.options.step;
			if ( this._hasMultipleValues() ) {
				curVal = newVal = this.values( index );
			} else {
				curVal = newVal = this.value();
			}

			switch ( event.keyCode ) {
				case $.ui.keyCode.HOME:
					newVal = this._valueMin();
					break;
				case $.ui.keyCode.END:
					newVal = this._valueMax();
					break;
				case $.ui.keyCode.PAGE_UP:
					newVal = this._trimAlignValue(
						curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
					);
					break;
				case $.ui.keyCode.PAGE_DOWN:
					newVal = this._trimAlignValue(
						curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
					break;
				case $.ui.keyCode.UP:
				case $.ui.keyCode.RIGHT:
					if ( curVal === this._valueMax() ) {
						return;
					}
					newVal = this._trimAlignValue( curVal + step );
					break;
				case $.ui.keyCode.DOWN:
				case $.ui.keyCode.LEFT:
					if ( curVal === this._valueMin() ) {
						return;
					}
					newVal = this._trimAlignValue( curVal - step );
					break;
			}

			this._slide( event, index, newVal );
		},
		keyup: function( event ) {
			var index = $( event.target ).data( "ui-slider-handle-index" );

			if ( this._keySliding ) {
				this._keySliding = false;
				this._stop( event, index );
				this._change( event, index );
				this._removeClass( $( event.target ), null, "ui-state-active" );
			}
		}
	}
} );


/*!
 * jQuery UI Sortable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Sortable
//>>group: Interactions
//>>description: Enables items in a list to be sorted using the mouse.
//>>docs: http://api.jqueryui.com/sortable/
//>>demos: http://jqueryui.com/sortable/
//>>css.structure: ../../themes/base/sortable.css



var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
	version: "1.12.1",
	widgetEventPrefix: "sort",
	ready: false,
	options: {
		appendTo: "parent",
		axis: false,
		connectWith: false,
		containment: false,
		cursor: "auto",
		cursorAt: false,
		dropOnEmpty: true,
		forcePlaceholderSize: false,
		forceHelperSize: false,
		grid: false,
		handle: false,
		helper: "original",
		items: "> *",
		opacity: false,
		placeholder: false,
		revert: false,
		scroll: true,
		scrollSensitivity: 20,
		scrollSpeed: 20,
		scope: "default",
		tolerance: "intersect",
		zIndex: 1000,

		// Callbacks
		activate: null,
		beforeStop: null,
		change: null,
		deactivate: null,
		out: null,
		over: null,
		receive: null,
		remove: null,
		sort: null,
		start: null,
		stop: null,
		update: null
	},

	_isOverAxis: function( x, reference, size ) {
		return ( x >= reference ) && ( x < ( reference + size ) );
	},

	_isFloating: function( item ) {
		return ( /left|right/ ).test( item.css( "float" ) ) ||
			( /inline|table-cell/ ).test( item.css( "display" ) );
	},

	_create: function() {
		this.containerCache = {};
		this._addClass( "ui-sortable" );

		//Get the items
		this.refresh();

		//Let's determine the parent's offset
		this.offset = this.element.offset();

		//Initialize mouse events for interaction
		this._mouseInit();

		this._setHandleClassName();

		//We're ready to go
		this.ready = true;

	},

	_setOption: function( key, value ) {
		this._super( key, value );

		if ( key === "handle" ) {
			this._setHandleClassName();
		}
	},

	_setHandleClassName: function() {
		var that = this;
		this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
		$.each( this.items, function() {
			that._addClass(
				this.instance.options.handle ?
					this.item.find( this.instance.options.handle ) :
					this.item,
				"ui-sortable-handle"
			);
		} );
	},

	_destroy: function() {
		this._mouseDestroy();

		for ( var i = this.items.length - 1; i >= 0; i-- ) {
			this.items[ i ].item.removeData( this.widgetName + "-item" );
		}

		return this;
	},

	_mouseCapture: function( event, overrideHandle ) {
		var currentItem = null,
			validHandle = false,
			that = this;

		if ( this.reverting ) {
			return false;
		}

		if ( this.options.disabled || this.options.type === "static" ) {
			return false;
		}

		//We have to refresh the items data once first
		this._refreshItems( event );

		//Find out if the clicked node (or one of its parents) is a actual item in this.items
		$( event.target ).parents().each( function() {
			if ( $.data( this, that.widgetName + "-item" ) === that ) {
				currentItem = $( this );
				return false;
			}
		} );
		if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
			currentItem = $( event.target );
		}

		if ( !currentItem ) {
			return false;
		}
		if ( this.options.handle && !overrideHandle ) {
			$( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
				if ( this === event.target ) {
					validHandle = true;
				}
			} );
			if ( !validHandle ) {
				return false;
			}
		}

		this.currentItem = currentItem;
		this._removeCurrentsFromItems();
		return true;

	},

	_mouseStart: function( event, overrideHandle, noActivation ) {

		var i, body,
			o = this.options;

		this.currentContainer = this;

		//We only need to call refreshPositions, because the refreshItems call has been moved to
		// mouseCapture
		this.refreshPositions();

		//Create and append the visible helper
		this.helper = this._createHelper( event );

		//Cache the helper size
		this._cacheHelperProportions();

		/*
		 * - Position generation -
		 * This block generates everything position related - it's the core of draggables.
		 */

		//Cache the margins of the original element
		this._cacheMargins();

		//Get the next scrolling parent
		this.scrollParent = this.helper.scrollParent();

		//The element's absolute position on the page minus margins
		this.offset = this.currentItem.offset();
		this.offset = {
			top: this.offset.top - this.margins.top,
			left: this.offset.left - this.margins.left
		};

		$.extend( this.offset, {
			click: { //Where the click happened, relative to the element
				left: event.pageX - this.offset.left,
				top: event.pageY - this.offset.top
			},
			parent: this._getParentOffset(),

			// This is a relative to absolute position minus the actual position calculation -
			// only used for relative positioned helper
			relative: this._getRelativeOffset()
		} );

		// Only after we got the offset, we can change the helper's position to absolute
		// TODO: Still need to figure out a way to make relative sorting possible
		this.helper.css( "position", "absolute" );
		this.cssPosition = this.helper.css( "position" );

		//Generate the original position
		this.originalPosition = this._generatePosition( event );
		this.originalPageX = event.pageX;
		this.originalPageY = event.pageY;

		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
		( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );

		//Cache the former DOM position
		this.domPosition = {
			prev: this.currentItem.prev()[ 0 ],
			parent: this.currentItem.parent()[ 0 ]
		};

		// If the helper is not the original, hide the original so it's not playing any role during
		// the drag, won't cause anything bad this way
		if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
			this.currentItem.hide();
		}

		//Create the placeholder
		this._createPlaceholder();

		//Set a containment if given in the options
		if ( o.containment ) {
			this._setContainment();
		}

		if ( o.cursor && o.cursor !== "auto" ) { // cursor option
			body = this.document.find( "body" );

			// Support: IE
			this.storedCursor = body.css( "cursor" );
			body.css( "cursor", o.cursor );

			this.storedStylesheet =
				$( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
		}

		if ( o.opacity ) { // opacity option
			if ( this.helper.css( "opacity" ) ) {
				this._storedOpacity = this.helper.css( "opacity" );
			}
			this.helper.css( "opacity", o.opacity );
		}

		if ( o.zIndex ) { // zIndex option
			if ( this.helper.css( "zIndex" ) ) {
				this._storedZIndex = this.helper.css( "zIndex" );
			}
			this.helper.css( "zIndex", o.zIndex );
		}

		//Prepare scrolling
		if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				this.scrollParent[ 0 ].tagName !== "HTML" ) {
			this.overflowOffset = this.scrollParent.offset();
		}

		//Call callbacks
		this._trigger( "start", event, this._uiHash() );

		//Recache the helper size
		if ( !this._preserveHelperProportions ) {
			this._cacheHelperProportions();
		}

		//Post "activate" events to possible containers
		if ( !noActivation ) {
			for ( i = this.containers.length - 1; i >= 0; i-- ) {
				this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
			}
		}

		//Prepare possible droppables
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.current = this;
		}

		if ( $.ui.ddmanager && !o.dropBehaviour ) {
			$.ui.ddmanager.prepareOffsets( this, event );
		}

		this.dragging = true;

		this._addClass( this.helper, "ui-sortable-helper" );

		// Execute the drag once - this causes the helper not to be visiblebefore getting its
		// correct position
		this._mouseDrag( event );
		return true;

	},

	_mouseDrag: function( event ) {
		var i, item, itemElement, intersection,
			o = this.options,
			scrolled = false;

		//Compute the helpers position
		this.position = this._generatePosition( event );
		this.positionAbs = this._convertPositionTo( "absolute" );

		if ( !this.lastPositionAbs ) {
			this.lastPositionAbs = this.positionAbs;
		}

		//Do scrolling
		if ( this.options.scroll ) {
			if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
					this.scrollParent[ 0 ].tagName !== "HTML" ) {

				if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
						event.pageY < o.scrollSensitivity ) {
					this.scrollParent[ 0 ].scrollTop =
						scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
				} else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
					this.scrollParent[ 0 ].scrollTop =
						scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
				}

				if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
						event.pageX < o.scrollSensitivity ) {
					this.scrollParent[ 0 ].scrollLeft = scrolled =
						this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
				} else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
					this.scrollParent[ 0 ].scrollLeft = scrolled =
						this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
				}

			} else {

				if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
					scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
				} else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
						o.scrollSensitivity ) {
					scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
				}

				if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
					scrolled = this.document.scrollLeft(
						this.document.scrollLeft() - o.scrollSpeed
					);
				} else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
						o.scrollSensitivity ) {
					scrolled = this.document.scrollLeft(
						this.document.scrollLeft() + o.scrollSpeed
					);
				}

			}

			if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
				$.ui.ddmanager.prepareOffsets( this, event );
			}
		}

		//Regenerate the absolute position used for position checks
		this.positionAbs = this._convertPositionTo( "absolute" );

		//Set the helper position
		if ( !this.options.axis || this.options.axis !== "y" ) {
			this.helper[ 0 ].style.left = this.position.left + "px";
		}
		if ( !this.options.axis || this.options.axis !== "x" ) {
			this.helper[ 0 ].style.top = this.position.top + "px";
		}

		//Rearrange
		for ( i = this.items.length - 1; i >= 0; i-- ) {

			//Cache variables and intersection, continue if no intersection
			item = this.items[ i ];
			itemElement = item.item[ 0 ];
			intersection = this._intersectsWithPointer( item );
			if ( !intersection ) {
				continue;
			}

			// Only put the placeholder inside the current Container, skip all
			// items from other containers. This works because when moving
			// an item from one container to another the
			// currentContainer is switched before the placeholder is moved.
			//
			// Without this, moving items in "sub-sortables" can cause
			// the placeholder to jitter between the outer and inner container.
			if ( item.instance !== this.currentContainer ) {
				continue;
			}

			// Cannot intersect with itself
			// no useless actions that have been done before
			// no action if the item moved is the parent of the item checked
			if ( itemElement !== this.currentItem[ 0 ] &&
				this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
				!$.contains( this.placeholder[ 0 ], itemElement ) &&
				( this.options.type === "semi-dynamic" ?
					!$.contains( this.element[ 0 ], itemElement ) :
					true
				)
			) {

				this.direction = intersection === 1 ? "down" : "up";

				if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
					this._rearrange( event, item );
				} else {
					break;
				}

				this._trigger( "change", event, this._uiHash() );
				break;
			}
		}

		//Post events to containers
		this._contactContainers( event );

		//Interconnect with droppables
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.drag( this, event );
		}

		//Call callbacks
		this._trigger( "sort", event, this._uiHash() );

		this.lastPositionAbs = this.positionAbs;
		return false;

	},

	_mouseStop: function( event, noPropagation ) {

		if ( !event ) {
			return;
		}

		//If we are using droppables, inform the manager about the drop
		if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
			$.ui.ddmanager.drop( this, event );
		}

		if ( this.options.revert ) {
			var that = this,
				cur = this.placeholder.offset(),
				axis = this.options.axis,
				animation = {};

			if ( !axis || axis === "x" ) {
				animation.left = cur.left - this.offset.parent.left - this.margins.left +
					( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
						0 :
						this.offsetParent[ 0 ].scrollLeft
					);
			}
			if ( !axis || axis === "y" ) {
				animation.top = cur.top - this.offset.parent.top - this.margins.top +
					( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
						0 :
						this.offsetParent[ 0 ].scrollTop
					);
			}
			this.reverting = true;
			$( this.helper ).animate(
				animation,
				parseInt( this.options.revert, 10 ) || 500,
				function() {
					that._clear( event );
				}
			);
		} else {
			this._clear( event, noPropagation );
		}

		return false;

	},

	cancel: function() {

		if ( this.dragging ) {

			this._mouseUp( new $.Event( "mouseup", { target: null } ) );

			if ( this.options.helper === "original" ) {
				this.currentItem.css( this._storedCSS );
				this._removeClass( this.currentItem, "ui-sortable-helper" );
			} else {
				this.currentItem.show();
			}

			//Post deactivating events to containers
			for ( var i = this.containers.length - 1; i >= 0; i-- ) {
				this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
				if ( this.containers[ i ].containerCache.over ) {
					this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
					this.containers[ i ].containerCache.over = 0;
				}
			}

		}

		if ( this.placeholder ) {

			//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
			// it unbinds ALL events from the original node!
			if ( this.placeholder[ 0 ].parentNode ) {
				this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
			}
			if ( this.options.helper !== "original" && this.helper &&
					this.helper[ 0 ].parentNode ) {
				this.helper.remove();
			}

			$.extend( this, {
				helper: null,
				dragging: false,
				reverting: false,
				_noFinalSort: null
			} );

			if ( this.domPosition.prev ) {
				$( this.domPosition.prev ).after( this.currentItem );
			} else {
				$( this.domPosition.parent ).prepend( this.currentItem );
			}
		}

		return this;

	},

	serialize: function( o ) {

		var items = this._getItemsAsjQuery( o && o.connected ),
			str = [];
		o = o || {};

		$( items ).each( function() {
			var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
				.match( o.expression || ( /(.+)[\-=_](.+)/ ) );
			if ( res ) {
				str.push(
					( o.key || res[ 1 ] + "[]" ) +
					"=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
			}
		} );

		if ( !str.length && o.key ) {
			str.push( o.key + "=" );
		}

		return str.join( "&" );

	},

	toArray: function( o ) {

		var items = this._getItemsAsjQuery( o && o.connected ),
			ret = [];

		o = o || {};

		items.each( function() {
			ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
		} );
		return ret;

	},

	/* Be careful with the following core functions */
	_intersectsWith: function( item ) {

		var x1 = this.positionAbs.left,
			x2 = x1 + this.helperProportions.width,
			y1 = this.positionAbs.top,
			y2 = y1 + this.helperProportions.height,
			l = item.left,
			r = l + item.width,
			t = item.top,
			b = t + item.height,
			dyClick = this.offset.click.top,
			dxClick = this.offset.click.left,
			isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
				( y1 + dyClick ) < b ),
			isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
				( x1 + dxClick ) < r ),
			isOverElement = isOverElementHeight && isOverElementWidth;

		if ( this.options.tolerance === "pointer" ||
			this.options.forcePointerForContainers ||
			( this.options.tolerance !== "pointer" &&
				this.helperProportions[ this.floating ? "width" : "height" ] >
				item[ this.floating ? "width" : "height" ] )
		) {
			return isOverElement;
		} else {

			return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
				x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
				t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
				y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half

		}
	},

	_intersectsWithPointer: function( item ) {
		var verticalDirection, horizontalDirection,
			isOverElementHeight = ( this.options.axis === "x" ) ||
				this._isOverAxis(
					this.positionAbs.top + this.offset.click.top, item.top, item.height ),
			isOverElementWidth = ( this.options.axis === "y" ) ||
				this._isOverAxis(
					this.positionAbs.left + this.offset.click.left, item.left, item.width ),
			isOverElement = isOverElementHeight && isOverElementWidth;

		if ( !isOverElement ) {
			return false;
		}

		verticalDirection = this._getDragVerticalDirection();
		horizontalDirection = this._getDragHorizontalDirection();

		return this.floating ?
			( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
			: ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );

	},

	_intersectsWithSides: function( item ) {

		var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
				this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
			isOverRightHalf = this._isOverAxis( this.positionAbs.left +
				this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
			verticalDirection = this._getDragVerticalDirection(),
			horizontalDirection = this._getDragHorizontalDirection();

		if ( this.floating && horizontalDirection ) {
			return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
				( horizontalDirection === "left" && !isOverRightHalf ) );
		} else {
			return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
				( verticalDirection === "up" && !isOverBottomHalf ) );
		}

	},

	_getDragVerticalDirection: function() {
		var delta = this.positionAbs.top - this.lastPositionAbs.top;
		return delta !== 0 && ( delta > 0 ? "down" : "up" );
	},

	_getDragHorizontalDirection: function() {
		var delta = this.positionAbs.left - this.lastPositionAbs.left;
		return delta !== 0 && ( delta > 0 ? "right" : "left" );
	},

	refresh: function( event ) {
		this._refreshItems( event );
		this._setHandleClassName();
		this.refreshPositions();
		return this;
	},

	_connectWith: function() {
		var options = this.options;
		return options.connectWith.constructor === String ?
			[ options.connectWith ] :
			options.connectWith;
	},

	_getItemsAsjQuery: function( connected ) {

		var i, j, cur, inst,
			items = [],
			queries = [],
			connectWith = this._connectWith();

		if ( connectWith && connected ) {
			for ( i = connectWith.length - 1; i >= 0; i-- ) {
				cur = $( connectWith[ i ], this.document[ 0 ] );
				for ( j = cur.length - 1; j >= 0; j-- ) {
					inst = $.data( cur[ j ], this.widgetFullName );
					if ( inst && inst !== this && !inst.options.disabled ) {
						queries.push( [ $.isFunction( inst.options.items ) ?
							inst.options.items.call( inst.element ) :
							$( inst.options.items, inst.element )
								.not( ".ui-sortable-helper" )
								.not( ".ui-sortable-placeholder" ), inst ] );
					}
				}
			}
		}

		queries.push( [ $.isFunction( this.options.items ) ?
			this.options.items
				.call( this.element, null, { options: this.options, item: this.currentItem } ) :
			$( this.options.items, this.element )
				.not( ".ui-sortable-helper" )
				.not( ".ui-sortable-placeholder" ), this ] );

		function addItems() {
			items.push( this );
		}
		for ( i = queries.length - 1; i >= 0; i-- ) {
			queries[ i ][ 0 ].each( addItems );
		}

		return $( items );

	},

	_removeCurrentsFromItems: function() {

		var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );

		this.items = $.grep( this.items, function( item ) {
			for ( var j = 0; j < list.length; j++ ) {
				if ( list[ j ] === item.item[ 0 ] ) {
					return false;
				}
			}
			return true;
		} );

	},

	_refreshItems: function( event ) {

		this.items = [];
		this.containers = [ this ];

		var i, j, cur, inst, targetData, _queries, item, queriesLength,
			items = this.items,
			queries = [ [ $.isFunction( this.options.items ) ?
				this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
				$( this.options.items, this.element ), this ] ],
			connectWith = this._connectWith();

		//Shouldn't be run the first time through due to massive slow-down
		if ( connectWith && this.ready ) {
			for ( i = connectWith.length - 1; i >= 0; i-- ) {
				cur = $( connectWith[ i ], this.document[ 0 ] );
				for ( j = cur.length - 1; j >= 0; j-- ) {
					inst = $.data( cur[ j ], this.widgetFullName );
					if ( inst && inst !== this && !inst.options.disabled ) {
						queries.push( [ $.isFunction( inst.options.items ) ?
							inst.options.items
								.call( inst.element[ 0 ], event, { item: this.currentItem } ) :
							$( inst.options.items, inst.element ), inst ] );
						this.containers.push( inst );
					}
				}
			}
		}

		for ( i = queries.length - 1; i >= 0; i-- ) {
			targetData = queries[ i ][ 1 ];
			_queries = queries[ i ][ 0 ];

			for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
				item = $( _queries[ j ] );

				// Data for target checking (mouse manager)
				item.data( this.widgetName + "-item", targetData );

				items.push( {
					item: item,
					instance: targetData,
					width: 0, height: 0,
					left: 0, top: 0
				} );
			}
		}

	},

	refreshPositions: function( fast ) {

		// Determine whether items are being displayed horizontally
		this.floating = this.items.length ?
			this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
			false;

		//This has to be redone because due to the item being moved out/into the offsetParent,
		// the offsetParent's position will change
		if ( this.offsetParent && this.helper ) {
			this.offset.parent = this._getParentOffset();
		}

		var i, item, t, p;

		for ( i = this.items.length - 1; i >= 0; i-- ) {
			item = this.items[ i ];

			//We ignore calculating positions of all connected containers when we're not over them
			if ( item.instance !== this.currentContainer && this.currentContainer &&
					item.item[ 0 ] !== this.currentItem[ 0 ] ) {
				continue;
			}

			t = this.options.toleranceElement ?
				$( this.options.toleranceElement, item.item ) :
				item.item;

			if ( !fast ) {
				item.width = t.outerWidth();
				item.height = t.outerHeight();
			}

			p = t.offset();
			item.left = p.left;
			item.top = p.top;
		}

		if ( this.options.custom && this.options.custom.refreshContainers ) {
			this.options.custom.refreshContainers.call( this );
		} else {
			for ( i = this.containers.length - 1; i >= 0; i-- ) {
				p = this.containers[ i ].element.offset();
				this.containers[ i ].containerCache.left = p.left;
				this.containers[ i ].containerCache.top = p.top;
				this.containers[ i ].containerCache.width =
					this.containers[ i ].element.outerWidth();
				this.containers[ i ].containerCache.height =
					this.containers[ i ].element.outerHeight();
			}
		}

		return this;
	},

	_createPlaceholder: function( that ) {
		that = that || this;
		var className,
			o = that.options;

		if ( !o.placeholder || o.placeholder.constructor === String ) {
			className = o.placeholder;
			o.placeholder = {
				element: function() {

					var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
						element = $( "<" + nodeName + ">", that.document[ 0 ] );

						that._addClass( element, "ui-sortable-placeholder",
								className || that.currentItem[ 0 ].className )
							._removeClass( element, "ui-sortable-helper" );

					if ( nodeName === "tbody" ) {
						that._createTrPlaceholder(
							that.currentItem.find( "tr" ).eq( 0 ),
							$( "<tr>", that.document[ 0 ] ).appendTo( element )
						);
					} else if ( nodeName === "tr" ) {
						that._createTrPlaceholder( that.currentItem, element );
					} else if ( nodeName === "img" ) {
						element.attr( "src", that.currentItem.attr( "src" ) );
					}

					if ( !className ) {
						element.css( "visibility", "hidden" );
					}

					return element;
				},
				update: function( container, p ) {

					// 1. If a className is set as 'placeholder option, we don't force sizes -
					// the class is responsible for that
					// 2. The option 'forcePlaceholderSize can be enabled to force it even if a
					// class name is specified
					if ( className && !o.forcePlaceholderSize ) {
						return;
					}

					//If the element doesn't have a actual height by itself (without styles coming
					// from a stylesheet), it receives the inline height from the dragged item
					if ( !p.height() ) {
						p.height(
							that.currentItem.innerHeight() -
							parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
							parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
					}
					if ( !p.width() ) {
						p.width(
							that.currentItem.innerWidth() -
							parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
							parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
					}
				}
			};
		}

		//Create the placeholder
		that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );

		//Append it after the actual current item
		that.currentItem.after( that.placeholder );

		//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
		o.placeholder.update( that, that.placeholder );

	},

	_createTrPlaceholder: function( sourceTr, targetTr ) {
		var that = this;

		sourceTr.children().each( function() {
			$( "<td>&#160;</td>", that.document[ 0 ] )
				.attr( "colspan", $( this ).attr( "colspan" ) || 1 )
				.appendTo( targetTr );
		} );
	},

	_contactContainers: function( event ) {
		var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
			floating, axis,
			innermostContainer = null,
			innermostIndex = null;

		// Get innermost container that intersects with item
		for ( i = this.containers.length - 1; i >= 0; i-- ) {

			// Never consider a container that's located within the item itself
			if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
				continue;
			}

			if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {

				// If we've already found a container and it's more "inner" than this, then continue
				if ( innermostContainer &&
						$.contains(
							this.containers[ i ].element[ 0 ],
							innermostContainer.element[ 0 ] ) ) {
					continue;
				}

				innermostContainer = this.containers[ i ];
				innermostIndex = i;

			} else {

				// container doesn't intersect. trigger "out" event if necessary
				if ( this.containers[ i ].containerCache.over ) {
					this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
					this.containers[ i ].containerCache.over = 0;
				}
			}

		}

		// If no intersecting containers found, return
		if ( !innermostContainer ) {
			return;
		}

		// Move the item into the container if it's not there already
		if ( this.containers.length === 1 ) {
			if ( !this.containers[ innermostIndex ].containerCache.over ) {
				this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
				this.containers[ innermostIndex ].containerCache.over = 1;
			}
		} else {

			// When entering a new container, we will find the item with the least distance and
			// append our item near it
			dist = 10000;
			itemWithLeastDistance = null;
			floating = innermostContainer.floating || this._isFloating( this.currentItem );
			posProperty = floating ? "left" : "top";
			sizeProperty = floating ? "width" : "height";
			axis = floating ? "pageX" : "pageY";

			for ( j = this.items.length - 1; j >= 0; j-- ) {
				if ( !$.contains(
						this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
				) {
					continue;
				}
				if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
					continue;
				}

				cur = this.items[ j ].item.offset()[ posProperty ];
				nearBottom = false;
				if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
					nearBottom = true;
				}

				if ( Math.abs( event[ axis ] - cur ) < dist ) {
					dist = Math.abs( event[ axis ] - cur );
					itemWithLeastDistance = this.items[ j ];
					this.direction = nearBottom ? "up" : "down";
				}
			}

			//Check if dropOnEmpty is enabled
			if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
				return;
			}

			if ( this.currentContainer === this.containers[ innermostIndex ] ) {
				if ( !this.currentContainer.containerCache.over ) {
					this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
					this.currentContainer.containerCache.over = 1;
				}
				return;
			}

			itemWithLeastDistance ?
				this._rearrange( event, itemWithLeastDistance, null, true ) :
				this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
			this._trigger( "change", event, this._uiHash() );
			this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
			this.currentContainer = this.containers[ innermostIndex ];

			//Update the placeholder
			this.options.placeholder.update( this.currentContainer, this.placeholder );

			this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
			this.containers[ innermostIndex ].containerCache.over = 1;
		}

	},

	_createHelper: function( event ) {

		var o = this.options,
			helper = $.isFunction( o.helper ) ?
				$( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
				( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );

		//Add the helper to the DOM if that didn't happen already
		if ( !helper.parents( "body" ).length ) {
			$( o.appendTo !== "parent" ?
				o.appendTo :
				this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
		}

		if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
			this._storedCSS = {
				width: this.currentItem[ 0 ].style.width,
				height: this.currentItem[ 0 ].style.height,
				position: this.currentItem.css( "position" ),
				top: this.currentItem.css( "top" ),
				left: this.currentItem.css( "left" )
			};
		}

		if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
			helper.width( this.currentItem.width() );
		}
		if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
			helper.height( this.currentItem.height() );
		}

		return helper;

	},

	_adjustOffsetFromHelper: function( obj ) {
		if ( typeof obj === "string" ) {
			obj = obj.split( " " );
		}
		if ( $.isArray( obj ) ) {
			obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
		}
		if ( "left" in obj ) {
			this.offset.click.left = obj.left + this.margins.left;
		}
		if ( "right" in obj ) {
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
		}
		if ( "top" in obj ) {
			this.offset.click.top = obj.top + this.margins.top;
		}
		if ( "bottom" in obj ) {
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
		}
	},

	_getParentOffset: function() {

		//Get the offsetParent and cache its position
		this.offsetParent = this.helper.offsetParent();
		var po = this.offsetParent.offset();

		// This is a special case where we need to modify a offset calculated on start, since the
		// following happened:
		// 1. The position of the helper is absolute, so it's position is calculated based on the
		// next positioned parent
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
		// the document, which means that the scroll is included in the initial calculation of the
		// offset of the parent, and never recalculated upon drag
		if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
			po.left += this.scrollParent.scrollLeft();
			po.top += this.scrollParent.scrollTop();
		}

		// This needs to be actually done for all browsers, since pageX/pageY includes this
		// information with an ugly IE fix
		if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
				( this.offsetParent[ 0 ].tagName &&
				this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
			po = { top: 0, left: 0 };
		}

		return {
			top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
			left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
		};

	},

	_getRelativeOffset: function() {

		if ( this.cssPosition === "relative" ) {
			var p = this.currentItem.position();
			return {
				top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
					this.scrollParent.scrollTop(),
				left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
					this.scrollParent.scrollLeft()
			};
		} else {
			return { top: 0, left: 0 };
		}

	},

	_cacheMargins: function() {
		this.margins = {
			left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
			top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
		};
	},

	_cacheHelperProportions: function() {
		this.helperProportions = {
			width: this.helper.outerWidth(),
			height: this.helper.outerHeight()
		};
	},

	_setContainment: function() {

		var ce, co, over,
			o = this.options;
		if ( o.containment === "parent" ) {
			o.containment = this.helper[ 0 ].parentNode;
		}
		if ( o.containment === "document" || o.containment === "window" ) {
			this.containment = [
				0 - this.offset.relative.left - this.offset.parent.left,
				0 - this.offset.relative.top - this.offset.parent.top,
				o.containment === "document" ?
					this.document.width() :
					this.window.width() - this.helperProportions.width - this.margins.left,
				( o.containment === "document" ?
					( this.document.height() || document.body.parentNode.scrollHeight ) :
					this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
				) - this.helperProportions.height - this.margins.top
			];
		}

		if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
			ce = $( o.containment )[ 0 ];
			co = $( o.containment ).offset();
			over = ( $( ce ).css( "overflow" ) !== "hidden" );

			this.containment = [
				co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
					( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
				co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
					( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
				co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
					( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
					( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
					this.helperProportions.width - this.margins.left,
				co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
					( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
					( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
					this.helperProportions.height - this.margins.top
			];
		}

	},

	_convertPositionTo: function( d, pos ) {

		if ( !pos ) {
			pos = this.position;
		}
		var mod = d === "absolute" ? 1 : -1,
			scroll = this.cssPosition === "absolute" &&
				!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
					this.offsetParent :
					this.scrollParent,
			scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );

		return {
			top: (

				// The absolute mouse position
				pos.top	+

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.top * mod +

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.top * mod -
				( ( this.cssPosition === "fixed" ?
					-this.scrollParent.scrollTop() :
					( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
			),
			left: (

				// The absolute mouse position
				pos.left +

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.left * mod +

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.left * mod	-
				( ( this.cssPosition === "fixed" ?
					-this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
					scroll.scrollLeft() ) * mod )
			)
		};

	},

	_generatePosition: function( event ) {

		var top, left,
			o = this.options,
			pageX = event.pageX,
			pageY = event.pageY,
			scroll = this.cssPosition === "absolute" &&
				!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
					this.offsetParent :
					this.scrollParent,
				scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );

		// This is another very weird special case that only happens for relative elements:
		// 1. If the css position is relative
		// 2. and the scroll parent is the document or similar to the offset parent
		// we have to refresh the relative offset during the scroll so there are no jumps
		if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
			this.offset.relative = this._getRelativeOffset();
		}

		/*
		 * - Position constraining -
		 * Constrain the position to a mix of grid, containment.
		 */

		if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options

			if ( this.containment ) {
				if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
					pageX = this.containment[ 0 ] + this.offset.click.left;
				}
				if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
					pageY = this.containment[ 1 ] + this.offset.click.top;
				}
				if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
					pageX = this.containment[ 2 ] + this.offset.click.left;
				}
				if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
					pageY = this.containment[ 3 ] + this.offset.click.top;
				}
			}

			if ( o.grid ) {
				top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
					o.grid[ 1 ] ) * o.grid[ 1 ];
				pageY = this.containment ?
					( ( top - this.offset.click.top >= this.containment[ 1 ] &&
						top - this.offset.click.top <= this.containment[ 3 ] ) ?
							top :
							( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
								top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
								top;

				left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
					o.grid[ 0 ] ) * o.grid[ 0 ];
				pageX = this.containment ?
					( ( left - this.offset.click.left >= this.containment[ 0 ] &&
						left - this.offset.click.left <= this.containment[ 2 ] ) ?
							left :
							( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
								left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
								left;
			}

		}

		return {
			top: (

				// The absolute mouse position
				pageY -

				// Click offset (relative to the element)
				this.offset.click.top -

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.top -

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.top +
				( ( this.cssPosition === "fixed" ?
					-this.scrollParent.scrollTop() :
					( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
			),
			left: (

				// The absolute mouse position
				pageX -

				// Click offset (relative to the element)
				this.offset.click.left -

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.left -

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.left +
				( ( this.cssPosition === "fixed" ?
					-this.scrollParent.scrollLeft() :
					scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
			)
		};

	},

	_rearrange: function( event, i, a, hardRefresh ) {

		a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
			i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
				( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );

		//Various things done here to improve the performance:
		// 1. we create a setTimeout, that calls refreshPositions
		// 2. on the instance, we have a counter variable, that get's higher after every append
		// 3. on the local scope, we copy the counter variable, and check in the timeout,
		// if it's still the same
		// 4. this lets only the last addition to the timeout stack through
		this.counter = this.counter ? ++this.counter : 1;
		var counter = this.counter;

		this._delay( function() {
			if ( counter === this.counter ) {

				//Precompute after each DOM insertion, NOT on mousemove
				this.refreshPositions( !hardRefresh );
			}
		} );

	},

	_clear: function( event, noPropagation ) {

		this.reverting = false;

		// We delay all events that have to be triggered to after the point where the placeholder
		// has been removed and everything else normalized again
		var i,
			delayedTriggers = [];

		// We first have to update the dom position of the actual currentItem
		// Note: don't do it if the current item is already removed (by a user), or it gets
		// reappended (see #4088)
		if ( !this._noFinalSort && this.currentItem.parent().length ) {
			this.placeholder.before( this.currentItem );
		}
		this._noFinalSort = null;

		if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
			for ( i in this._storedCSS ) {
				if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
					this._storedCSS[ i ] = "";
				}
			}
			this.currentItem.css( this._storedCSS );
			this._removeClass( this.currentItem, "ui-sortable-helper" );
		} else {
			this.currentItem.show();
		}

		if ( this.fromOutside && !noPropagation ) {
			delayedTriggers.push( function( event ) {
				this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
			} );
		}
		if ( ( this.fromOutside ||
				this.domPosition.prev !==
				this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
				this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {

			// Trigger update callback if the DOM position has changed
			delayedTriggers.push( function( event ) {
				this._trigger( "update", event, this._uiHash() );
			} );
		}

		// Check if the items Container has Changed and trigger appropriate
		// events.
		if ( this !== this.currentContainer ) {
			if ( !noPropagation ) {
				delayedTriggers.push( function( event ) {
					this._trigger( "remove", event, this._uiHash() );
				} );
				delayedTriggers.push( ( function( c ) {
					return function( event ) {
						c._trigger( "receive", event, this._uiHash( this ) );
					};
				} ).call( this, this.currentContainer ) );
				delayedTriggers.push( ( function( c ) {
					return function( event ) {
						c._trigger( "update", event, this._uiHash( this ) );
					};
				} ).call( this, this.currentContainer ) );
			}
		}

		//Post events to containers
		function delayEvent( type, instance, container ) {
			return function( event ) {
				container._trigger( type, event, instance._uiHash( instance ) );
			};
		}
		for ( i = this.containers.length - 1; i >= 0; i-- ) {
			if ( !noPropagation ) {
				delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
			}
			if ( this.containers[ i ].containerCache.over ) {
				delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
				this.containers[ i ].containerCache.over = 0;
			}
		}

		//Do what was originally in plugins
		if ( this.storedCursor ) {
			this.document.find( "body" ).css( "cursor", this.storedCursor );
			this.storedStylesheet.remove();
		}
		if ( this._storedOpacity ) {
			this.helper.css( "opacity", this._storedOpacity );
		}
		if ( this._storedZIndex ) {
			this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
		}

		this.dragging = false;

		if ( !noPropagation ) {
			this._trigger( "beforeStop", event, this._uiHash() );
		}

		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
		// it unbinds ALL events from the original node!
		this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );

		if ( !this.cancelHelperRemoval ) {
			if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
				this.helper.remove();
			}
			this.helper = null;
		}

		if ( !noPropagation ) {
			for ( i = 0; i < delayedTriggers.length; i++ ) {

				// Trigger all delayed events
				delayedTriggers[ i ].call( this, event );
			}
			this._trigger( "stop", event, this._uiHash() );
		}

		this.fromOutside = false;
		return !this.cancelHelperRemoval;

	},

	_trigger: function() {
		if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
			this.cancel();
		}
	},

	_uiHash: function( _inst ) {
		var inst = _inst || this;
		return {
			helper: inst.helper,
			placeholder: inst.placeholder || $( [] ),
			position: inst.position,
			originalPosition: inst.originalPosition,
			offset: inst.positionAbs,
			item: inst.currentItem,
			sender: _inst ? _inst.element : null
		};
	}

} );


/*!
 * jQuery UI Spinner 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Spinner
//>>group: Widgets
//>>description: Displays buttons to easily input numbers via the keyboard or mouse.
//>>docs: http://api.jqueryui.com/spinner/
//>>demos: http://jqueryui.com/spinner/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/spinner.css
//>>css.theme: ../../themes/base/theme.css



function spinnerModifer( fn ) {
	return function() {
		var previous = this.element.val();
		fn.apply( this, arguments );
		this._refresh();
		if ( previous !== this.element.val() ) {
			this._trigger( "change" );
		}
	};
}

$.widget( "ui.spinner", {
	version: "1.12.1",
	defaultElement: "<input>",
	widgetEventPrefix: "spin",
	options: {
		classes: {
			"ui-spinner": "ui-corner-all",
			"ui-spinner-down": "ui-corner-br",
			"ui-spinner-up": "ui-corner-tr"
		},
		culture: null,
		icons: {
			down: "ui-icon-triangle-1-s",
			up: "ui-icon-triangle-1-n"
		},
		incremental: true,
		max: null,
		min: null,
		numberFormat: null,
		page: 10,
		step: 1,

		change: null,
		spin: null,
		start: null,
		stop: null
	},

	_create: function() {

		// handle string values that need to be parsed
		this._setOption( "max", this.options.max );
		this._setOption( "min", this.options.min );
		this._setOption( "step", this.options.step );

		// Only format if there is a value, prevents the field from being marked
		// as invalid in Firefox, see #9573.
		if ( this.value() !== "" ) {

			// Format the value, but don't constrain.
			this._value( this.element.val(), true );
		}

		this._draw();
		this._on( this._events );
		this._refresh();

		// Turning off autocomplete prevents the browser from remembering the
		// value when navigating through history, so we re-enable autocomplete
		// if the page is unloaded before the widget is destroyed. #7790
		this._on( this.window, {
			beforeunload: function() {
				this.element.removeAttr( "autocomplete" );
			}
		} );
	},

	_getCreateOptions: function() {
		var options = this._super();
		var element = this.element;

		$.each( [ "min", "max", "step" ], function( i, option ) {
			var value = element.attr( option );
			if ( value != null && value.length ) {
				options[ option ] = value;
			}
		} );

		return options;
	},

	_events: {
		keydown: function( event ) {
			if ( this._start( event ) && this._keydown( event ) ) {
				event.preventDefault();
			}
		},
		keyup: "_stop",
		focus: function() {
			this.previous = this.element.val();
		},
		blur: function( event ) {
			if ( this.cancelBlur ) {
				delete this.cancelBlur;
				return;
			}

			this._stop();
			this._refresh();
			if ( this.previous !== this.element.val() ) {
				this._trigger( "change", event );
			}
		},
		mousewheel: function( event, delta ) {
			if ( !delta ) {
				return;
			}
			if ( !this.spinning && !this._start( event ) ) {
				return false;
			}

			this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
			clearTimeout( this.mousewheelTimer );
			this.mousewheelTimer = this._delay( function() {
				if ( this.spinning ) {
					this._stop( event );
				}
			}, 100 );
			event.preventDefault();
		},
		"mousedown .ui-spinner-button": function( event ) {
			var previous;

			// We never want the buttons to have focus; whenever the user is
			// interacting with the spinner, the focus should be on the input.
			// If the input is focused then this.previous is properly set from
			// when the input first received focus. If the input is not focused
			// then we need to set this.previous based on the value before spinning.
			previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
				this.previous : this.element.val();
			function checkFocus() {
				var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
				if ( !isActive ) {
					this.element.trigger( "focus" );
					this.previous = previous;

					// support: IE
					// IE sets focus asynchronously, so we need to check if focus
					// moved off of the input because the user clicked on the button.
					this._delay( function() {
						this.previous = previous;
					} );
				}
			}

			// Ensure focus is on (or stays on) the text field
			event.preventDefault();
			checkFocus.call( this );

			// Support: IE
			// IE doesn't prevent moving focus even with event.preventDefault()
			// so we set a flag to know when we should ignore the blur event
			// and check (again) if focus moved off of the input.
			this.cancelBlur = true;
			this._delay( function() {
				delete this.cancelBlur;
				checkFocus.call( this );
			} );

			if ( this._start( event ) === false ) {
				return;
			}

			this._repeat( null, $( event.currentTarget )
				.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
		},
		"mouseup .ui-spinner-button": "_stop",
		"mouseenter .ui-spinner-button": function( event ) {

			// button will add ui-state-active if mouse was down while mouseleave and kept down
			if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
				return;
			}

			if ( this._start( event ) === false ) {
				return false;
			}
			this._repeat( null, $( event.currentTarget )
				.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
		},

		// TODO: do we really want to consider this a stop?
		// shouldn't we just stop the repeater and wait until mouseup before
		// we trigger the stop event?
		"mouseleave .ui-spinner-button": "_stop"
	},

	// Support mobile enhanced option and make backcompat more sane
	_enhance: function() {
		this.uiSpinner = this.element
			.attr( "autocomplete", "off" )
			.wrap( "<span>" )
			.parent()

				// Add buttons
				.append(
					"<a></a><a></a>"
				);
	},

	_draw: function() {
		this._enhance();

		this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
		this._addClass( "ui-spinner-input" );

		this.element.attr( "role", "spinbutton" );

		// Button bindings
		this.buttons = this.uiSpinner.children( "a" )
			.attr( "tabIndex", -1 )
			.attr( "aria-hidden", true )
			.button( {
				classes: {
					"ui-button": ""
				}
			} );

		// TODO: Right now button does not support classes this is already updated in button PR
		this._removeClass( this.buttons, "ui-corner-all" );

		this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
		this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
		this.buttons.first().button( {
			"icon": this.options.icons.up,
			"showLabel": false
		} );
		this.buttons.last().button( {
			"icon": this.options.icons.down,
			"showLabel": false
		} );

		// IE 6 doesn't understand height: 50% for the buttons
		// unless the wrapper has an explicit height
		if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
				this.uiSpinner.height() > 0 ) {
			this.uiSpinner.height( this.uiSpinner.height() );
		}
	},

	_keydown: function( event ) {
		var options = this.options,
			keyCode = $.ui.keyCode;

		switch ( event.keyCode ) {
		case keyCode.UP:
			this._repeat( null, 1, event );
			return true;
		case keyCode.DOWN:
			this._repeat( null, -1, event );
			return true;
		case keyCode.PAGE_UP:
			this._repeat( null, options.page, event );
			return true;
		case keyCode.PAGE_DOWN:
			this._repeat( null, -options.page, event );
			return true;
		}

		return false;
	},

	_start: function( event ) {
		if ( !this.spinning && this._trigger( "start", event ) === false ) {
			return false;
		}

		if ( !this.counter ) {
			this.counter = 1;
		}
		this.spinning = true;
		return true;
	},

	_repeat: function( i, steps, event ) {
		i = i || 500;

		clearTimeout( this.timer );
		this.timer = this._delay( function() {
			this._repeat( 40, steps, event );
		}, i );

		this._spin( steps * this.options.step, event );
	},

	_spin: function( step, event ) {
		var value = this.value() || 0;

		if ( !this.counter ) {
			this.counter = 1;
		}

		value = this._adjustValue( value + step * this._increment( this.counter ) );

		if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
			this._value( value );
			this.counter++;
		}
	},

	_increment: function( i ) {
		var incremental = this.options.incremental;

		if ( incremental ) {
			return $.isFunction( incremental ) ?
				incremental( i ) :
				Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
		}

		return 1;
	},

	_precision: function() {
		var precision = this._precisionOf( this.options.step );
		if ( this.options.min !== null ) {
			precision = Math.max( precision, this._precisionOf( this.options.min ) );
		}
		return precision;
	},

	_precisionOf: function( num ) {
		var str = num.toString(),
			decimal = str.indexOf( "." );
		return decimal === -1 ? 0 : str.length - decimal - 1;
	},

	_adjustValue: function( value ) {
		var base, aboveMin,
			options = this.options;

		// Make sure we're at a valid step
		// - find out where we are relative to the base (min or 0)
		base = options.min !== null ? options.min : 0;
		aboveMin = value - base;

		// - round to the nearest step
		aboveMin = Math.round( aboveMin / options.step ) * options.step;

		// - rounding is based on 0, so adjust back to our base
		value = base + aboveMin;

		// Fix precision from bad JS floating point math
		value = parseFloat( value.toFixed( this._precision() ) );

		// Clamp the value
		if ( options.max !== null && value > options.max ) {
			return options.max;
		}
		if ( options.min !== null && value < options.min ) {
			return options.min;
		}

		return value;
	},

	_stop: function( event ) {
		if ( !this.spinning ) {
			return;
		}

		clearTimeout( this.timer );
		clearTimeout( this.mousewheelTimer );
		this.counter = 0;
		this.spinning = false;
		this._trigger( "stop", event );
	},

	_setOption: function( key, value ) {
		var prevValue, first, last;

		if ( key === "culture" || key === "numberFormat" ) {
			prevValue = this._parse( this.element.val() );
			this.options[ key ] = value;
			this.element.val( this._format( prevValue ) );
			return;
		}

		if ( key === "max" || key === "min" || key === "step" ) {
			if ( typeof value === "string" ) {
				value = this._parse( value );
			}
		}
		if ( key === "icons" ) {
			first = this.buttons.first().find( ".ui-icon" );
			this._removeClass( first, null, this.options.icons.up );
			this._addClass( first, null, value.up );
			last = this.buttons.last().find( ".ui-icon" );
			this._removeClass( last, null, this.options.icons.down );
			this._addClass( last, null, value.down );
		}

		this._super( key, value );
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
		this.element.prop( "disabled", !!value );
		this.buttons.button( value ? "disable" : "enable" );
	},

	_setOptions: spinnerModifer( function( options ) {
		this._super( options );
	} ),

	_parse: function( val ) {
		if ( typeof val === "string" && val !== "" ) {
			val = window.Globalize && this.options.numberFormat ?
				Globalize.parseFloat( val, 10, this.options.culture ) : +val;
		}
		return val === "" || isNaN( val ) ? null : val;
	},

	_format: function( value ) {
		if ( value === "" ) {
			return "";
		}
		return window.Globalize && this.options.numberFormat ?
			Globalize.format( value, this.options.numberFormat, this.options.culture ) :
			value;
	},

	_refresh: function() {
		this.element.attr( {
			"aria-valuemin": this.options.min,
			"aria-valuemax": this.options.max,

			// TODO: what should we do with values that can't be parsed?
			"aria-valuenow": this._parse( this.element.val() )
		} );
	},

	isValid: function() {
		var value = this.value();

		// Null is invalid
		if ( value === null ) {
			return false;
		}

		// If value gets adjusted, it's invalid
		return value === this._adjustValue( value );
	},

	// Update the value without triggering change
	_value: function( value, allowAny ) {
		var parsed;
		if ( value !== "" ) {
			parsed = this._parse( value );
			if ( parsed !== null ) {
				if ( !allowAny ) {
					parsed = this._adjustValue( parsed );
				}
				value = this._format( parsed );
			}
		}
		this.element.val( value );
		this._refresh();
	},

	_destroy: function() {
		this.element
			.prop( "disabled", false )
			.removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );

		this.uiSpinner.replaceWith( this.element );
	},

	stepUp: spinnerModifer( function( steps ) {
		this._stepUp( steps );
	} ),
	_stepUp: function( steps ) {
		if ( this._start() ) {
			this._spin( ( steps || 1 ) * this.options.step );
			this._stop();
		}
	},

	stepDown: spinnerModifer( function( steps ) {
		this._stepDown( steps );
	} ),
	_stepDown: function( steps ) {
		if ( this._start() ) {
			this._spin( ( steps || 1 ) * -this.options.step );
			this._stop();
		}
	},

	pageUp: spinnerModifer( function( pages ) {
		this._stepUp( ( pages || 1 ) * this.options.page );
	} ),

	pageDown: spinnerModifer( function( pages ) {
		this._stepDown( ( pages || 1 ) * this.options.page );
	} ),

	value: function( newVal ) {
		if ( !arguments.length ) {
			return this._parse( this.element.val() );
		}
		spinnerModifer( this._value ).call( this, newVal );
	},

	widget: function() {
		return this.uiSpinner;
	}
} );

// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for spinner html extension points
	$.widget( "ui.spinner", $.ui.spinner, {
		_enhance: function() {
			this.uiSpinner = this.element
				.attr( "autocomplete", "off" )
				.wrap( this._uiSpinnerHtml() )
				.parent()

					// Add buttons
					.append( this._buttonHtml() );
		},
		_uiSpinnerHtml: function() {
			return "<span>";
		},

		_buttonHtml: function() {
			return "<a></a><a></a>";
		}
	} );
}

var widgetsSpinner = $.ui.spinner;


/*!
 * jQuery UI Tabs 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Tabs
//>>group: Widgets
//>>description: Transforms a set of container elements into a tab structure.
//>>docs: http://api.jqueryui.com/tabs/
//>>demos: http://jqueryui.com/tabs/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/tabs.css
//>>css.theme: ../../themes/base/theme.css



$.widget( "ui.tabs", {
	version: "1.12.1",
	delay: 300,
	options: {
		active: null,
		classes: {
			"ui-tabs": "ui-corner-all",
			"ui-tabs-nav": "ui-corner-all",
			"ui-tabs-panel": "ui-corner-bottom",
			"ui-tabs-tab": "ui-corner-top"
		},
		collapsible: false,
		event: "click",
		heightStyle: "content",
		hide: null,
		show: null,

		// Callbacks
		activate: null,
		beforeActivate: null,
		beforeLoad: null,
		load: null
	},

	_isLocal: ( function() {
		var rhash = /#.*$/;

		return function( anchor ) {
			var anchorUrl, locationUrl;

			anchorUrl = anchor.href.replace( rhash, "" );
			locationUrl = location.href.replace( rhash, "" );

			// Decoding may throw an error if the URL isn't UTF-8 (#9518)
			try {
				anchorUrl = decodeURIComponent( anchorUrl );
			} catch ( error ) {}
			try {
				locationUrl = decodeURIComponent( locationUrl );
			} catch ( error ) {}

			return anchor.hash.length > 1 && anchorUrl === locationUrl;
		};
	} )(),

	_create: function() {
		var that = this,
			options = this.options;

		this.running = false;

		this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
		this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );

		this._processTabs();
		options.active = this._initialActive();

		// Take disabling tabs via class attribute from HTML
		// into account and update option properly.
		if ( $.isArray( options.disabled ) ) {
			options.disabled = $.unique( options.disabled.concat(
				$.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
					return that.tabs.index( li );
				} )
			) ).sort();
		}

		// Check for length avoids error when initializing empty list
		if ( this.options.active !== false && this.anchors.length ) {
			this.active = this._findActive( options.active );
		} else {
			this.active = $();
		}

		this._refresh();

		if ( this.active.length ) {
			this.load( options.active );
		}
	},

	_initialActive: function() {
		var active = this.options.active,
			collapsible = this.options.collapsible,
			locationHash = location.hash.substring( 1 );

		if ( active === null ) {

			// check the fragment identifier in the URL
			if ( locationHash ) {
				this.tabs.each( function( i, tab ) {
					if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
						active = i;
						return false;
					}
				} );
			}

			// Check for a tab marked active via a class
			if ( active === null ) {
				active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
			}

			// No active tab, set to false
			if ( active === null || active === -1 ) {
				active = this.tabs.length ? 0 : false;
			}
		}

		// Handle numbers: negative, out of range
		if ( active !== false ) {
			active = this.tabs.index( this.tabs.eq( active ) );
			if ( active === -1 ) {
				active = collapsible ? false : 0;
			}
		}

		// Don't allow collapsible: false and active: false
		if ( !collapsible && active === false && this.anchors.length ) {
			active = 0;
		}

		return active;
	},

	_getCreateEventData: function() {
		return {
			tab: this.active,
			panel: !this.active.length ? $() : this._getPanelForTab( this.active )
		};
	},

	_tabKeydown: function( event ) {
		var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
			selectedIndex = this.tabs.index( focusedTab ),
			goingForward = true;

		if ( this._handlePageNav( event ) ) {
			return;
		}

		switch ( event.keyCode ) {
		case $.ui.keyCode.RIGHT:
		case $.ui.keyCode.DOWN:
			selectedIndex++;
			break;
		case $.ui.keyCode.UP:
		case $.ui.keyCode.LEFT:
			goingForward = false;
			selectedIndex--;
			break;
		case $.ui.keyCode.END:
			selectedIndex = this.anchors.length - 1;
			break;
		case $.ui.keyCode.HOME:
			selectedIndex = 0;
			break;
		case $.ui.keyCode.SPACE:

			// Activate only, no collapsing
			event.preventDefault();
			clearTimeout( this.activating );
			this._activate( selectedIndex );
			return;
		case $.ui.keyCode.ENTER:

			// Toggle (cancel delayed activation, allow collapsing)
			event.preventDefault();
			clearTimeout( this.activating );

			// Determine if we should collapse or activate
			this._activate( selectedIndex === this.options.active ? false : selectedIndex );
			return;
		default:
			return;
		}

		// Focus the appropriate tab, based on which key was pressed
		event.preventDefault();
		clearTimeout( this.activating );
		selectedIndex = this._focusNextTab( selectedIndex, goingForward );

		// Navigating with control/command key will prevent automatic activation
		if ( !event.ctrlKey && !event.metaKey ) {

			// Update aria-selected immediately so that AT think the tab is already selected.
			// Otherwise AT may confuse the user by stating that they need to activate the tab,
			// but the tab will already be activated by the time the announcement finishes.
			focusedTab.attr( "aria-selected", "false" );
			this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );

			this.activating = this._delay( function() {
				this.option( "active", selectedIndex );
			}, this.delay );
		}
	},

	_panelKeydown: function( event ) {
		if ( this._handlePageNav( event ) ) {
			return;
		}

		// Ctrl+up moves focus to the current tab
		if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
			event.preventDefault();
			this.active.trigger( "focus" );
		}
	},

	// Alt+page up/down moves focus to the previous/next tab (and activates)
	_handlePageNav: function( event ) {
		if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
			this._activate( this._focusNextTab( this.options.active - 1, false ) );
			return true;
		}
		if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
			this._activate( this._focusNextTab( this.options.active + 1, true ) );
			return true;
		}
	},

	_findNextTab: function( index, goingForward ) {
		var lastTabIndex = this.tabs.length - 1;

		function constrain() {
			if ( index > lastTabIndex ) {
				index = 0;
			}
			if ( index < 0 ) {
				index = lastTabIndex;
			}
			return index;
		}

		while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
			index = goingForward ? index + 1 : index - 1;
		}

		return index;
	},

	_focusNextTab: function( index, goingForward ) {
		index = this._findNextTab( index, goingForward );
		this.tabs.eq( index ).trigger( "focus" );
		return index;
	},

	_setOption: function( key, value ) {
		if ( key === "active" ) {

			// _activate() will handle invalid values and update this.options
			this._activate( value );
			return;
		}

		this._super( key, value );

		if ( key === "collapsible" ) {
			this._toggleClass( "ui-tabs-collapsible", null, value );

			// Setting collapsible: false while collapsed; open first panel
			if ( !value && this.options.active === false ) {
				this._activate( 0 );
			}
		}

		if ( key === "event" ) {
			this._setupEvents( value );
		}

		if ( key === "heightStyle" ) {
			this._setupHeightStyle( value );
		}
	},

	_sanitizeSelector: function( hash ) {
		return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
	},

	refresh: function() {
		var options = this.options,
			lis = this.tablist.children( ":has(a[href])" );

		// Get disabled tabs from class attribute from HTML
		// this will get converted to a boolean if needed in _refresh()
		options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
			return lis.index( tab );
		} );

		this._processTabs();

		// Was collapsed or no tabs
		if ( options.active === false || !this.anchors.length ) {
			options.active = false;
			this.active = $();

		// was active, but active tab is gone
		} else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {

			// all remaining tabs are disabled
			if ( this.tabs.length === options.disabled.length ) {
				options.active = false;
				this.active = $();

			// activate previous tab
			} else {
				this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
			}

		// was active, active tab still exists
		} else {

			// make sure active index is correct
			options.active = this.tabs.index( this.active );
		}

		this._refresh();
	},

	_refresh: function() {
		this._setOptionDisabled( this.options.disabled );
		this._setupEvents( this.options.event );
		this._setupHeightStyle( this.options.heightStyle );

		this.tabs.not( this.active ).attr( {
			"aria-selected": "false",
			"aria-expanded": "false",
			tabIndex: -1
		} );
		this.panels.not( this._getPanelForTab( this.active ) )
			.hide()
			.attr( {
				"aria-hidden": "true"
			} );

		// Make sure one tab is in the tab order
		if ( !this.active.length ) {
			this.tabs.eq( 0 ).attr( "tabIndex", 0 );
		} else {
			this.active
				.attr( {
					"aria-selected": "true",
					"aria-expanded": "true",
					tabIndex: 0
				} );
			this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
			this._getPanelForTab( this.active )
				.show()
				.attr( {
					"aria-hidden": "false"
				} );
		}
	},

	_processTabs: function() {
		var that = this,
			prevTabs = this.tabs,
			prevAnchors = this.anchors,
			prevPanels = this.panels;

		this.tablist = this._getList().attr( "role", "tablist" );
		this._addClass( this.tablist, "ui-tabs-nav",
			"ui-helper-reset ui-helper-clearfix ui-widget-header" );

		// Prevent users from focusing disabled tabs via click
		this.tablist
			.on( "mousedown" + this.eventNamespace, "> li", function( event ) {
				if ( $( this ).is( ".ui-state-disabled" ) ) {
					event.preventDefault();
				}
			} )

			// Support: IE <9
			// Preventing the default action in mousedown doesn't prevent IE
			// from focusing the element, so if the anchor gets focused, blur.
			// We don't have to worry about focusing the previously focused
			// element since clicking on a non-focusable element should focus
			// the body anyway.
			.on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
				if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
					this.blur();
				}
			} );

		this.tabs = this.tablist.find( "> li:has(a[href])" )
			.attr( {
				role: "tab",
				tabIndex: -1
			} );
		this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );

		this.anchors = this.tabs.map( function() {
			return $( "a", this )[ 0 ];
		} )
			.attr( {
				role: "presentation",
				tabIndex: -1
			} );
		this._addClass( this.anchors, "ui-tabs-anchor" );

		this.panels = $();

		this.anchors.each( function( i, anchor ) {
			var selector, panel, panelId,
				anchorId = $( anchor ).uniqueId().attr( "id" ),
				tab = $( anchor ).closest( "li" ),
				originalAriaControls = tab.attr( "aria-controls" );

			// Inline tab
			if ( that._isLocal( anchor ) ) {
				selector = anchor.hash;
				panelId = selector.substring( 1 );
				panel = that.element.find( that._sanitizeSelector( selector ) );

			// remote tab
			} else {

				// If the tab doesn't already have aria-controls,
				// generate an id by using a throw-away element
				panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
				selector = "#" + panelId;
				panel = that.element.find( selector );
				if ( !panel.length ) {
					panel = that._createPanel( panelId );
					panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
				}
				panel.attr( "aria-live", "polite" );
			}

			if ( panel.length ) {
				that.panels = that.panels.add( panel );
			}
			if ( originalAriaControls ) {
				tab.data( "ui-tabs-aria-controls", originalAriaControls );
			}
			tab.attr( {
				"aria-controls": panelId,
				"aria-labelledby": anchorId
			} );
			panel.attr( "aria-labelledby", anchorId );
		} );

		this.panels.attr( "role", "tabpanel" );
		this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );

		// Avoid memory leaks (#10056)
		if ( prevTabs ) {
			this._off( prevTabs.not( this.tabs ) );
			this._off( prevAnchors.not( this.anchors ) );
			this._off( prevPanels.not( this.panels ) );
		}
	},

	// Allow overriding how to find the list for rare usage scenarios (#7715)
	_getList: function() {
		return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
	},

	_createPanel: function( id ) {
		return $( "<div>" )
			.attr( "id", id )
			.data( "ui-tabs-destroy", true );
	},

	_setOptionDisabled: function( disabled ) {
		var currentItem, li, i;

		if ( $.isArray( disabled ) ) {
			if ( !disabled.length ) {
				disabled = false;
			} else if ( disabled.length === this.anchors.length ) {
				disabled = true;
			}
		}

		// Disable tabs
		for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
			currentItem = $( li );
			if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
				currentItem.attr( "aria-disabled", "true" );
				this._addClass( currentItem, null, "ui-state-disabled" );
			} else {
				currentItem.removeAttr( "aria-disabled" );
				this._removeClass( currentItem, null, "ui-state-disabled" );
			}
		}

		this.options.disabled = disabled;

		this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
			disabled === true );
	},

	_setupEvents: function( event ) {
		var events = {};
		if ( event ) {
			$.each( event.split( " " ), function( index, eventName ) {
				events[ eventName ] = "_eventHandler";
			} );
		}

		this._off( this.anchors.add( this.tabs ).add( this.panels ) );

		// Always prevent the default action, even when disabled
		this._on( true, this.anchors, {
			click: function( event ) {
				event.preventDefault();
			}
		} );
		this._on( this.anchors, events );
		this._on( this.tabs, { keydown: "_tabKeydown" } );
		this._on( this.panels, { keydown: "_panelKeydown" } );

		this._focusable( this.tabs );
		this._hoverable( this.tabs );
	},

	_setupHeightStyle: function( heightStyle ) {
		var maxHeight,
			parent = this.element.parent();

		if ( heightStyle === "fill" ) {
			maxHeight = parent.height();
			maxHeight -= this.element.outerHeight() - this.element.height();

			this.element.siblings( ":visible" ).each( function() {
				var elem = $( this ),
					position = elem.css( "position" );

				if ( position === "absolute" || position === "fixed" ) {
					return;
				}
				maxHeight -= elem.outerHeight( true );
			} );

			this.element.children().not( this.panels ).each( function() {
				maxHeight -= $( this ).outerHeight( true );
			} );

			this.panels.each( function() {
				$( this ).height( Math.max( 0, maxHeight -
					$( this ).innerHeight() + $( this ).height() ) );
			} )
				.css( "overflow", "auto" );
		} else if ( heightStyle === "auto" ) {
			maxHeight = 0;
			this.panels.each( function() {
				maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
			} ).height( maxHeight );
		}
	},

	_eventHandler: function( event ) {
		var options = this.options,
			active = this.active,
			anchor = $( event.currentTarget ),
			tab = anchor.closest( "li" ),
			clickedIsActive = tab[ 0 ] === active[ 0 ],
			collapsing = clickedIsActive && options.collapsible,
			toShow = collapsing ? $() : this._getPanelForTab( tab ),
			toHide = !active.length ? $() : this._getPanelForTab( active ),
			eventData = {
				oldTab: active,
				oldPanel: toHide,
				newTab: collapsing ? $() : tab,
				newPanel: toShow
			};

		event.preventDefault();

		if ( tab.hasClass( "ui-state-disabled" ) ||

				// tab is already loading
				tab.hasClass( "ui-tabs-loading" ) ||

				// can't switch durning an animation
				this.running ||

				// click on active header, but not collapsible
				( clickedIsActive && !options.collapsible ) ||

				// allow canceling activation
				( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
			return;
		}

		options.active = collapsing ? false : this.tabs.index( tab );

		this.active = clickedIsActive ? $() : tab;
		if ( this.xhr ) {
			this.xhr.abort();
		}

		if ( !toHide.length && !toShow.length ) {
			$.error( "jQuery UI Tabs: Mismatching fragment identifier." );
		}

		if ( toShow.length ) {
			this.load( this.tabs.index( tab ), event );
		}
		this._toggle( event, eventData );
	},

	// Handles show/hide for selecting tabs
	_toggle: function( event, eventData ) {
		var that = this,
			toShow = eventData.newPanel,
			toHide = eventData.oldPanel;

		this.running = true;

		function complete() {
			that.running = false;
			that._trigger( "activate", event, eventData );
		}

		function show() {
			that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );

			if ( toShow.length && that.options.show ) {
				that._show( toShow, that.options.show, complete );
			} else {
				toShow.show();
				complete();
			}
		}

		// Start out by hiding, then showing, then completing
		if ( toHide.length && this.options.hide ) {
			this._hide( toHide, this.options.hide, function() {
				that._removeClass( eventData.oldTab.closest( "li" ),
					"ui-tabs-active", "ui-state-active" );
				show();
			} );
		} else {
			this._removeClass( eventData.oldTab.closest( "li" ),
				"ui-tabs-active", "ui-state-active" );
			toHide.hide();
			show();
		}

		toHide.attr( "aria-hidden", "true" );
		eventData.oldTab.attr( {
			"aria-selected": "false",
			"aria-expanded": "false"
		} );

		// If we're switching tabs, remove the old tab from the tab order.
		// If we're opening from collapsed state, remove the previous tab from the tab order.
		// If we're collapsing, then keep the collapsing tab in the tab order.
		if ( toShow.length && toHide.length ) {
			eventData.oldTab.attr( "tabIndex", -1 );
		} else if ( toShow.length ) {
			this.tabs.filter( function() {
				return $( this ).attr( "tabIndex" ) === 0;
			} )
				.attr( "tabIndex", -1 );
		}

		toShow.attr( "aria-hidden", "false" );
		eventData.newTab.attr( {
			"aria-selected": "true",
			"aria-expanded": "true",
			tabIndex: 0
		} );
	},

	_activate: function( index ) {
		var anchor,
			active = this._findActive( index );

		// Trying to activate the already active panel
		if ( active[ 0 ] === this.active[ 0 ] ) {
			return;
		}

		// Trying to collapse, simulate a click on the current active header
		if ( !active.length ) {
			active = this.active;
		}

		anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
		this._eventHandler( {
			target: anchor,
			currentTarget: anchor,
			preventDefault: $.noop
		} );
	},

	_findActive: function( index ) {
		return index === false ? $() : this.tabs.eq( index );
	},

	_getIndex: function( index ) {

		// meta-function to give users option to provide a href string instead of a numerical index.
		if ( typeof index === "string" ) {
			index = this.anchors.index( this.anchors.filter( "[href$='" +
				$.ui.escapeSelector( index ) + "']" ) );
		}

		return index;
	},

	_destroy: function() {
		if ( this.xhr ) {
			this.xhr.abort();
		}

		this.tablist
			.removeAttr( "role" )
			.off( this.eventNamespace );

		this.anchors
			.removeAttr( "role tabIndex" )
			.removeUniqueId();

		this.tabs.add( this.panels ).each( function() {
			if ( $.data( this, "ui-tabs-destroy" ) ) {
				$( this ).remove();
			} else {
				$( this ).removeAttr( "role tabIndex " +
					"aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
			}
		} );

		this.tabs.each( function() {
			var li = $( this ),
				prev = li.data( "ui-tabs-aria-controls" );
			if ( prev ) {
				li
					.attr( "aria-controls", prev )
					.removeData( "ui-tabs-aria-controls" );
			} else {
				li.removeAttr( "aria-controls" );
			}
		} );

		this.panels.show();

		if ( this.options.heightStyle !== "content" ) {
			this.panels.css( "height", "" );
		}
	},

	enable: function( index ) {
		var disabled = this.options.disabled;
		if ( disabled === false ) {
			return;
		}

		if ( index === undefined ) {
			disabled = false;
		} else {
			index = this._getIndex( index );
			if ( $.isArray( disabled ) ) {
				disabled = $.map( disabled, function( num ) {
					return num !== index ? num : null;
				} );
			} else {
				disabled = $.map( this.tabs, function( li, num ) {
					return num !== index ? num : null;
				} );
			}
		}
		this._setOptionDisabled( disabled );
	},

	disable: function( index ) {
		var disabled = this.options.disabled;
		if ( disabled === true ) {
			return;
		}

		if ( index === undefined ) {
			disabled = true;
		} else {
			index = this._getIndex( index );
			if ( $.inArray( index, disabled ) !== -1 ) {
				return;
			}
			if ( $.isArray( disabled ) ) {
				disabled = $.merge( [ index ], disabled ).sort();
			} else {
				disabled = [ index ];
			}
		}
		this._setOptionDisabled( disabled );
	},

	load: function( index, event ) {
		index = this._getIndex( index );
		var that = this,
			tab = this.tabs.eq( index ),
			anchor = tab.find( ".ui-tabs-anchor" ),
			panel = this._getPanelForTab( tab ),
			eventData = {
				tab: tab,
				panel: panel
			},
			complete = function( jqXHR, status ) {
				if ( status === "abort" ) {
					that.panels.stop( false, true );
				}

				that._removeClass( tab, "ui-tabs-loading" );
				panel.removeAttr( "aria-busy" );

				if ( jqXHR === that.xhr ) {
					delete that.xhr;
				}
			};

		// Not remote
		if ( this._isLocal( anchor[ 0 ] ) ) {
			return;
		}

		this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );

		// Support: jQuery <1.8
		// jQuery <1.8 returns false if the request is canceled in beforeSend,
		// but as of 1.8, $.ajax() always returns a jqXHR object.
		if ( this.xhr && this.xhr.statusText !== "canceled" ) {
			this._addClass( tab, "ui-tabs-loading" );
			panel.attr( "aria-busy", "true" );

			this.xhr
				.done( function( response, status, jqXHR ) {

					// support: jQuery <1.8
					// http://bugs.jquery.com/ticket/11778
					setTimeout( function() {
						panel.html( response );
						that._trigger( "load", event, eventData );

						complete( jqXHR, status );
					}, 1 );
				} )
				.fail( function( jqXHR, status ) {

					// support: jQuery <1.8
					// http://bugs.jquery.com/ticket/11778
					setTimeout( function() {
						complete( jqXHR, status );
					}, 1 );
				} );
		}
	},

	_ajaxSettings: function( anchor, event, eventData ) {
		var that = this;
		return {

			// Support: IE <11 only
			// Strip any hash that exists to prevent errors with the Ajax request
			url: anchor.attr( "href" ).replace( /#.*$/, "" ),
			beforeSend: function( jqXHR, settings ) {
				return that._trigger( "beforeLoad", event,
					$.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
			}
		};
	},

	_getPanelForTab: function( tab ) {
		var id = $( tab ).attr( "aria-controls" );
		return this.element.find( this._sanitizeSelector( "#" + id ) );
	}
} );

// DEPRECATED
// TODO: Switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for ui-tab class (now ui-tabs-tab)
	$.widget( "ui.tabs", $.ui.tabs, {
		_processTabs: function() {
			this._superApply( arguments );
			this._addClass( this.tabs, "ui-tab" );
		}
	} );
}

var widgetsTabs = $.ui.tabs;


/*!
 * jQuery UI Tooltip 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Tooltip
//>>group: Widgets
//>>description: Shows additional information for any element on hover or focus.
//>>docs: http://api.jqueryui.com/tooltip/
//>>demos: http://jqueryui.com/tooltip/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/tooltip.css
//>>css.theme: ../../themes/base/theme.css



$.widget( "ui.tooltip", {
	version: "1.12.1",
	options: {
		classes: {
			"ui-tooltip": "ui-corner-all ui-widget-shadow"
		},
		content: function() {

			// support: IE<9, Opera in jQuery <1.7
			// .text() can't accept undefined, so coerce to a string
			var title = $( this ).attr( "title" ) || "";

			// Escape title, since we're going from an attribute to raw HTML
			return $( "<a>" ).text( title ).html();
		},
		hide: true,

		// Disabled elements have inconsistent behavior across browsers (#8661)
		items: "[title]:not([disabled])",
		position: {
			my: "left top+15",
			at: "left bottom",
			collision: "flipfit flip"
		},
		show: true,
		track: false,

		// Callbacks
		close: null,
		open: null
	},

	_addDescribedBy: function( elem, id ) {
		var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
		describedby.push( id );
		elem
			.data( "ui-tooltip-id", id )
			.attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
	},

	_removeDescribedBy: function( elem ) {
		var id = elem.data( "ui-tooltip-id" ),
			describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
			index = $.inArray( id, describedby );

		if ( index !== -1 ) {
			describedby.splice( index, 1 );
		}

		elem.removeData( "ui-tooltip-id" );
		describedby = $.trim( describedby.join( " " ) );
		if ( describedby ) {
			elem.attr( "aria-describedby", describedby );
		} else {
			elem.removeAttr( "aria-describedby" );
		}
	},

	_create: function() {
		this._on( {
			mouseover: "open",
			focusin: "open"
		} );

		// IDs of generated tooltips, needed for destroy
		this.tooltips = {};

		// IDs of parent tooltips where we removed the title attribute
		this.parents = {};

		// Append the aria-live region so tooltips announce correctly
		this.liveRegion = $( "<div>" )
			.attr( {
				role: "log",
				"aria-live": "assertive",
				"aria-relevant": "additions"
			} )
			.appendTo( this.document[ 0 ].body );
		this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );

		this.disabledTitles = $( [] );
	},

	_setOption: function( key, value ) {
		var that = this;

		this._super( key, value );

		if ( key === "content" ) {
			$.each( this.tooltips, function( id, tooltipData ) {
				that._updateContent( tooltipData.element );
			} );
		}
	},

	_setOptionDisabled: function( value ) {
		this[ value ? "_disable" : "_enable" ]();
	},

	_disable: function() {
		var that = this;

		// Close open tooltips
		$.each( this.tooltips, function( id, tooltipData ) {
			var event = $.Event( "blur" );
			event.target = event.currentTarget = tooltipData.element[ 0 ];
			that.close( event, true );
		} );

		// Remove title attributes to prevent native tooltips
		this.disabledTitles = this.disabledTitles.add(
			this.element.find( this.options.items ).addBack()
				.filter( function() {
					var element = $( this );
					if ( element.is( "[title]" ) ) {
						return element
							.data( "ui-tooltip-title", element.attr( "title" ) )
							.removeAttr( "title" );
					}
				} )
		);
	},

	_enable: function() {

		// restore title attributes
		this.disabledTitles.each( function() {
			var element = $( this );
			if ( element.data( "ui-tooltip-title" ) ) {
				element.attr( "title", element.data( "ui-tooltip-title" ) );
			}
		} );
		this.disabledTitles = $( [] );
	},

	open: function( event ) {
		var that = this,
			target = $( event ? event.target : this.element )

				// we need closest here due to mouseover bubbling,
				// but always pointing at the same event target
				.closest( this.options.items );

		// No element to show a tooltip for or the tooltip is already open
		if ( !target.length || target.data( "ui-tooltip-id" ) ) {
			return;
		}

		if ( target.attr( "title" ) ) {
			target.data( "ui-tooltip-title", target.attr( "title" ) );
		}

		target.data( "ui-tooltip-open", true );

		// Kill parent tooltips, custom or native, for hover
		if ( event && event.type === "mouseover" ) {
			target.parents().each( function() {
				var parent = $( this ),
					blurEvent;
				if ( parent.data( "ui-tooltip-open" ) ) {
					blurEvent = $.Event( "blur" );
					blurEvent.target = blurEvent.currentTarget = this;
					that.close( blurEvent, true );
				}
				if ( parent.attr( "title" ) ) {
					parent.uniqueId();
					that.parents[ this.id ] = {
						element: this,
						title: parent.attr( "title" )
					};
					parent.attr( "title", "" );
				}
			} );
		}

		this._registerCloseHandlers( event, target );
		this._updateContent( target, event );
	},

	_updateContent: function( target, event ) {
		var content,
			contentOption = this.options.content,
			that = this,
			eventType = event ? event.type : null;

		if ( typeof contentOption === "string" || contentOption.nodeType ||
				contentOption.jquery ) {
			return this._open( event, target, contentOption );
		}

		content = contentOption.call( target[ 0 ], function( response ) {

			// IE may instantly serve a cached response for ajax requests
			// delay this call to _open so the other call to _open runs first
			that._delay( function() {

				// Ignore async response if tooltip was closed already
				if ( !target.data( "ui-tooltip-open" ) ) {
					return;
				}

				// JQuery creates a special event for focusin when it doesn't
				// exist natively. To improve performance, the native event
				// object is reused and the type is changed. Therefore, we can't
				// rely on the type being correct after the event finished
				// bubbling, so we set it back to the previous value. (#8740)
				if ( event ) {
					event.type = eventType;
				}
				this._open( event, target, response );
			} );
		} );
		if ( content ) {
			this._open( event, target, content );
		}
	},

	_open: function( event, target, content ) {
		var tooltipData, tooltip, delayedShow, a11yContent,
			positionOption = $.extend( {}, this.options.position );

		if ( !content ) {
			return;
		}

		// Content can be updated multiple times. If the tooltip already
		// exists, then just update the content and bail.
		tooltipData = this._find( target );
		if ( tooltipData ) {
			tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
			return;
		}

		// If we have a title, clear it to prevent the native tooltip
		// we have to check first to avoid defining a title if none exists
		// (we don't want to cause an element to start matching [title])
		//
		// We use removeAttr only for key events, to allow IE to export the correct
		// accessible attributes. For mouse events, set to empty string to avoid
		// native tooltip showing up (happens only when removing inside mouseover).
		if ( target.is( "[title]" ) ) {
			if ( event && event.type === "mouseover" ) {
				target.attr( "title", "" );
			} else {
				target.removeAttr( "title" );
			}
		}

		tooltipData = this._tooltip( target );
		tooltip = tooltipData.tooltip;
		this._addDescribedBy( target, tooltip.attr( "id" ) );
		tooltip.find( ".ui-tooltip-content" ).html( content );

		// Support: Voiceover on OS X, JAWS on IE <= 9
		// JAWS announces deletions even when aria-relevant="additions"
		// Voiceover will sometimes re-read the entire log region's contents from the beginning
		this.liveRegion.children().hide();
		a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
		a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
		a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
		a11yContent.appendTo( this.liveRegion );

		function position( event ) {
			positionOption.of = event;
			if ( tooltip.is( ":hidden" ) ) {
				return;
			}
			tooltip.position( positionOption );
		}
		if ( this.options.track && event && /^mouse/.test( event.type ) ) {
			this._on( this.document, {
				mousemove: position
			} );

			// trigger once to override element-relative positioning
			position( event );
		} else {
			tooltip.position( $.extend( {
				of: target
			}, this.options.position ) );
		}

		tooltip.hide();

		this._show( tooltip, this.options.show );

		// Handle tracking tooltips that are shown with a delay (#8644). As soon
		// as the tooltip is visible, position the tooltip using the most recent
		// event.
		// Adds the check to add the timers only when both delay and track options are set (#14682)
		if ( this.options.track && this.options.show && this.options.show.delay ) {
			delayedShow = this.delayedShow = setInterval( function() {
				if ( tooltip.is( ":visible" ) ) {
					position( positionOption.of );
					clearInterval( delayedShow );
				}
			}, $.fx.interval );
		}

		this._trigger( "open", event, { tooltip: tooltip } );
	},

	_registerCloseHandlers: function( event, target ) {
		var events = {
			keyup: function( event ) {
				if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
					var fakeEvent = $.Event( event );
					fakeEvent.currentTarget = target[ 0 ];
					this.close( fakeEvent, true );
				}
			}
		};

		// Only bind remove handler for delegated targets. Non-delegated
		// tooltips will handle this in destroy.
		if ( target[ 0 ] !== this.element[ 0 ] ) {
			events.remove = function() {
				this._removeTooltip( this._find( target ).tooltip );
			};
		}

		if ( !event || event.type === "mouseover" ) {
			events.mouseleave = "close";
		}
		if ( !event || event.type === "focusin" ) {
			events.focusout = "close";
		}
		this._on( true, target, events );
	},

	close: function( event ) {
		var tooltip,
			that = this,
			target = $( event ? event.currentTarget : this.element ),
			tooltipData = this._find( target );

		// The tooltip may already be closed
		if ( !tooltipData ) {

			// We set ui-tooltip-open immediately upon open (in open()), but only set the
			// additional data once there's actually content to show (in _open()). So even if the
			// tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
			// the period between open() and _open().
			target.removeData( "ui-tooltip-open" );
			return;
		}

		tooltip = tooltipData.tooltip;

		// Disabling closes the tooltip, so we need to track when we're closing
		// to avoid an infinite loop in case the tooltip becomes disabled on close
		if ( tooltipData.closing ) {
			return;
		}

		// Clear the interval for delayed tracking tooltips
		clearInterval( this.delayedShow );

		// Only set title if we had one before (see comment in _open())
		// If the title attribute has changed since open(), don't restore
		if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
			target.attr( "title", target.data( "ui-tooltip-title" ) );
		}

		this._removeDescribedBy( target );

		tooltipData.hiding = true;
		tooltip.stop( true );
		this._hide( tooltip, this.options.hide, function() {
			that._removeTooltip( $( this ) );
		} );

		target.removeData( "ui-tooltip-open" );
		this._off( target, "mouseleave focusout keyup" );

		// Remove 'remove' binding only on delegated targets
		if ( target[ 0 ] !== this.element[ 0 ] ) {
			this._off( target, "remove" );
		}
		this._off( this.document, "mousemove" );

		if ( event && event.type === "mouseleave" ) {
			$.each( this.parents, function( id, parent ) {
				$( parent.element ).attr( "title", parent.title );
				delete that.parents[ id ];
			} );
		}

		tooltipData.closing = true;
		this._trigger( "close", event, { tooltip: tooltip } );
		if ( !tooltipData.hiding ) {
			tooltipData.closing = false;
		}
	},

	_tooltip: function( element ) {
		var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
			content = $( "<div>" ).appendTo( tooltip ),
			id = tooltip.uniqueId().attr( "id" );

		this._addClass( content, "ui-tooltip-content" );
		this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );

		tooltip.appendTo( this._appendTo( element ) );

		return this.tooltips[ id ] = {
			element: element,
			tooltip: tooltip
		};
	},

	_find: function( target ) {
		var id = target.data( "ui-tooltip-id" );
		return id ? this.tooltips[ id ] : null;
	},

	_removeTooltip: function( tooltip ) {
		tooltip.remove();
		delete this.tooltips[ tooltip.attr( "id" ) ];
	},

	_appendTo: function( target ) {
		var element = target.closest( ".ui-front, dialog" );

		if ( !element.length ) {
			element = this.document[ 0 ].body;
		}

		return element;
	},

	_destroy: function() {
		var that = this;

		// Close open tooltips
		$.each( this.tooltips, function( id, tooltipData ) {

			// Delegate to close method to handle common cleanup
			var event = $.Event( "blur" ),
				element = tooltipData.element;
			event.target = event.currentTarget = element[ 0 ];
			that.close( event, true );

			// Remove immediately; destroying an open tooltip doesn't use the
			// hide animation
			$( "#" + id ).remove();

			// Restore the title
			if ( element.data( "ui-tooltip-title" ) ) {

				// If the title attribute has changed since open(), don't restore
				if ( !element.attr( "title" ) ) {
					element.attr( "title", element.data( "ui-tooltip-title" ) );
				}
				element.removeData( "ui-tooltip-title" );
			}
		} );
		this.liveRegion.remove();
	}
} );

// DEPRECATED
// TODO: Switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for tooltipClass option
	$.widget( "ui.tooltip", $.ui.tooltip, {
		options: {
			tooltipClass: null
		},
		_tooltip: function() {
			var tooltipData = this._superApply( arguments );
			if ( this.options.tooltipClass ) {
				tooltipData.tooltip.addClass( this.options.tooltipClass );
			}
			return tooltipData;
		}
	} );
}

var widgetsTooltip = $.ui.tooltip;




}));;/** 
 * Kendo UI v2017.2.504 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2017 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.core', ['jquery'], f);
}(function () {
    var __meta__ = {
        id: 'core',
        name: 'Core',
        category: 'framework',
        description: 'The core of the Kendo framework.'
    };
    (function ($, window, undefined) {
        var kendo = window.kendo = window.kendo || { cultures: {} }, extend = $.extend, each = $.each, isArray = $.isArray, proxy = $.proxy, noop = $.noop, math = Math, Template, JSON = window.JSON || {}, support = {}, percentRegExp = /%/, formatRegExp = /\{(\d+)(:[^\}]+)?\}/g, boxShadowRegExp = /(\d+(?:\.?)\d*)px\s*(\d+(?:\.?)\d*)px\s*(\d+(?:\.?)\d*)px\s*(\d+)?/i, numberRegExp = /^(\+|-?)\d+(\.?)\d*$/, FUNCTION = 'function', STRING = 'string', NUMBER = 'number', OBJECT = 'object', NULL = 'null', BOOLEAN = 'boolean', UNDEFINED = 'undefined', getterCache = {}, setterCache = {}, slice = [].slice;
        kendo.version = '2017.2.504'.replace(/^\s+|\s+$/g, '');
        function Class() {
        }
        Class.extend = function (proto) {
            var base = function () {
                }, member, that = this, subclass = proto && proto.init ? proto.init : function () {
                    that.apply(this, arguments);
                }, fn;
            base.prototype = that.prototype;
            fn = subclass.fn = subclass.prototype = new base();
            for (member in proto) {
                if (proto[member] != null && proto[member].constructor === Object) {
                    fn[member] = extend(true, {}, base.prototype[member], proto[member]);
                } else {
                    fn[member] = proto[member];
                }
            }
            fn.constructor = subclass;
            subclass.extend = that.extend;
            return subclass;
        };
        Class.prototype._initOptions = function (options) {
            this.options = deepExtend({}, this.options, options);
        };
        var isFunction = kendo.isFunction = function (fn) {
            return typeof fn === 'function';
        };
        var preventDefault = function () {
            this._defaultPrevented = true;
        };
        var isDefaultPrevented = function () {
            return this._defaultPrevented === true;
        };
        var Observable = Class.extend({
            init: function () {
                this._events = {};
            },
            bind: function (eventName, handlers, one) {
                var that = this, idx, eventNames = typeof eventName === STRING ? [eventName] : eventName, length, original, handler, handlersIsFunction = typeof handlers === FUNCTION, events;
                if (handlers === undefined) {
                    for (idx in eventName) {
                        that.bind(idx, eventName[idx]);
                    }
                    return that;
                }
                for (idx = 0, length = eventNames.length; idx < length; idx++) {
                    eventName = eventNames[idx];
                    handler = handlersIsFunction ? handlers : handlers[eventName];
                    if (handler) {
                        if (one) {
                            original = handler;
                            handler = function () {
                                that.unbind(eventName, handler);
                                original.apply(that, arguments);
                            };
                            handler.original = original;
                        }
                        events = that._events[eventName] = that._events[eventName] || [];
                        events.push(handler);
                    }
                }
                return that;
            },
            one: function (eventNames, handlers) {
                return this.bind(eventNames, handlers, true);
            },
            first: function (eventName, handlers) {
                var that = this, idx, eventNames = typeof eventName === STRING ? [eventName] : eventName, length, handler, handlersIsFunction = typeof handlers === FUNCTION, events;
                for (idx = 0, length = eventNames.length; idx < length; idx++) {
                    eventName = eventNames[idx];
                    handler = handlersIsFunction ? handlers : handlers[eventName];
                    if (handler) {
                        events = that._events[eventName] = that._events[eventName] || [];
                        events.unshift(handler);
                    }
                }
                return that;
            },
            trigger: function (eventName, e) {
                var that = this, events = that._events[eventName], idx, length;
                if (events) {
                    e = e || {};
                    e.sender = that;
                    e._defaultPrevented = false;
                    e.preventDefault = preventDefault;
                    e.isDefaultPrevented = isDefaultPrevented;
                    events = events.slice();
                    for (idx = 0, length = events.length; idx < length; idx++) {
                        events[idx].call(that, e);
                    }
                    return e._defaultPrevented === true;
                }
                return false;
            },
            unbind: function (eventName, handler) {
                var that = this, events = that._events[eventName], idx;
                if (eventName === undefined) {
                    that._events = {};
                } else if (events) {
                    if (handler) {
                        for (idx = events.length - 1; idx >= 0; idx--) {
                            if (events[idx] === handler || events[idx].original === handler) {
                                events.splice(idx, 1);
                            }
                        }
                    } else {
                        that._events[eventName] = [];
                    }
                }
                return that;
            }
        });
        function compilePart(part, stringPart) {
            if (stringPart) {
                return '\'' + part.split('\'').join('\\\'').split('\\"').join('\\\\\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t') + '\'';
            } else {
                var first = part.charAt(0), rest = part.substring(1);
                if (first === '=') {
                    return '+(' + rest + ')+';
                } else if (first === ':') {
                    return '+$kendoHtmlEncode(' + rest + ')+';
                } else {
                    return ';' + part + ';$kendoOutput+=';
                }
            }
        }
        var argumentNameRegExp = /^\w+/, encodeRegExp = /\$\{([^}]*)\}/g, escapedCurlyRegExp = /\\\}/g, curlyRegExp = /__CURLY__/g, escapedSharpRegExp = /\\#/g, sharpRegExp = /__SHARP__/g, zeros = [
                '',
                '0',
                '00',
                '000',
                '0000'
            ];
        Template = {
            paramName: 'data',
            useWithBlock: true,
            render: function (template, data) {
                var idx, length, html = '';
                for (idx = 0, length = data.length; idx < length; idx++) {
                    html += template(data[idx]);
                }
                return html;
            },
            compile: function (template, options) {
                var settings = extend({}, this, options), paramName = settings.paramName, argumentName = paramName.match(argumentNameRegExp)[0], useWithBlock = settings.useWithBlock, functionBody = 'var $kendoOutput, $kendoHtmlEncode = kendo.htmlEncode;', fn, parts, idx;
                if (isFunction(template)) {
                    return template;
                }
                functionBody += useWithBlock ? 'with(' + paramName + '){' : '';
                functionBody += '$kendoOutput=';
                parts = template.replace(escapedCurlyRegExp, '__CURLY__').replace(encodeRegExp, '#=$kendoHtmlEncode($1)#').replace(curlyRegExp, '}').replace(escapedSharpRegExp, '__SHARP__').split('#');
                for (idx = 0; idx < parts.length; idx++) {
                    functionBody += compilePart(parts[idx], idx % 2 === 0);
                }
                functionBody += useWithBlock ? ';}' : ';';
                functionBody += 'return $kendoOutput;';
                functionBody = functionBody.replace(sharpRegExp, '#');
                try {
                    fn = new Function(argumentName, functionBody);
                    fn._slotCount = Math.floor(parts.length / 2);
                    return fn;
                } catch (e) {
                    throw new Error(kendo.format('Invalid template:\'{0}\' Generated code:\'{1}\'', template, functionBody));
                }
            }
        };
        function pad(number, digits, end) {
            number = number + '';
            digits = digits || 2;
            end = digits - number.length;
            if (end) {
                return zeros[digits].substring(0, end) + number;
            }
            return number;
        }
        (function () {
            var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = {
                    '\b': '\\b',
                    '\t': '\\t',
                    '\n': '\\n',
                    '\f': '\\f',
                    '\r': '\\r',
                    '"': '\\"',
                    '\\': '\\\\'
                }, rep, toString = {}.toString;
            if (typeof Date.prototype.toJSON !== FUNCTION) {
                Date.prototype.toJSON = function () {
                    var that = this;
                    return isFinite(that.valueOf()) ? pad(that.getUTCFullYear(), 4) + '-' + pad(that.getUTCMonth() + 1) + '-' + pad(that.getUTCDate()) + 'T' + pad(that.getUTCHours()) + ':' + pad(that.getUTCMinutes()) + ':' + pad(that.getUTCSeconds()) + 'Z' : null;
                };
                String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function () {
                    return this.valueOf();
                };
            }
            function quote(string) {
                escapable.lastIndex = 0;
                return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
                    var c = meta[a];
                    return typeof c === STRING ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                }) + '"' : '"' + string + '"';
            }
            function str(key, holder) {
                var i, k, v, length, mind = gap, partial, value = holder[key], type;
                if (value && typeof value === OBJECT && typeof value.toJSON === FUNCTION) {
                    value = value.toJSON(key);
                }
                if (typeof rep === FUNCTION) {
                    value = rep.call(holder, key, value);
                }
                type = typeof value;
                if (type === STRING) {
                    return quote(value);
                } else if (type === NUMBER) {
                    return isFinite(value) ? String(value) : NULL;
                } else if (type === BOOLEAN || type === NULL) {
                    return String(value);
                } else if (type === OBJECT) {
                    if (!value) {
                        return NULL;
                    }
                    gap += indent;
                    partial = [];
                    if (toString.apply(value) === '[object Array]') {
                        length = value.length;
                        for (i = 0; i < length; i++) {
                            partial[i] = str(i, value) || NULL;
                        }
                        v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']';
                        gap = mind;
                        return v;
                    }
                    if (rep && typeof rep === OBJECT) {
                        length = rep.length;
                        for (i = 0; i < length; i++) {
                            if (typeof rep[i] === STRING) {
                                k = rep[i];
                                v = str(k, value);
                                if (v) {
                                    partial.push(quote(k) + (gap ? ': ' : ':') + v);
                                }
                            }
                        }
                    } else {
                        for (k in value) {
                            if (Object.hasOwnProperty.call(value, k)) {
                                v = str(k, value);
                                if (v) {
                                    partial.push(quote(k) + (gap ? ': ' : ':') + v);
                                }
                            }
                        }
                    }
                    v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}';
                    gap = mind;
                    return v;
                }
            }
            if (typeof JSON.stringify !== FUNCTION) {
                JSON.stringify = function (value, replacer, space) {
                    var i;
                    gap = '';
                    indent = '';
                    if (typeof space === NUMBER) {
                        for (i = 0; i < space; i += 1) {
                            indent += ' ';
                        }
                    } else if (typeof space === STRING) {
                        indent = space;
                    }
                    rep = replacer;
                    if (replacer && typeof replacer !== FUNCTION && (typeof replacer !== OBJECT || typeof replacer.length !== NUMBER)) {
                        throw new Error('JSON.stringify');
                    }
                    return str('', { '': value });
                };
            }
        }());
        (function () {
            var dateFormatRegExp = /dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|HH|H|hh|h|mm|m|fff|ff|f|tt|ss|s|zzz|zz|z|"[^"]*"|'[^']*'/g, standardFormatRegExp = /^(n|c|p|e)(\d*)$/i, literalRegExp = /(\\.)|(['][^']*[']?)|(["][^"]*["]?)/g, commaRegExp = /\,/g, EMPTY = '', POINT = '.', COMMA = ',', SHARP = '#', ZERO = '0', PLACEHOLDER = '??', EN = 'en-US', objectToString = {}.toString;
            kendo.cultures['en-US'] = {
                name: EN,
                numberFormat: {
                    pattern: ['-n'],
                    decimals: 2,
                    ',': ',',
                    '.': '.',
                    groupSize: [3],
                    percent: {
                        pattern: [
                            '-n %',
                            'n %'
                        ],
                        decimals: 2,
                        ',': ',',
                        '.': '.',
                        groupSize: [3],
                        symbol: '%'
                    },
                    currency: {
                        name: 'US Dollar',
                        abbr: 'USD',
                        pattern: [
                            '($n)',
                            '$n'
                        ],
                        decimals: 2,
                        ',': ',',
                        '.': '.',
                        groupSize: [3],
                        symbol: '$'
                    }
                },
                calendars: {
                    standard: {
                        days: {
                            names: [
                                'Sunday',
                                'Monday',
                                'Tuesday',
                                'Wednesday',
                                'Thursday',
                                'Friday',
                                'Saturday'
                            ],
                            namesAbbr: [
                                'Sun',
                                'Mon',
                                'Tue',
                                'Wed',
                                'Thu',
                                'Fri',
                                'Sat'
                            ],
                            namesShort: [
                                'Su',
                                'Mo',
                                'Tu',
                                'We',
                                'Th',
                                'Fr',
                                'Sa'
                            ]
                        },
                        months: {
                            names: [
                                'January',
                                'February',
                                'March',
                                'April',
                                'May',
                                'June',
                                'July',
                                'August',
                                'September',
                                'October',
                                'November',
                                'December'
                            ],
                            namesAbbr: [
                                'Jan',
                                'Feb',
                                'Mar',
                                'Apr',
                                'May',
                                'Jun',
                                'Jul',
                                'Aug',
                                'Sep',
                                'Oct',
                                'Nov',
                                'Dec'
                            ]
                        },
                        AM: [
                            'AM',
                            'am',
                            'AM'
                        ],
                        PM: [
                            'PM',
                            'pm',
                            'PM'
                        ],
                        patterns: {
                            d: 'M/d/yyyy',
                            D: 'dddd, MMMM dd, yyyy',
                            F: 'dddd, MMMM dd, yyyy h:mm:ss tt',
                            g: 'M/d/yyyy h:mm tt',
                            G: 'M/d/yyyy h:mm:ss tt',
                            m: 'MMMM dd',
                            M: 'MMMM dd',
                            s: 'yyyy\'-\'MM\'-\'ddTHH\':\'mm\':\'ss',
                            t: 'h:mm tt',
                            T: 'h:mm:ss tt',
                            u: 'yyyy\'-\'MM\'-\'dd HH\':\'mm\':\'ss\'Z\'',
                            y: 'MMMM, yyyy',
                            Y: 'MMMM, yyyy'
                        },
                        '/': '/',
                        ':': ':',
                        firstDay: 0,
                        twoDigitYearMax: 2029
                    }
                }
            };
            function findCulture(culture) {
                if (culture) {
                    if (culture.numberFormat) {
                        return culture;
                    }
                    if (typeof culture === STRING) {
                        var cultures = kendo.cultures;
                        return cultures[culture] || cultures[culture.split('-')[0]] || null;
                    }
                    return null;
                }
                return null;
            }
            function getCulture(culture) {
                if (culture) {
                    culture = findCulture(culture);
                }
                return culture || kendo.cultures.current;
            }
            kendo.culture = function (cultureName) {
                var cultures = kendo.cultures, culture;
                if (cultureName !== undefined) {
                    culture = findCulture(cultureName) || cultures[EN];
                    culture.calendar = culture.calendars.standard;
                    cultures.current = culture;
                } else {
                    return cultures.current;
                }
            };
            kendo.findCulture = findCulture;
            kendo.getCulture = getCulture;
            kendo.culture(EN);
            function formatDate(date, format, culture) {
                culture = getCulture(culture);
                var calendar = culture.calendars.standard, days = calendar.days, months = calendar.months;
                format = calendar.patterns[format] || format;
                return format.replace(dateFormatRegExp, function (match) {
                    var minutes;
                    var result;
                    var sign;
                    if (match === 'd') {
                        result = date.getDate();
                    } else if (match === 'dd') {
                        result = pad(date.getDate());
                    } else if (match === 'ddd') {
                        result = days.namesAbbr[date.getDay()];
                    } else if (match === 'dddd') {
                        result = days.names[date.getDay()];
                    } else if (match === 'M') {
                        result = date.getMonth() + 1;
                    } else if (match === 'MM') {
                        result = pad(date.getMonth() + 1);
                    } else if (match === 'MMM') {
                        result = months.namesAbbr[date.getMonth()];
                    } else if (match === 'MMMM') {
                        result = months.names[date.getMonth()];
                    } else if (match === 'yy') {
                        result = pad(date.getFullYear() % 100);
                    } else if (match === 'yyyy') {
                        result = pad(date.getFullYear(), 4);
                    } else if (match === 'h') {
                        result = date.getHours() % 12 || 12;
                    } else if (match === 'hh') {
                        result = pad(date.getHours() % 12 || 12);
                    } else if (match === 'H') {
                        result = date.getHours();
                    } else if (match === 'HH') {
                        result = pad(date.getHours());
                    } else if (match === 'm') {
                        result = date.getMinutes();
                    } else if (match === 'mm') {
                        result = pad(date.getMinutes());
                    } else if (match === 's') {
                        result = date.getSeconds();
                    } else if (match === 'ss') {
                        result = pad(date.getSeconds());
                    } else if (match === 'f') {
                        result = math.floor(date.getMilliseconds() / 100);
                    } else if (match === 'ff') {
                        result = date.getMilliseconds();
                        if (result > 99) {
                            result = math.floor(result / 10);
                        }
                        result = pad(result);
                    } else if (match === 'fff') {
                        result = pad(date.getMilliseconds(), 3);
                    } else if (match === 'tt') {
                        result = date.getHours() < 12 ? calendar.AM[0] : calendar.PM[0];
                    } else if (match === 'zzz') {
                        minutes = date.getTimezoneOffset();
                        sign = minutes < 0;
                        result = math.abs(minutes / 60).toString().split('.')[0];
                        minutes = math.abs(minutes) - result * 60;
                        result = (sign ? '+' : '-') + pad(result);
                        result += ':' + pad(minutes);
                    } else if (match === 'zz' || match === 'z') {
                        result = date.getTimezoneOffset() / 60;
                        sign = result < 0;
                        result = math.abs(result).toString().split('.')[0];
                        result = (sign ? '+' : '-') + (match === 'zz' ? pad(result) : result);
                    }
                    return result !== undefined ? result : match.slice(1, match.length - 1);
                });
            }
            function formatNumber(number, format, culture) {
                culture = getCulture(culture);
                var numberFormat = culture.numberFormat, decimal = numberFormat[POINT], precision = numberFormat.decimals, pattern = numberFormat.pattern[0], literals = [], symbol, isCurrency, isPercent, customPrecision, formatAndPrecision, negative = number < 0, integer, fraction, integerLength, fractionLength, replacement = EMPTY, value = EMPTY, idx, length, ch, hasGroup, hasNegativeFormat, decimalIndex, sharpIndex, zeroIndex, hasZero, hasSharp, percentIndex, currencyIndex, startZeroIndex, start = -1, end;
                if (number === undefined) {
                    return EMPTY;
                }
                if (!isFinite(number)) {
                    return number;
                }
                if (!format) {
                    return culture.name.length ? number.toLocaleString() : number.toString();
                }
                formatAndPrecision = standardFormatRegExp.exec(format);
                if (formatAndPrecision) {
                    format = formatAndPrecision[1].toLowerCase();
                    isCurrency = format === 'c';
                    isPercent = format === 'p';
                    if (isCurrency || isPercent) {
                        numberFormat = isCurrency ? numberFormat.currency : numberFormat.percent;
                        decimal = numberFormat[POINT];
                        precision = numberFormat.decimals;
                        symbol = numberFormat.symbol;
                        pattern = numberFormat.pattern[negative ? 0 : 1];
                    }
                    customPrecision = formatAndPrecision[2];
                    if (customPrecision) {
                        precision = +customPrecision;
                    }
                    if (format === 'e') {
                        return customPrecision ? number.toExponential(precision) : number.toExponential();
                    }
                    if (isPercent) {
                        number *= 100;
                    }
                    number = round(number, precision);
                    negative = number < 0;
                    number = number.split(POINT);
                    integer = number[0];
                    fraction = number[1];
                    if (negative) {
                        integer = integer.substring(1);
                    }
                    value = groupInteger(integer, 0, integer.length, numberFormat);
                    if (fraction) {
                        value += decimal + fraction;
                    }
                    if (format === 'n' && !negative) {
                        return value;
                    }
                    number = EMPTY;
                    for (idx = 0, length = pattern.length; idx < length; idx++) {
                        ch = pattern.charAt(idx);
                        if (ch === 'n') {
                            number += value;
                        } else if (ch === '$' || ch === '%') {
                            number += symbol;
                        } else {
                            number += ch;
                        }
                    }
                    return number;
                }
                if (negative) {
                    number = -number;
                }
                if (format.indexOf('\'') > -1 || format.indexOf('"') > -1 || format.indexOf('\\') > -1) {
                    format = format.replace(literalRegExp, function (match) {
                        var quoteChar = match.charAt(0).replace('\\', ''), literal = match.slice(1).replace(quoteChar, '');
                        literals.push(literal);
                        return PLACEHOLDER;
                    });
                }
                format = format.split(';');
                if (negative && format[1]) {
                    format = format[1];
                    hasNegativeFormat = true;
                } else if (number === 0) {
                    format = format[2] || format[0];
                    if (format.indexOf(SHARP) == -1 && format.indexOf(ZERO) == -1) {
                        return format;
                    }
                } else {
                    format = format[0];
                }
                percentIndex = format.indexOf('%');
                currencyIndex = format.indexOf('$');
                isPercent = percentIndex != -1;
                isCurrency = currencyIndex != -1;
                if (isPercent) {
                    number *= 100;
                }
                if (isCurrency && format[currencyIndex - 1] === '\\') {
                    format = format.split('\\').join('');
                    isCurrency = false;
                }
                if (isCurrency || isPercent) {
                    numberFormat = isCurrency ? numberFormat.currency : numberFormat.percent;
                    decimal = numberFormat[POINT];
                    precision = numberFormat.decimals;
                    symbol = numberFormat.symbol;
                }
                hasGroup = format.indexOf(COMMA) > -1;
                if (hasGroup) {
                    format = format.replace(commaRegExp, EMPTY);
                }
                decimalIndex = format.indexOf(POINT);
                length = format.length;
                if (decimalIndex != -1) {
                    fraction = number.toString().split('e');
                    if (fraction[1]) {
                        fraction = round(number, Math.abs(fraction[1]));
                    } else {
                        fraction = fraction[0];
                    }
                    fraction = fraction.split(POINT)[1] || EMPTY;
                    zeroIndex = format.lastIndexOf(ZERO) - decimalIndex;
                    sharpIndex = format.lastIndexOf(SHARP) - decimalIndex;
                    hasZero = zeroIndex > -1;
                    hasSharp = sharpIndex > -1;
                    idx = fraction.length;
                    if (!hasZero && !hasSharp) {
                        format = format.substring(0, decimalIndex) + format.substring(decimalIndex + 1);
                        length = format.length;
                        decimalIndex = -1;
                        idx = 0;
                    }
                    if (hasZero && zeroIndex > sharpIndex) {
                        idx = zeroIndex;
                    } else if (sharpIndex > zeroIndex) {
                        if (hasSharp && idx > sharpIndex) {
                            idx = sharpIndex;
                        } else if (hasZero && idx < zeroIndex) {
                            idx = zeroIndex;
                        }
                    }
                    if (idx > -1) {
                        number = round(number, idx);
                    }
                } else {
                    number = round(number);
                }
                sharpIndex = format.indexOf(SHARP);
                startZeroIndex = zeroIndex = format.indexOf(ZERO);
                if (sharpIndex == -1 && zeroIndex != -1) {
                    start = zeroIndex;
                } else if (sharpIndex != -1 && zeroIndex == -1) {
                    start = sharpIndex;
                } else {
                    start = sharpIndex > zeroIndex ? zeroIndex : sharpIndex;
                }
                sharpIndex = format.lastIndexOf(SHARP);
                zeroIndex = format.lastIndexOf(ZERO);
                if (sharpIndex == -1 && zeroIndex != -1) {
                    end = zeroIndex;
                } else if (sharpIndex != -1 && zeroIndex == -1) {
                    end = sharpIndex;
                } else {
                    end = sharpIndex > zeroIndex ? sharpIndex : zeroIndex;
                }
                if (start == length) {
                    end = start;
                }
                if (start != -1) {
                    value = number.toString().split(POINT);
                    integer = value[0];
                    fraction = value[1] || EMPTY;
                    integerLength = integer.length;
                    fractionLength = fraction.length;
                    if (negative && number * -1 >= 0) {
                        negative = false;
                    }
                    number = format.substring(0, start);
                    if (negative && !hasNegativeFormat) {
                        number += '-';
                    }
                    for (idx = start; idx < length; idx++) {
                        ch = format.charAt(idx);
                        if (decimalIndex == -1) {
                            if (end - idx < integerLength) {
                                number += integer;
                                break;
                            }
                        } else {
                            if (zeroIndex != -1 && zeroIndex < idx) {
                                replacement = EMPTY;
                            }
                            if (decimalIndex - idx <= integerLength && decimalIndex - idx > -1) {
                                number += integer;
                                idx = decimalIndex;
                            }
                            if (decimalIndex === idx) {
                                number += (fraction ? decimal : EMPTY) + fraction;
                                idx += end - decimalIndex + 1;
                                continue;
                            }
                        }
                        if (ch === ZERO) {
                            number += ch;
                            replacement = ch;
                        } else if (ch === SHARP) {
                            number += replacement;
                        }
                    }
                    if (hasGroup) {
                        number = groupInteger(number, start + (negative && !hasNegativeFormat ? 1 : 0), Math.max(end, integerLength + start), numberFormat);
                    }
                    if (end >= start) {
                        number += format.substring(end + 1);
                    }
                    if (isCurrency || isPercent) {
                        value = EMPTY;
                        for (idx = 0, length = number.length; idx < length; idx++) {
                            ch = number.charAt(idx);
                            value += ch === '$' || ch === '%' ? symbol : ch;
                        }
                        number = value;
                    }
                    length = literals.length;
                    if (length) {
                        for (idx = 0; idx < length; idx++) {
                            number = number.replace(PLACEHOLDER, literals[idx]);
                        }
                    }
                }
                return number;
            }
            var groupInteger = function (number, start, end, numberFormat) {
                var decimalIndex = number.indexOf(numberFormat[POINT]);
                var groupSizes = numberFormat.groupSize.slice();
                var groupSize = groupSizes.shift();
                var integer, integerLength;
                var idx, parts, value;
                var newGroupSize;
                end = decimalIndex !== -1 ? decimalIndex : end + 1;
                integer = number.substring(start, end);
                integerLength = integer.length;
                if (integerLength >= groupSize) {
                    idx = integerLength;
                    parts = [];
                    while (idx > -1) {
                        value = integer.substring(idx - groupSize, idx);
                        if (value) {
                            parts.push(value);
                        }
                        idx -= groupSize;
                        newGroupSize = groupSizes.shift();
                        groupSize = newGroupSize !== undefined ? newGroupSize : groupSize;
                        if (groupSize === 0) {
                            parts.push(integer.substring(0, idx));
                            break;
                        }
                    }
                    integer = parts.reverse().join(numberFormat[COMMA]);
                    number = number.substring(0, start) + integer + number.substring(end);
                }
                return number;
            };
            var round = function (value, precision) {
                precision = precision || 0;
                value = value.toString().split('e');
                value = Math.round(+(value[0] + 'e' + (value[1] ? +value[1] + precision : precision)));
                value = value.toString().split('e');
                value = +(value[0] + 'e' + (value[1] ? +value[1] - precision : -precision));
                return value.toFixed(Math.min(precision, 20));
            };
            var toString = function (value, fmt, culture) {
                if (fmt) {
                    if (objectToString.call(value) === '[object Date]') {
                        return formatDate(value, fmt, culture);
                    } else if (typeof value === NUMBER) {
                        return formatNumber(value, fmt, culture);
                    }
                }
                return value !== undefined ? value : '';
            };
            kendo.format = function (fmt) {
                var values = arguments;
                return fmt.replace(formatRegExp, function (match, index, placeholderFormat) {
                    var value = values[parseInt(index, 10) + 1];
                    return toString(value, placeholderFormat ? placeholderFormat.substring(1) : '');
                });
            };
            kendo._extractFormat = function (format) {
                if (format.slice(0, 3) === '{0:') {
                    format = format.slice(3, format.length - 1);
                }
                return format;
            };
            kendo._activeElement = function () {
                try {
                    return document.activeElement;
                } catch (e) {
                    return document.documentElement.activeElement;
                }
            };
            kendo._round = round;
            kendo._outerWidth = function (element, includeMargin) {
                return $(element).outerWidth(includeMargin || false) || 0;
            };
            kendo._outerHeight = function (element, includeMargin) {
                return $(element).outerHeight(includeMargin || false) || 0;
            };
            kendo.toString = toString;
        }());
        (function () {
            var nonBreakingSpaceRegExp = /\u00A0/g, exponentRegExp = /[eE][\-+]?[0-9]+/, shortTimeZoneRegExp = /[+|\-]\d{1,2}/, longTimeZoneRegExp = /[+|\-]\d{1,2}:?\d{2}/, dateRegExp = /^\/Date\((.*?)\)\/$/, offsetRegExp = /[+-]\d*/, FORMATS_SEQUENCE = [
                    [],
                    [
                        'G',
                        'g',
                        'F'
                    ],
                    [
                        'D',
                        'd',
                        'y',
                        'm',
                        'T',
                        't'
                    ]
                ], STANDARD_FORMATS = [
                    [
                        'yyyy-MM-ddTHH:mm:ss.fffffffzzz',
                        'yyyy-MM-ddTHH:mm:ss.fffffff',
                        'yyyy-MM-ddTHH:mm:ss.fffzzz',
                        'yyyy-MM-ddTHH:mm:ss.fff',
                        'ddd MMM dd yyyy HH:mm:ss',
                        'yyyy-MM-ddTHH:mm:sszzz',
                        'yyyy-MM-ddTHH:mmzzz',
                        'yyyy-MM-ddTHH:mmzz',
                        'yyyy-MM-ddTHH:mm:ss',
                        'yyyy-MM-dd HH:mm:ss',
                        'yyyy/MM/dd HH:mm:ss'
                    ],
                    [
                        'yyyy-MM-ddTHH:mm',
                        'yyyy-MM-dd HH:mm',
                        'yyyy/MM/dd HH:mm'
                    ],
                    [
                        'yyyy/MM/dd',
                        'yyyy-MM-dd',
                        'HH:mm:ss',
                        'HH:mm'
                    ]
                ], numberRegExp = {
                    2: /^\d{1,2}/,
                    3: /^\d{1,3}/,
                    4: /^\d{4}/
                }, objectToString = {}.toString;
            function outOfRange(value, start, end) {
                return !(value >= start && value <= end);
            }
            function designatorPredicate(designator) {
                return designator.charAt(0);
            }
            function mapDesignators(designators) {
                return $.map(designators, designatorPredicate);
            }
            function adjustDST(date, hours) {
                if (!hours && date.getHours() === 23) {
                    date.setHours(date.getHours() + 2);
                }
            }
            function lowerArray(data) {
                var idx = 0, length = data.length, array = [];
                for (; idx < length; idx++) {
                    array[idx] = (data[idx] + '').toLowerCase();
                }
                return array;
            }
            function lowerLocalInfo(localInfo) {
                var newLocalInfo = {}, property;
                for (property in localInfo) {
                    newLocalInfo[property] = lowerArray(localInfo[property]);
                }
                return newLocalInfo;
            }
            function parseExact(value, format, culture) {
                if (!value) {
                    return null;
                }
                var lookAhead = function (match) {
                        var i = 0;
                        while (format[idx] === match) {
                            i++;
                            idx++;
                        }
                        if (i > 0) {
                            idx -= 1;
                        }
                        return i;
                    }, getNumber = function (size) {
                        var rg = numberRegExp[size] || new RegExp('^\\d{1,' + size + '}'), match = value.substr(valueIdx, size).match(rg);
                        if (match) {
                            match = match[0];
                            valueIdx += match.length;
                            return parseInt(match, 10);
                        }
                        return null;
                    }, getIndexByName = function (names, lower) {
                        var i = 0, length = names.length, name, nameLength, matchLength = 0, matchIdx = 0, subValue;
                        for (; i < length; i++) {
                            name = names[i];
                            nameLength = name.length;
                            subValue = value.substr(valueIdx, nameLength);
                            if (lower) {
                                subValue = subValue.toLowerCase();
                            }
                            if (subValue == name && nameLength > matchLength) {
                                matchLength = nameLength;
                                matchIdx = i;
                            }
                        }
                        if (matchLength) {
                            valueIdx += matchLength;
                            return matchIdx + 1;
                        }
                        return null;
                    }, checkLiteral = function () {
                        var result = false;
                        if (value.charAt(valueIdx) === format[idx]) {
                            valueIdx++;
                            result = true;
                        }
                        return result;
                    }, calendar = culture.calendars.standard, year = null, month = null, day = null, hours = null, minutes = null, seconds = null, milliseconds = null, idx = 0, valueIdx = 0, literal = false, date = new Date(), twoDigitYearMax = calendar.twoDigitYearMax || 2029, defaultYear = date.getFullYear(), ch, count, length, pattern, pmHour, UTC, matches, amDesignators, pmDesignators, hoursOffset, minutesOffset, hasTime, match;
                if (!format) {
                    format = 'd';
                }
                pattern = calendar.patterns[format];
                if (pattern) {
                    format = pattern;
                }
                format = format.split('');
                length = format.length;
                for (; idx < length; idx++) {
                    ch = format[idx];
                    if (literal) {
                        if (ch === '\'') {
                            literal = false;
                        } else {
                            checkLiteral();
                        }
                    } else {
                        if (ch === 'd') {
                            count = lookAhead('d');
                            if (!calendar._lowerDays) {
                                calendar._lowerDays = lowerLocalInfo(calendar.days);
                            }
                            if (day !== null && count > 2) {
                                continue;
                            }
                            day = count < 3 ? getNumber(2) : getIndexByName(calendar._lowerDays[count == 3 ? 'namesAbbr' : 'names'], true);
                            if (day === null || outOfRange(day, 1, 31)) {
                                return null;
                            }
                        } else if (ch === 'M') {
                            count = lookAhead('M');
                            if (!calendar._lowerMonths) {
                                calendar._lowerMonths = lowerLocalInfo(calendar.months);
                            }
                            month = count < 3 ? getNumber(2) : getIndexByName(calendar._lowerMonths[count == 3 ? 'namesAbbr' : 'names'], true);
                            if (month === null || outOfRange(month, 1, 12)) {
                                return null;
                            }
                            month -= 1;
                        } else if (ch === 'y') {
                            count = lookAhead('y');
                            year = getNumber(count);
                            if (year === null) {
                                return null;
                            }
                            if (count == 2) {
                                if (typeof twoDigitYearMax === 'string') {
                                    twoDigitYearMax = defaultYear + parseInt(twoDigitYearMax, 10);
                                }
                                year = defaultYear - defaultYear % 100 + year;
                                if (year > twoDigitYearMax) {
                                    year -= 100;
                                }
                            }
                        } else if (ch === 'h') {
                            lookAhead('h');
                            hours = getNumber(2);
                            if (hours == 12) {
                                hours = 0;
                            }
                            if (hours === null || outOfRange(hours, 0, 11)) {
                                return null;
                            }
                        } else if (ch === 'H') {
                            lookAhead('H');
                            hours = getNumber(2);
                            if (hours === null || outOfRange(hours, 0, 23)) {
                                return null;
                            }
                        } else if (ch === 'm') {
                            lookAhead('m');
                            minutes = getNumber(2);
                            if (minutes === null || outOfRange(minutes, 0, 59)) {
                                return null;
                            }
                        } else if (ch === 's') {
                            lookAhead('s');
                            seconds = getNumber(2);
                            if (seconds === null || outOfRange(seconds, 0, 59)) {
                                return null;
                            }
                        } else if (ch === 'f') {
                            count = lookAhead('f');
                            match = value.substr(valueIdx, count).match(numberRegExp[3]);
                            milliseconds = getNumber(count);
                            if (milliseconds !== null) {
                                milliseconds = parseFloat('0.' + match[0], 10);
                                milliseconds = kendo._round(milliseconds, 3);
                                milliseconds *= 1000;
                            }
                            if (milliseconds === null || outOfRange(milliseconds, 0, 999)) {
                                return null;
                            }
                        } else if (ch === 't') {
                            count = lookAhead('t');
                            amDesignators = calendar.AM;
                            pmDesignators = calendar.PM;
                            if (count === 1) {
                                amDesignators = mapDesignators(amDesignators);
                                pmDesignators = mapDesignators(pmDesignators);
                            }
                            pmHour = getIndexByName(pmDesignators);
                            if (!pmHour && !getIndexByName(amDesignators)) {
                                return null;
                            }
                        } else if (ch === 'z') {
                            UTC = true;
                            count = lookAhead('z');
                            if (value.substr(valueIdx, 1) === 'Z') {
                                checkLiteral();
                                continue;
                            }
                            matches = value.substr(valueIdx, 6).match(count > 2 ? longTimeZoneRegExp : shortTimeZoneRegExp);
                            if (!matches) {
                                return null;
                            }
                            matches = matches[0].split(':');
                            hoursOffset = matches[0];
                            minutesOffset = matches[1];
                            if (!minutesOffset && hoursOffset.length > 3) {
                                valueIdx = hoursOffset.length - 2;
                                minutesOffset = hoursOffset.substring(valueIdx);
                                hoursOffset = hoursOffset.substring(0, valueIdx);
                            }
                            hoursOffset = parseInt(hoursOffset, 10);
                            if (outOfRange(hoursOffset, -12, 13)) {
                                return null;
                            }
                            if (count > 2) {
                                minutesOffset = parseInt(minutesOffset, 10);
                                if (isNaN(minutesOffset) || outOfRange(minutesOffset, 0, 59)) {
                                    return null;
                                }
                            }
                        } else if (ch === '\'') {
                            literal = true;
                            checkLiteral();
                        } else if (!checkLiteral()) {
                            return null;
                        }
                    }
                }
                hasTime = hours !== null || minutes !== null || seconds || null;
                if (year === null && month === null && day === null && hasTime) {
                    year = defaultYear;
                    month = date.getMonth();
                    day = date.getDate();
                } else {
                    if (year === null) {
                        year = defaultYear;
                    }
                    if (day === null) {
                        day = 1;
                    }
                }
                if (pmHour && hours < 12) {
                    hours += 12;
                }
                if (UTC) {
                    if (hoursOffset) {
                        hours += -hoursOffset;
                    }
                    if (minutesOffset) {
                        minutes += -minutesOffset;
                    }
                    value = new Date(Date.UTC(year, month, day, hours, minutes, seconds, milliseconds));
                } else {
                    value = new Date(year, month, day, hours, minutes, seconds, milliseconds);
                    adjustDST(value, hours);
                }
                if (year < 100) {
                    value.setFullYear(year);
                }
                if (value.getDate() !== day && UTC === undefined) {
                    return null;
                }
                return value;
            }
            function parseMicrosoftFormatOffset(offset) {
                var sign = offset.substr(0, 1) === '-' ? -1 : 1;
                offset = offset.substring(1);
                offset = parseInt(offset.substr(0, 2), 10) * 60 + parseInt(offset.substring(2), 10);
                return sign * offset;
            }
            function getDefaultFormats(culture) {
                var length = math.max(FORMATS_SEQUENCE.length, STANDARD_FORMATS.length);
                var patterns = culture.calendar.patterns;
                var cultureFormats, formatIdx, idx;
                var formats = [];
                for (idx = 0; idx < length; idx++) {
                    cultureFormats = FORMATS_SEQUENCE[idx];
                    for (formatIdx = 0; formatIdx < cultureFormats.length; formatIdx++) {
                        formats.push(patterns[cultureFormats[formatIdx]]);
                    }
                    formats = formats.concat(STANDARD_FORMATS[idx]);
                }
                return formats;
            }
            kendo.parseDate = function (value, formats, culture) {
                if (objectToString.call(value) === '[object Date]') {
                    return value;
                }
                var idx = 0;
                var date = null;
                var length;
                var tzoffset;
                if (value && value.indexOf('/D') === 0) {
                    date = dateRegExp.exec(value);
                    if (date) {
                        date = date[1];
                        tzoffset = offsetRegExp.exec(date.substring(1));
                        date = new Date(parseInt(date, 10));
                        if (tzoffset) {
                            tzoffset = parseMicrosoftFormatOffset(tzoffset[0]);
                            date = kendo.timezone.apply(date, 0);
                            date = kendo.timezone.convert(date, 0, -1 * tzoffset);
                        }
                        return date;
                    }
                }
                culture = kendo.getCulture(culture);
                if (!formats) {
                    formats = getDefaultFormats(culture);
                }
                formats = isArray(formats) ? formats : [formats];
                length = formats.length;
                for (; idx < length; idx++) {
                    date = parseExact(value, formats[idx], culture);
                    if (date) {
                        return date;
                    }
                }
                return date;
            };
            kendo.parseInt = function (value, culture) {
                var result = kendo.parseFloat(value, culture);
                if (result) {
                    result = result | 0;
                }
                return result;
            };
            kendo.parseFloat = function (value, culture, format) {
                if (!value && value !== 0) {
                    return null;
                }
                if (typeof value === NUMBER) {
                    return value;
                }
                value = value.toString();
                culture = kendo.getCulture(culture);
                var number = culture.numberFormat, percent = number.percent, currency = number.currency, symbol = currency.symbol, percentSymbol = percent.symbol, negative = value.indexOf('-'), parts, isPercent;
                if (exponentRegExp.test(value)) {
                    value = parseFloat(value.replace(number['.'], '.'));
                    if (isNaN(value)) {
                        value = null;
                    }
                    return value;
                }
                if (negative > 0) {
                    return null;
                } else {
                    negative = negative > -1;
                }
                if (value.indexOf(symbol) > -1 || format && format.toLowerCase().indexOf('c') > -1) {
                    number = currency;
                    parts = number.pattern[0].replace('$', symbol).split('n');
                    if (value.indexOf(parts[0]) > -1 && value.indexOf(parts[1]) > -1) {
                        value = value.replace(parts[0], '').replace(parts[1], '');
                        negative = true;
                    }
                } else if (value.indexOf(percentSymbol) > -1) {
                    isPercent = true;
                    number = percent;
                    symbol = percentSymbol;
                }
                value = value.replace('-', '').replace(symbol, '').replace(nonBreakingSpaceRegExp, ' ').split(number[','].replace(nonBreakingSpaceRegExp, ' ')).join('').replace(number['.'], '.');
                value = parseFloat(value);
                if (isNaN(value)) {
                    value = null;
                } else if (negative) {
                    value *= -1;
                }
                if (value && isPercent) {
                    value /= 100;
                }
                return value;
            };
        }());
        function getShadows(element) {
            var shadow = element.css(kendo.support.transitions.css + 'box-shadow') || element.css('box-shadow'), radius = shadow ? shadow.match(boxShadowRegExp) || [
                    0,
                    0,
                    0,
                    0,
                    0
                ] : [
                    0,
                    0,
                    0,
                    0,
                    0
                ], blur = math.max(+radius[3], +(radius[4] || 0));
            return {
                left: -radius[1] + blur,
                right: +radius[1] + blur,
                bottom: +radius[2] + blur
            };
        }
        function wrap(element, autosize) {
            var browser = support.browser, percentage, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight;
            if (!element.parent().hasClass('k-animation-container')) {
                var width = element[0].style.width, height = element[0].style.height, percentWidth = percentRegExp.test(width), percentHeight = percentRegExp.test(height);
                percentage = percentWidth || percentHeight;
                if (!percentWidth && (!autosize || autosize && width)) {
                    width = outerWidth(element);
                }
                if (!percentHeight && (!autosize || autosize && height)) {
                    height = outerHeight(element);
                }
                element.wrap($('<div/>').addClass('k-animation-container').css({
                    width: width,
                    height: height
                }));
                if (percentage) {
                    element.css({
                        width: '100%',
                        height: '100%',
                        boxSizing: 'border-box',
                        mozBoxSizing: 'border-box',
                        webkitBoxSizing: 'border-box'
                    });
                }
            } else {
                var wrapper = element.parent('.k-animation-container'), wrapperStyle = wrapper[0].style;
                if (wrapper.is(':hidden')) {
                    wrapper.show();
                }
                percentage = percentRegExp.test(wrapperStyle.width) || percentRegExp.test(wrapperStyle.height);
                if (!percentage) {
                    wrapper.css({
                        width: outerWidth(element),
                        height: outerHeight(element),
                        boxSizing: 'content-box',
                        mozBoxSizing: 'content-box',
                        webkitBoxSizing: 'content-box'
                    });
                }
            }
            if (browser.msie && math.floor(browser.version) <= 7) {
                element.css({ zoom: 1 });
                element.children('.k-menu').width(element.width());
            }
            return element.parent();
        }
        function deepExtend(destination) {
            var i = 1, length = arguments.length;
            for (i = 1; i < length; i++) {
                deepExtendOne(destination, arguments[i]);
            }
            return destination;
        }
        function deepExtendOne(destination, source) {
            var ObservableArray = kendo.data.ObservableArray, LazyObservableArray = kendo.data.LazyObservableArray, DataSource = kendo.data.DataSource, HierarchicalDataSource = kendo.data.HierarchicalDataSource, property, propValue, propType, propInit, destProp;
            for (property in source) {
                propValue = source[property];
                propType = typeof propValue;
                if (propType === OBJECT && propValue !== null) {
                    propInit = propValue.constructor;
                } else {
                    propInit = null;
                }
                if (propInit && propInit !== Array && propInit !== ObservableArray && propInit !== LazyObservableArray && propInit !== DataSource && propInit !== HierarchicalDataSource && propInit !== RegExp) {
                    if (propValue instanceof Date) {
                        destination[property] = new Date(propValue.getTime());
                    } else if (isFunction(propValue.clone)) {
                        destination[property] = propValue.clone();
                    } else {
                        destProp = destination[property];
                        if (typeof destProp === OBJECT) {
                            destination[property] = destProp || {};
                        } else {
                            destination[property] = {};
                        }
                        deepExtendOne(destination[property], propValue);
                    }
                } else if (propType !== UNDEFINED) {
                    destination[property] = propValue;
                }
            }
            return destination;
        }
        function testRx(agent, rxs, dflt) {
            for (var rx in rxs) {
                if (rxs.hasOwnProperty(rx) && rxs[rx].test(agent)) {
                    return rx;
                }
            }
            return dflt !== undefined ? dflt : agent;
        }
        function toHyphens(str) {
            return str.replace(/([a-z][A-Z])/g, function (g) {
                return g.charAt(0) + '-' + g.charAt(1).toLowerCase();
            });
        }
        function toCamelCase(str) {
            return str.replace(/\-(\w)/g, function (strMatch, g1) {
                return g1.toUpperCase();
            });
        }
        function getComputedStyles(element, properties) {
            var styles = {}, computedStyle;
            if (document.defaultView && document.defaultView.getComputedStyle) {
                computedStyle = document.defaultView.getComputedStyle(element, '');
                if (properties) {
                    $.each(properties, function (idx, value) {
                        styles[value] = computedStyle.getPropertyValue(value);
                    });
                }
            } else {
                computedStyle = element.currentStyle;
                if (properties) {
                    $.each(properties, function (idx, value) {
                        styles[value] = computedStyle[toCamelCase(value)];
                    });
                }
            }
            if (!kendo.size(styles)) {
                styles = computedStyle;
            }
            return styles;
        }
        function isScrollable(element) {
            if (element && element.className && typeof element.className === 'string' && element.className.indexOf('k-auto-scrollable') > -1) {
                return true;
            }
            var overflow = getComputedStyles(element, ['overflow']).overflow;
            return overflow == 'auto' || overflow == 'scroll';
        }
        function scrollLeft(element, value) {
            var webkit = support.browser.webkit;
            var mozila = support.browser.mozilla;
            var el = element instanceof $ ? element[0] : element;
            var isRtl;
            if (!element) {
                return;
            }
            isRtl = support.isRtl(element);
            if (value !== undefined) {
                if (isRtl && webkit) {
                    el.scrollLeft = el.scrollWidth - el.clientWidth - value;
                } else if (isRtl && mozila) {
                    el.scrollLeft = -value;
                } else {
                    el.scrollLeft = value;
                }
            } else {
                if (isRtl && webkit) {
                    return el.scrollWidth - el.clientWidth - el.scrollLeft;
                } else {
                    return Math.abs(el.scrollLeft);
                }
            }
        }
        (function () {
            support._scrollbar = undefined;
            support.scrollbar = function (refresh) {
                if (!isNaN(support._scrollbar) && !refresh) {
                    return support._scrollbar;
                } else {
                    var div = document.createElement('div'), result;
                    div.style.cssText = 'overflow:scroll;overflow-x:hidden;zoom:1;clear:both;display:block';
                    div.innerHTML = '&nbsp;';
                    document.body.appendChild(div);
                    support._scrollbar = result = div.offsetWidth - div.scrollWidth;
                    document.body.removeChild(div);
                    return result;
                }
            };
            support.isRtl = function (element) {
                return $(element).closest('.k-rtl').length > 0;
            };
            var table = document.createElement('table');
            try {
                table.innerHTML = '<tr><td></td></tr>';
                support.tbodyInnerHtml = true;
            } catch (e) {
                support.tbodyInnerHtml = false;
            }
            support.touch = 'ontouchstart' in window;
            var docStyle = document.documentElement.style;
            var transitions = support.transitions = false, transforms = support.transforms = false, elementProto = 'HTMLElement' in window ? HTMLElement.prototype : [];
            support.hasHW3D = 'WebKitCSSMatrix' in window && 'm11' in new window.WebKitCSSMatrix() || 'MozPerspective' in docStyle || 'msPerspective' in docStyle;
            support.cssFlexbox = 'flexWrap' in docStyle || 'WebkitFlexWrap' in docStyle || 'msFlexWrap' in docStyle;
            each([
                'Moz',
                'webkit',
                'O',
                'ms'
            ], function () {
                var prefix = this.toString(), hasTransitions = typeof table.style[prefix + 'Transition'] === STRING;
                if (hasTransitions || typeof table.style[prefix + 'Transform'] === STRING) {
                    var lowPrefix = prefix.toLowerCase();
                    transforms = {
                        css: lowPrefix != 'ms' ? '-' + lowPrefix + '-' : '',
                        prefix: prefix,
                        event: lowPrefix === 'o' || lowPrefix === 'webkit' ? lowPrefix : ''
                    };
                    if (hasTransitions) {
                        transitions = transforms;
                        transitions.event = transitions.event ? transitions.event + 'TransitionEnd' : 'transitionend';
                    }
                    return false;
                }
            });
            table = null;
            support.transforms = transforms;
            support.transitions = transitions;
            support.devicePixelRatio = window.devicePixelRatio === undefined ? 1 : window.devicePixelRatio;
            try {
                support.screenWidth = window.outerWidth || window.screen ? window.screen.availWidth : window.innerWidth;
                support.screenHeight = window.outerHeight || window.screen ? window.screen.availHeight : window.innerHeight;
            } catch (e) {
                support.screenWidth = window.screen.availWidth;
                support.screenHeight = window.screen.availHeight;
            }
            support.detectOS = function (ua) {
                var os = false, minorVersion, match = [], notAndroidPhone = !/mobile safari/i.test(ua), agentRxs = {
                        wp: /(Windows Phone(?: OS)?)\s(\d+)\.(\d+(\.\d+)?)/,
                        fire: /(Silk)\/(\d+)\.(\d+(\.\d+)?)/,
                        android: /(Android|Android.*(?:Opera|Firefox).*?\/)\s*(\d+)\.(\d+(\.\d+)?)/,
                        iphone: /(iPhone|iPod).*OS\s+(\d+)[\._]([\d\._]+)/,
                        ipad: /(iPad).*OS\s+(\d+)[\._]([\d_]+)/,
                        meego: /(MeeGo).+NokiaBrowser\/(\d+)\.([\d\._]+)/,
                        webos: /(webOS)\/(\d+)\.(\d+(\.\d+)?)/,
                        blackberry: /(BlackBerry|BB10).*?Version\/(\d+)\.(\d+(\.\d+)?)/,
                        playbook: /(PlayBook).*?Tablet\s*OS\s*(\d+)\.(\d+(\.\d+)?)/,
                        windows: /(MSIE)\s+(\d+)\.(\d+(\.\d+)?)/,
                        tizen: /(tizen).*?Version\/(\d+)\.(\d+(\.\d+)?)/i,
                        sailfish: /(sailfish).*rv:(\d+)\.(\d+(\.\d+)?).*firefox/i,
                        ffos: /(Mobile).*rv:(\d+)\.(\d+(\.\d+)?).*Firefox/
                    }, osRxs = {
                        ios: /^i(phone|pad|pod)$/i,
                        android: /^android|fire$/i,
                        blackberry: /^blackberry|playbook/i,
                        windows: /windows/,
                        wp: /wp/,
                        flat: /sailfish|ffos|tizen/i,
                        meego: /meego/
                    }, formFactorRxs = { tablet: /playbook|ipad|fire/i }, browserRxs = {
                        omini: /Opera\sMini/i,
                        omobile: /Opera\sMobi/i,
                        firefox: /Firefox|Fennec/i,
                        mobilesafari: /version\/.*safari/i,
                        ie: /MSIE|Windows\sPhone/i,
                        chrome: /chrome|crios/i,
                        webkit: /webkit/i
                    };
                for (var agent in agentRxs) {
                    if (agentRxs.hasOwnProperty(agent)) {
                        match = ua.match(agentRxs[agent]);
                        if (match) {
                            if (agent == 'windows' && 'plugins' in navigator) {
                                return false;
                            }
                            os = {};
                            os.device = agent;
                            os.tablet = testRx(agent, formFactorRxs, false);
                            os.browser = testRx(ua, browserRxs, 'default');
                            os.name = testRx(agent, osRxs);
                            os[os.name] = true;
                            os.majorVersion = match[2];
                            os.minorVersion = match[3].replace('_', '.');
                            minorVersion = os.minorVersion.replace('.', '').substr(0, 2);
                            os.flatVersion = os.majorVersion + minorVersion + new Array(3 - (minorVersion.length < 3 ? minorVersion.length : 2)).join('0');
                            os.cordova = typeof window.PhoneGap !== UNDEFINED || typeof window.cordova !== UNDEFINED;
                            os.appMode = window.navigator.standalone || /file|local|wmapp/.test(window.location.protocol) || os.cordova;
                            if (os.android && (support.devicePixelRatio < 1.5 && os.flatVersion < 400 || notAndroidPhone) && (support.screenWidth > 800 || support.screenHeight > 800)) {
                                os.tablet = agent;
                            }
                            break;
                        }
                    }
                }
                return os;
            };
            var mobileOS = support.mobileOS = support.detectOS(navigator.userAgent);
            support.wpDevicePixelRatio = mobileOS.wp ? screen.width / 320 : 0;
            support.hasNativeScrolling = false;
            if (mobileOS.ios || mobileOS.android && mobileOS.majorVersion > 2 || mobileOS.wp) {
                support.hasNativeScrolling = mobileOS;
            }
            support.delayedClick = function () {
                if (support.touch) {
                    if (mobileOS.ios) {
                        return true;
                    }
                    if (mobileOS.android) {
                        if (!support.browser.chrome) {
                            return true;
                        }
                        if (support.browser.version < 32) {
                            return false;
                        }
                        return !($('meta[name=viewport]').attr('content') || '').match(/user-scalable=no/i);
                    }
                }
                return false;
            };
            support.mouseAndTouchPresent = support.touch && !(support.mobileOS.ios || support.mobileOS.android);
            support.detectBrowser = function (ua) {
                var browser = false, match = [], browserRxs = {
                        edge: /(edge)[ \/]([\w.]+)/i,
                        webkit: /(chrome)[ \/]([\w.]+)/i,
                        safari: /(webkit)[ \/]([\w.]+)/i,
                        opera: /(opera)(?:.*version|)[ \/]([\w.]+)/i,
                        msie: /(msie\s|trident.*? rv:)([\w.]+)/i,
                        mozilla: /(mozilla)(?:.*? rv:([\w.]+)|)/i
                    };
                for (var agent in browserRxs) {
                    if (browserRxs.hasOwnProperty(agent)) {
                        match = ua.match(browserRxs[agent]);
                        if (match) {
                            browser = {};
                            browser[agent] = true;
                            browser[match[1].toLowerCase().split(' ')[0].split('/')[0]] = true;
                            browser.version = parseInt(document.documentMode || match[2], 10);
                            break;
                        }
                    }
                }
                return browser;
            };
            support.browser = support.detectBrowser(navigator.userAgent);
            support.detectClipboardAccess = function () {
                var commands = {
                    copy: document.queryCommandSupported ? document.queryCommandSupported('copy') : false,
                    cut: document.queryCommandSupported ? document.queryCommandSupported('cut') : false,
                    paste: document.queryCommandSupported ? document.queryCommandSupported('paste') : false
                };
                if (support.browser.chrome) {
                    commands.paste = false;
                    if (support.browser.version >= 43) {
                        commands.copy = true;
                        commands.cut = true;
                    }
                }
                return commands;
            };
            support.clipboard = support.detectClipboardAccess();
            support.zoomLevel = function () {
                try {
                    var browser = support.browser;
                    var ie11WidthCorrection = 0;
                    var docEl = document.documentElement;
                    if (browser.msie && browser.version == 11 && docEl.scrollHeight > docEl.clientHeight && !support.touch) {
                        ie11WidthCorrection = support.scrollbar();
                    }
                    return support.touch ? docEl.clientWidth / window.innerWidth : browser.msie && browser.version >= 10 ? ((top || window).document.documentElement.offsetWidth + ie11WidthCorrection) / (top || window).innerWidth : 1;
                } catch (e) {
                    return 1;
                }
            };
            support.cssBorderSpacing = typeof docStyle.borderSpacing != 'undefined' && !(support.browser.msie && support.browser.version < 8);
            (function (browser) {
                var cssClass = '', docElement = $(document.documentElement), majorVersion = parseInt(browser.version, 10);
                if (browser.msie) {
                    cssClass = 'ie';
                } else if (browser.mozilla) {
                    cssClass = 'ff';
                } else if (browser.safari) {
                    cssClass = 'safari';
                } else if (browser.webkit) {
                    cssClass = 'webkit';
                } else if (browser.opera) {
                    cssClass = 'opera';
                } else if (browser.edge) {
                    cssClass = 'edge';
                }
                if (cssClass) {
                    cssClass = 'k-' + cssClass + ' k-' + cssClass + majorVersion;
                }
                if (support.mobileOS) {
                    cssClass += ' k-mobile';
                }
                if (!support.cssFlexbox) {
                    cssClass += ' k-no-flexbox';
                }
                docElement.addClass(cssClass);
            }(support.browser));
            support.eventCapture = document.documentElement.addEventListener;
            var input = document.createElement('input');
            support.placeholder = 'placeholder' in input;
            support.propertyChangeEvent = 'onpropertychange' in input;
            support.input = function () {
                var types = [
                    'number',
                    'date',
                    'time',
                    'month',
                    'week',
                    'datetime',
                    'datetime-local'
                ];
                var length = types.length;
                var value = 'test';
                var result = {};
                var idx = 0;
                var type;
                for (; idx < length; idx++) {
                    type = types[idx];
                    input.setAttribute('type', type);
                    input.value = value;
                    result[type.replace('-', '')] = input.type !== 'text' && input.value !== value;
                }
                return result;
            }();
            input.style.cssText = 'float:left;';
            support.cssFloat = !!input.style.cssFloat;
            input = null;
            support.stableSort = function () {
                var threshold = 513;
                var sorted = [{
                        index: 0,
                        field: 'b'
                    }];
                for (var i = 1; i < threshold; i++) {
                    sorted.push({
                        index: i,
                        field: 'a'
                    });
                }
                sorted.sort(function (a, b) {
                    return a.field > b.field ? 1 : a.field < b.field ? -1 : 0;
                });
                return sorted[0].index === 1;
            }();
            support.matchesSelector = elementProto.webkitMatchesSelector || elementProto.mozMatchesSelector || elementProto.msMatchesSelector || elementProto.oMatchesSelector || elementProto.matchesSelector || elementProto.matches || function (selector) {
                var nodeList = document.querySelectorAll ? (this.parentNode || document).querySelectorAll(selector) || [] : $(selector), i = nodeList.length;
                while (i--) {
                    if (nodeList[i] == this) {
                        return true;
                    }
                }
                return false;
            };
            support.pushState = window.history && window.history.pushState;
            var documentMode = document.documentMode;
            support.hashChange = 'onhashchange' in window && !(support.browser.msie && (!documentMode || documentMode <= 8));
            support.customElements = 'registerElement' in window.document;
            var chrome = support.browser.chrome;
            support.msPointers = !chrome && window.MSPointerEvent;
            support.pointers = !chrome && window.PointerEvent;
            support.kineticScrollNeeded = mobileOS && (support.touch || support.msPointers || support.pointers);
        }());
        function size(obj) {
            var result = 0, key;
            for (key in obj) {
                if (obj.hasOwnProperty(key) && key != 'toJSON') {
                    result++;
                }
            }
            return result;
        }
        function getOffset(element, type, positioned) {
            if (!type) {
                type = 'offset';
            }
            var offset = element[type]();
            var result = {
                top: offset.top,
                right: offset.right,
                bottom: offset.bottom,
                left: offset.left
            };
            if (support.browser.msie && (support.pointers || support.msPointers) && !positioned) {
                var sign = support.isRtl(element) ? 1 : -1;
                result.top -= window.pageYOffset + sign * document.documentElement.scrollTop;
                result.left -= window.pageXOffset + sign * document.documentElement.scrollLeft;
            }
            return result;
        }
        var directions = {
            left: { reverse: 'right' },
            right: { reverse: 'left' },
            down: { reverse: 'up' },
            up: { reverse: 'down' },
            top: { reverse: 'bottom' },
            bottom: { reverse: 'top' },
            'in': { reverse: 'out' },
            out: { reverse: 'in' }
        };
        function parseEffects(input) {
            var effects = {};
            each(typeof input === 'string' ? input.split(' ') : input, function (idx) {
                effects[idx] = this;
            });
            return effects;
        }
        function fx(element) {
            return new kendo.effects.Element(element);
        }
        var effects = {};
        $.extend(effects, {
            enabled: true,
            Element: function (element) {
                this.element = $(element);
            },
            promise: function (element, options) {
                if (!element.is(':visible')) {
                    element.css({ display: element.data('olddisplay') || 'block' }).css('display');
                }
                if (options.hide) {
                    element.data('olddisplay', element.css('display')).hide();
                }
                if (options.init) {
                    options.init();
                }
                if (options.completeCallback) {
                    options.completeCallback(element);
                }
                element.dequeue();
            },
            disable: function () {
                this.enabled = false;
                this.promise = this.promiseShim;
            },
            enable: function () {
                this.enabled = true;
                this.promise = this.animatedPromise;
            }
        });
        effects.promiseShim = effects.promise;
        function prepareAnimationOptions(options, duration, reverse, complete) {
            if (typeof options === STRING) {
                if (isFunction(duration)) {
                    complete = duration;
                    duration = 400;
                    reverse = false;
                }
                if (isFunction(reverse)) {
                    complete = reverse;
                    reverse = false;
                }
                if (typeof duration === BOOLEAN) {
                    reverse = duration;
                    duration = 400;
                }
                options = {
                    effects: options,
                    duration: duration,
                    reverse: reverse,
                    complete: complete
                };
            }
            return extend({
                effects: {},
                duration: 400,
                reverse: false,
                init: noop,
                teardown: noop,
                hide: false
            }, options, {
                completeCallback: options.complete,
                complete: noop
            });
        }
        function animate(element, options, duration, reverse, complete) {
            var idx = 0, length = element.length, instance;
            for (; idx < length; idx++) {
                instance = $(element[idx]);
                instance.queue(function () {
                    effects.promise(instance, prepareAnimationOptions(options, duration, reverse, complete));
                });
            }
            return element;
        }
        function toggleClass(element, classes, options, add) {
            if (classes) {
                classes = classes.split(' ');
                each(classes, function (idx, value) {
                    element.toggleClass(value, add);
                });
            }
            return element;
        }
        if (!('kendoAnimate' in $.fn)) {
            extend($.fn, {
                kendoStop: function (clearQueue, gotoEnd) {
                    return this.stop(clearQueue, gotoEnd);
                },
                kendoAnimate: function (options, duration, reverse, complete) {
                    return animate(this, options, duration, reverse, complete);
                },
                kendoAddClass: function (classes, options) {
                    return kendo.toggleClass(this, classes, options, true);
                },
                kendoRemoveClass: function (classes, options) {
                    return kendo.toggleClass(this, classes, options, false);
                },
                kendoToggleClass: function (classes, options, toggle) {
                    return kendo.toggleClass(this, classes, options, toggle);
                }
            });
        }
        var ampRegExp = /&/g, ltRegExp = /</g, quoteRegExp = /"/g, aposRegExp = /'/g, gtRegExp = />/g;
        function htmlEncode(value) {
            return ('' + value).replace(ampRegExp, '&amp;').replace(ltRegExp, '&lt;').replace(gtRegExp, '&gt;').replace(quoteRegExp, '&quot;').replace(aposRegExp, '&#39;');
        }
        var eventTarget = function (e) {
            return e.target;
        };
        if (support.touch) {
            eventTarget = function (e) {
                var touches = 'originalEvent' in e ? e.originalEvent.changedTouches : 'changedTouches' in e ? e.changedTouches : null;
                return touches ? document.elementFromPoint(touches[0].clientX, touches[0].clientY) : e.target;
            };
            each([
                'swipe',
                'swipeLeft',
                'swipeRight',
                'swipeUp',
                'swipeDown',
                'doubleTap',
                'tap'
            ], function (m, value) {
                $.fn[value] = function (callback) {
                    return this.bind(value, callback);
                };
            });
        }
        if (support.touch) {
            if (!support.mobileOS) {
                support.mousedown = 'mousedown touchstart';
                support.mouseup = 'mouseup touchend';
                support.mousemove = 'mousemove touchmove';
                support.mousecancel = 'mouseleave touchcancel';
                support.click = 'click';
                support.resize = 'resize';
            } else {
                support.mousedown = 'touchstart';
                support.mouseup = 'touchend';
                support.mousemove = 'touchmove';
                support.mousecancel = 'touchcancel';
                support.click = 'touchend';
                support.resize = 'orientationchange';
            }
        } else if (support.pointers) {
            support.mousemove = 'pointermove';
            support.mousedown = 'pointerdown';
            support.mouseup = 'pointerup';
            support.mousecancel = 'pointercancel';
            support.click = 'pointerup';
            support.resize = 'orientationchange resize';
        } else if (support.msPointers) {
            support.mousemove = 'MSPointerMove';
            support.mousedown = 'MSPointerDown';
            support.mouseup = 'MSPointerUp';
            support.mousecancel = 'MSPointerCancel';
            support.click = 'MSPointerUp';
            support.resize = 'orientationchange resize';
        } else {
            support.mousemove = 'mousemove';
            support.mousedown = 'mousedown';
            support.mouseup = 'mouseup';
            support.mousecancel = 'mouseleave';
            support.click = 'click';
            support.resize = 'resize';
        }
        var wrapExpression = function (members, paramName) {
                var result = paramName || 'd', index, idx, length, member, count = 1;
                for (idx = 0, length = members.length; idx < length; idx++) {
                    member = members[idx];
                    if (member !== '') {
                        index = member.indexOf('[');
                        if (index !== 0) {
                            if (index == -1) {
                                member = '.' + member;
                            } else {
                                count++;
                                member = '.' + member.substring(0, index) + ' || {})' + member.substring(index);
                            }
                        }
                        count++;
                        result += member + (idx < length - 1 ? ' || {})' : ')');
                    }
                }
                return new Array(count).join('(') + result;
            }, localUrlRe = /^([a-z]+:)?\/\//i;
        extend(kendo, {
            widgets: [],
            _widgetRegisteredCallbacks: [],
            ui: kendo.ui || {},
            fx: kendo.fx || fx,
            effects: kendo.effects || effects,
            mobile: kendo.mobile || {},
            data: kendo.data || {},
            dataviz: kendo.dataviz || {},
            drawing: kendo.drawing || {},
            spreadsheet: { messages: {} },
            keys: {
                INSERT: 45,
                DELETE: 46,
                BACKSPACE: 8,
                TAB: 9,
                ENTER: 13,
                ESC: 27,
                LEFT: 37,
                UP: 38,
                RIGHT: 39,
                DOWN: 40,
                END: 35,
                HOME: 36,
                SPACEBAR: 32,
                PAGEUP: 33,
                PAGEDOWN: 34,
                F2: 113,
                F10: 121,
                F12: 123,
                NUMPAD_PLUS: 107,
                NUMPAD_MINUS: 109,
                NUMPAD_DOT: 110
            },
            support: kendo.support || support,
            animate: kendo.animate || animate,
            ns: '',
            attr: function (value) {
                return 'data-' + kendo.ns + value;
            },
            getShadows: getShadows,
            wrap: wrap,
            deepExtend: deepExtend,
            getComputedStyles: getComputedStyles,
            webComponents: kendo.webComponents || [],
            isScrollable: isScrollable,
            scrollLeft: scrollLeft,
            size: size,
            toCamelCase: toCamelCase,
            toHyphens: toHyphens,
            getOffset: kendo.getOffset || getOffset,
            parseEffects: kendo.parseEffects || parseEffects,
            toggleClass: kendo.toggleClass || toggleClass,
            directions: kendo.directions || directions,
            Observable: Observable,
            Class: Class,
            Template: Template,
            template: proxy(Template.compile, Template),
            render: proxy(Template.render, Template),
            stringify: proxy(JSON.stringify, JSON),
            eventTarget: eventTarget,
            htmlEncode: htmlEncode,
            isLocalUrl: function (url) {
                return url && !localUrlRe.test(url);
            },
            expr: function (expression, safe, paramName) {
                expression = expression || '';
                if (typeof safe == STRING) {
                    paramName = safe;
                    safe = false;
                }
                paramName = paramName || 'd';
                if (expression && expression.charAt(0) !== '[') {
                    expression = '.' + expression;
                }
                if (safe) {
                    expression = expression.replace(/"([^.]*)\.([^"]*)"/g, '"$1_$DOT$_$2"');
                    expression = expression.replace(/'([^.]*)\.([^']*)'/g, '\'$1_$DOT$_$2\'');
                    expression = wrapExpression(expression.split('.'), paramName);
                    expression = expression.replace(/_\$DOT\$_/g, '.');
                } else {
                    expression = paramName + expression;
                }
                return expression;
            },
            getter: function (expression, safe) {
                var key = expression + safe;
                return getterCache[key] = getterCache[key] || new Function('d', 'return ' + kendo.expr(expression, safe));
            },
            setter: function (expression) {
                return setterCache[expression] = setterCache[expression] || new Function('d,value', kendo.expr(expression) + '=value');
            },
            accessor: function (expression) {
                return {
                    get: kendo.getter(expression),
                    set: kendo.setter(expression)
                };
            },
            guid: function () {
                var id = '', i, random;
                for (i = 0; i < 32; i++) {
                    random = math.random() * 16 | 0;
                    if (i == 8 || i == 12 || i == 16 || i == 20) {
                        id += '-';
                    }
                    id += (i == 12 ? 4 : i == 16 ? random & 3 | 8 : random).toString(16);
                }
                return id;
            },
            roleSelector: function (role) {
                return role.replace(/(\S+)/g, '[' + kendo.attr('role') + '=$1],').slice(0, -1);
            },
            directiveSelector: function (directives) {
                var selectors = directives.split(' ');
                if (selectors) {
                    for (var i = 0; i < selectors.length; i++) {
                        if (selectors[i] != 'view') {
                            selectors[i] = selectors[i].replace(/(\w*)(view|bar|strip|over)$/, '$1-$2');
                        }
                    }
                }
                return selectors.join(' ').replace(/(\S+)/g, 'kendo-mobile-$1,').slice(0, -1);
            },
            triggeredByInput: function (e) {
                return /^(label|input|textarea|select)$/i.test(e.target.tagName);
            },
            onWidgetRegistered: function (callback) {
                for (var i = 0, len = kendo.widgets.length; i < len; i++) {
                    callback(kendo.widgets[i]);
                }
                kendo._widgetRegisteredCallbacks.push(callback);
            },
            logToConsole: function (message, type) {
                var console = window.console;
                if (!kendo.suppressLog && typeof console != 'undefined' && console.log) {
                    console[type || 'log'](message);
                }
            }
        });
        var Widget = Observable.extend({
            init: function (element, options) {
                var that = this;
                that.element = kendo.jQuery(element).handler(that);
                that.angular('init', options);
                Observable.fn.init.call(that);
                var dataSource = options ? options.dataSource : null;
                if (dataSource) {
                    options = extend({}, options, { dataSource: {} });
                }
                options = that.options = extend(true, {}, that.options, options);
                if (dataSource) {
                    options.dataSource = dataSource;
                }
                if (!that.element.attr(kendo.attr('role'))) {
                    that.element.attr(kendo.attr('role'), (options.name || '').toLowerCase());
                }
                that.element.data('kendo' + options.prefix + options.name, that);
                that.bind(that.events, options);
            },
            events: [],
            options: { prefix: '' },
            _hasBindingTarget: function () {
                return !!this.element[0].kendoBindingTarget;
            },
            _tabindex: function (target) {
                target = target || this.wrapper;
                var element = this.element, TABINDEX = 'tabindex', tabindex = target.attr(TABINDEX) || element.attr(TABINDEX);
                element.removeAttr(TABINDEX);
                target.attr(TABINDEX, !isNaN(tabindex) ? tabindex : 0);
            },
            setOptions: function (options) {
                this._setEvents(options);
                $.extend(this.options, options);
            },
            _setEvents: function (options) {
                var that = this, idx = 0, length = that.events.length, e;
                for (; idx < length; idx++) {
                    e = that.events[idx];
                    if (that.options[e] && options[e]) {
                        that.unbind(e, that.options[e]);
                    }
                }
                that.bind(that.events, options);
            },
            resize: function (force) {
                var size = this.getSize(), currentSize = this._size;
                if (force || (size.width > 0 || size.height > 0) && (!currentSize || size.width !== currentSize.width || size.height !== currentSize.height)) {
                    this._size = size;
                    this._resize(size, force);
                    this.trigger('resize', size);
                }
            },
            getSize: function () {
                return kendo.dimensions(this.element);
            },
            size: function (size) {
                if (!size) {
                    return this.getSize();
                } else {
                    this.setSize(size);
                }
            },
            setSize: $.noop,
            _resize: $.noop,
            destroy: function () {
                var that = this;
                that.element.removeData('kendo' + that.options.prefix + that.options.name);
                that.element.removeData('handler');
                that.unbind();
            },
            _destroy: function () {
                this.destroy();
            },
            angular: function () {
            },
            _muteAngularRebind: function (callback) {
                this._muteRebind = true;
                callback.call(this);
                this._muteRebind = false;
            }
        });
        var DataBoundWidget = Widget.extend({
            dataItems: function () {
                return this.dataSource.flatView();
            },
            _angularItems: function (cmd) {
                var that = this;
                that.angular(cmd, function () {
                    return {
                        elements: that.items(),
                        data: $.map(that.dataItems(), function (dataItem) {
                            return { dataItem: dataItem };
                        })
                    };
                });
            }
        });
        kendo.dimensions = function (element, dimensions) {
            var domElement = element[0];
            if (dimensions) {
                element.css(dimensions);
            }
            return {
                width: domElement.offsetWidth,
                height: domElement.offsetHeight
            };
        };
        kendo.notify = noop;
        var templateRegExp = /template$/i, jsonRegExp = /^\s*(?:\{(?:.|\r\n|\n)*\}|\[(?:.|\r\n|\n)*\])\s*$/, jsonFormatRegExp = /^\{(\d+)(:[^\}]+)?\}|^\[[A-Za-z_]+\]$/, dashRegExp = /([A-Z])/g;
        function parseOption(element, option) {
            var value;
            if (option.indexOf('data') === 0) {
                option = option.substring(4);
                option = option.charAt(0).toLowerCase() + option.substring(1);
            }
            option = option.replace(dashRegExp, '-$1');
            value = element.getAttribute('data-' + kendo.ns + option);
            if (value === null) {
                value = undefined;
            } else if (value === 'null') {
                value = null;
            } else if (value === 'true') {
                value = true;
            } else if (value === 'false') {
                value = false;
            } else if (numberRegExp.test(value)) {
                value = parseFloat(value);
            } else if (jsonRegExp.test(value) && !jsonFormatRegExp.test(value)) {
                value = new Function('return (' + value + ')')();
            }
            return value;
        }
        function parseOptions(element, options) {
            var result = {}, option, value;
            for (option in options) {
                value = parseOption(element, option);
                if (value !== undefined) {
                    if (templateRegExp.test(option)) {
                        if (typeof value === 'string') {
                            value = kendo.template($('#' + value).html());
                        } else {
                            value = element.getAttribute(option);
                        }
                    }
                    result[option] = value;
                }
            }
            return result;
        }
        kendo.initWidget = function (element, options, roles) {
            var result, option, widget, idx, length, role, value, dataSource, fullPath, widgetKeyRegExp;
            if (!roles) {
                roles = kendo.ui.roles;
            } else if (roles.roles) {
                roles = roles.roles;
            }
            element = element.nodeType ? element : element[0];
            role = element.getAttribute('data-' + kendo.ns + 'role');
            if (!role) {
                return;
            }
            fullPath = role.indexOf('.') === -1;
            if (fullPath) {
                widget = roles[role];
            } else {
                widget = kendo.getter(role)(window);
            }
            var data = $(element).data(), widgetKey = widget ? 'kendo' + widget.fn.options.prefix + widget.fn.options.name : '';
            if (fullPath) {
                widgetKeyRegExp = new RegExp('^kendo.*' + role + '$', 'i');
            } else {
                widgetKeyRegExp = new RegExp('^' + widgetKey + '$', 'i');
            }
            for (var key in data) {
                if (key.match(widgetKeyRegExp)) {
                    if (key === widgetKey) {
                        result = data[key];
                    } else {
                        return data[key];
                    }
                }
            }
            if (!widget) {
                return;
            }
            dataSource = parseOption(element, 'dataSource');
            options = $.extend({}, parseOptions(element, widget.fn.options), options);
            if (dataSource) {
                if (typeof dataSource === STRING) {
                    options.dataSource = kendo.getter(dataSource)(window);
                } else {
                    options.dataSource = dataSource;
                }
            }
            for (idx = 0, length = widget.fn.events.length; idx < length; idx++) {
                option = widget.fn.events[idx];
                value = parseOption(element, option);
                if (value !== undefined) {
                    options[option] = kendo.getter(value)(window);
                }
            }
            if (!result) {
                result = new widget(element, options);
            } else if (!$.isEmptyObject(options)) {
                result.setOptions(options);
            }
            return result;
        };
        kendo.rolesFromNamespaces = function (namespaces) {
            var roles = [], idx, length;
            if (!namespaces[0]) {
                namespaces = [
                    kendo.ui,
                    kendo.dataviz.ui
                ];
            }
            for (idx = 0, length = namespaces.length; idx < length; idx++) {
                roles[idx] = namespaces[idx].roles;
            }
            return extend.apply(null, [{}].concat(roles.reverse()));
        };
        kendo.init = function (element) {
            var roles = kendo.rolesFromNamespaces(slice.call(arguments, 1));
            $(element).find('[data-' + kendo.ns + 'role]').addBack().each(function () {
                kendo.initWidget(this, {}, roles);
            });
        };
        kendo.destroy = function (element) {
            $(element).find('[data-' + kendo.ns + 'role]').addBack().each(function () {
                var data = $(this).data();
                for (var key in data) {
                    if (key.indexOf('kendo') === 0 && typeof data[key].destroy === FUNCTION) {
                        data[key].destroy();
                    }
                }
            });
        };
        function containmentComparer(a, b) {
            return $.contains(a, b) ? -1 : 1;
        }
        function resizableWidget() {
            var widget = $(this);
            return $.inArray(widget.attr('data-' + kendo.ns + 'role'), [
                'slider',
                'rangeslider'
            ]) > -1 || widget.is(':visible');
        }
        kendo.resize = function (element, force) {
            var widgets = $(element).find('[data-' + kendo.ns + 'role]').addBack().filter(resizableWidget);
            if (!widgets.length) {
                return;
            }
            var widgetsArray = $.makeArray(widgets);
            widgetsArray.sort(containmentComparer);
            $.each(widgetsArray, function () {
                var widget = kendo.widgetInstance($(this));
                if (widget) {
                    widget.resize(force);
                }
            });
        };
        kendo.parseOptions = parseOptions;
        extend(kendo.ui, {
            Widget: Widget,
            DataBoundWidget: DataBoundWidget,
            roles: {},
            progress: function (container, toggle) {
                var mask = container.find('.k-loading-mask'), support = kendo.support, browser = support.browser, isRtl, leftRight, webkitCorrection, containerScrollLeft;
                if (toggle) {
                    if (!mask.length) {
                        isRtl = support.isRtl(container);
                        leftRight = isRtl ? 'right' : 'left';
                        containerScrollLeft = container.scrollLeft();
                        webkitCorrection = browser.webkit ? !isRtl ? 0 : container[0].scrollWidth - container.width() - 2 * containerScrollLeft : 0;
                        mask = $('<div class=\'k-loading-mask\'><span class=\'k-loading-text\'>' + kendo.ui.progress.messages.loading + '</span><div class=\'k-loading-image\'/><div class=\'k-loading-color\'/></div>').width('100%').height('100%').css('top', container.scrollTop()).css(leftRight, Math.abs(containerScrollLeft) + webkitCorrection).prependTo(container);
                    }
                } else if (mask) {
                    mask.remove();
                }
            },
            plugin: function (widget, register, prefix) {
                var name = widget.fn.options.name, getter;
                register = register || kendo.ui;
                prefix = prefix || '';
                register[name] = widget;
                register.roles[name.toLowerCase()] = widget;
                getter = 'getKendo' + prefix + name;
                name = 'kendo' + prefix + name;
                var widgetEntry = {
                    name: name,
                    widget: widget,
                    prefix: prefix || ''
                };
                kendo.widgets.push(widgetEntry);
                for (var i = 0, len = kendo._widgetRegisteredCallbacks.length; i < len; i++) {
                    kendo._widgetRegisteredCallbacks[i](widgetEntry);
                }
                $.fn[name] = function (options) {
                    var value = this, args;
                    if (typeof options === STRING) {
                        args = slice.call(arguments, 1);
                        this.each(function () {
                            var widget = $.data(this, name), method, result;
                            if (!widget) {
                                throw new Error(kendo.format('Cannot call method \'{0}\' of {1} before it is initialized', options, name));
                            }
                            method = widget[options];
                            if (typeof method !== FUNCTION) {
                                throw new Error(kendo.format('Cannot find method \'{0}\' of {1}', options, name));
                            }
                            result = method.apply(widget, args);
                            if (result !== undefined) {
                                value = result;
                                return false;
                            }
                        });
                    } else {
                        this.each(function () {
                            return new widget(this, options);
                        });
                    }
                    return value;
                };
                $.fn[name].widget = widget;
                $.fn[getter] = function () {
                    return this.data(name);
                };
            }
        });
        kendo.ui.progress.messages = { loading: 'Loading...' };
        var ContainerNullObject = {
            bind: function () {
                return this;
            },
            nullObject: true,
            options: {}
        };
        var MobileWidget = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.element.autoApplyNS();
                this.wrapper = this.element;
                this.element.addClass('km-widget');
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.kendoDestroy();
            },
            options: { prefix: 'Mobile' },
            events: [],
            view: function () {
                var viewElement = this.element.closest(kendo.roleSelector('view splitview modalview drawer'));
                return kendo.widgetInstance(viewElement, kendo.mobile.ui) || ContainerNullObject;
            },
            viewHasNativeScrolling: function () {
                var view = this.view();
                return view && view.options.useNativeScrolling;
            },
            container: function () {
                var element = this.element.closest(kendo.roleSelector('view layout modalview drawer splitview'));
                return kendo.widgetInstance(element.eq(0), kendo.mobile.ui) || ContainerNullObject;
            }
        });
        extend(kendo.mobile, {
            init: function (element) {
                kendo.init(element, kendo.mobile.ui, kendo.ui, kendo.dataviz.ui);
            },
            appLevelNativeScrolling: function () {
                return kendo.mobile.application && kendo.mobile.application.options && kendo.mobile.application.options.useNativeScrolling;
            },
            roles: {},
            ui: {
                Widget: MobileWidget,
                DataBoundWidget: DataBoundWidget.extend(MobileWidget.prototype),
                roles: {},
                plugin: function (widget) {
                    kendo.ui.plugin(widget, kendo.mobile.ui, 'Mobile');
                }
            }
        });
        deepExtend(kendo.dataviz, {
            init: function (element) {
                kendo.init(element, kendo.dataviz.ui);
            },
            ui: {
                roles: {},
                themes: {},
                views: [],
                plugin: function (widget) {
                    kendo.ui.plugin(widget, kendo.dataviz.ui);
                }
            },
            roles: {}
        });
        kendo.touchScroller = function (elements, options) {
            if (!options) {
                options = {};
            }
            options.useNative = true;
            return $(elements).map(function (idx, element) {
                element = $(element);
                if (support.kineticScrollNeeded && kendo.mobile.ui.Scroller && !element.data('kendoMobileScroller')) {
                    element.kendoMobileScroller(options);
                    return element.data('kendoMobileScroller');
                } else {
                    return false;
                }
            })[0];
        };
        kendo.preventDefault = function (e) {
            e.preventDefault();
        };
        kendo.widgetInstance = function (element, suites) {
            var role = element.data(kendo.ns + 'role'), widgets = [], i, length;
            if (role) {
                if (role === 'content') {
                    role = 'scroller';
                }
                if (suites) {
                    if (suites[0]) {
                        for (i = 0, length = suites.length; i < length; i++) {
                            widgets.push(suites[i].roles[role]);
                        }
                    } else {
                        widgets.push(suites.roles[role]);
                    }
                } else {
                    widgets = [
                        kendo.ui.roles[role],
                        kendo.dataviz.ui.roles[role],
                        kendo.mobile.ui.roles[role]
                    ];
                }
                if (role.indexOf('.') >= 0) {
                    widgets = [kendo.getter(role)(window)];
                }
                for (i = 0, length = widgets.length; i < length; i++) {
                    var widget = widgets[i];
                    if (widget) {
                        var instance = element.data('kendo' + widget.fn.options.prefix + widget.fn.options.name);
                        if (instance) {
                            return instance;
                        }
                    }
                }
            }
        };
        kendo.onResize = function (callback) {
            var handler = callback;
            if (support.mobileOS.android) {
                handler = function () {
                    setTimeout(callback, 600);
                };
            }
            $(window).on(support.resize, handler);
            return handler;
        };
        kendo.unbindResize = function (callback) {
            $(window).off(support.resize, callback);
        };
        kendo.attrValue = function (element, key) {
            return element.data(kendo.ns + key);
        };
        kendo.days = {
            Sunday: 0,
            Monday: 1,
            Tuesday: 2,
            Wednesday: 3,
            Thursday: 4,
            Friday: 5,
            Saturday: 6
        };
        function focusable(element, isTabIndexNotNaN) {
            var nodeName = element.nodeName.toLowerCase();
            return (/input|select|textarea|button|object/.test(nodeName) ? !element.disabled : 'a' === nodeName ? element.href || isTabIndexNotNaN : isTabIndexNotNaN) && visible(element);
        }
        function visible(element) {
            return $.expr.filters.visible(element) && !$(element).parents().addBack().filter(function () {
                return $.css(this, 'visibility') === 'hidden';
            }).length;
        }
        $.extend($.expr[':'], {
            kendoFocusable: function (element) {
                var idx = $.attr(element, 'tabindex');
                return focusable(element, !isNaN(idx) && idx > -1);
            }
        });
        var MOUSE_EVENTS = [
            'mousedown',
            'mousemove',
            'mouseenter',
            'mouseleave',
            'mouseover',
            'mouseout',
            'mouseup',
            'click'
        ];
        var EXCLUDE_BUST_CLICK_SELECTOR = 'label, input, [data-rel=external]';
        var MouseEventNormalizer = {
            setupMouseMute: function () {
                var idx = 0, length = MOUSE_EVENTS.length, element = document.documentElement;
                if (MouseEventNormalizer.mouseTrap || !support.eventCapture) {
                    return;
                }
                MouseEventNormalizer.mouseTrap = true;
                MouseEventNormalizer.bustClick = false;
                MouseEventNormalizer.captureMouse = false;
                var handler = function (e) {
                    if (MouseEventNormalizer.captureMouse) {
                        if (e.type === 'click') {
                            if (MouseEventNormalizer.bustClick && !$(e.target).is(EXCLUDE_BUST_CLICK_SELECTOR)) {
                                e.preventDefault();
                                e.stopPropagation();
                            }
                        } else {
                            e.stopPropagation();
                        }
                    }
                };
                for (; idx < length; idx++) {
                    element.addEventListener(MOUSE_EVENTS[idx], handler, true);
                }
            },
            muteMouse: function (e) {
                MouseEventNormalizer.captureMouse = true;
                if (e.data.bustClick) {
                    MouseEventNormalizer.bustClick = true;
                }
                clearTimeout(MouseEventNormalizer.mouseTrapTimeoutID);
            },
            unMuteMouse: function () {
                clearTimeout(MouseEventNormalizer.mouseTrapTimeoutID);
                MouseEventNormalizer.mouseTrapTimeoutID = setTimeout(function () {
                    MouseEventNormalizer.captureMouse = false;
                    MouseEventNormalizer.bustClick = false;
                }, 400);
            }
        };
        var eventMap = {
            down: 'touchstart mousedown',
            move: 'mousemove touchmove',
            up: 'mouseup touchend touchcancel',
            cancel: 'mouseleave touchcancel'
        };
        if (support.touch && (support.mobileOS.ios || support.mobileOS.android)) {
            eventMap = {
                down: 'touchstart',
                move: 'touchmove',
                up: 'touchend touchcancel',
                cancel: 'touchcancel'
            };
        } else if (support.pointers) {
            eventMap = {
                down: 'pointerdown',
                move: 'pointermove',
                up: 'pointerup',
                cancel: 'pointercancel pointerleave'
            };
        } else if (support.msPointers) {
            eventMap = {
                down: 'MSPointerDown',
                move: 'MSPointerMove',
                up: 'MSPointerUp',
                cancel: 'MSPointerCancel MSPointerLeave'
            };
        }
        if (support.msPointers && !('onmspointerenter' in window)) {
            $.each({
                MSPointerEnter: 'MSPointerOver',
                MSPointerLeave: 'MSPointerOut'
            }, function (orig, fix) {
                $.event.special[orig] = {
                    delegateType: fix,
                    bindType: fix,
                    handle: function (event) {
                        var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj;
                        if (!related || related !== target && !$.contains(target, related)) {
                            event.type = handleObj.origType;
                            ret = handleObj.handler.apply(this, arguments);
                            event.type = fix;
                        }
                        return ret;
                    }
                };
            });
        }
        var getEventMap = function (e) {
                return eventMap[e] || e;
            }, eventRegEx = /([^ ]+)/g;
        kendo.applyEventMap = function (events, ns) {
            events = events.replace(eventRegEx, getEventMap);
            if (ns) {
                events = events.replace(eventRegEx, '$1.' + ns);
            }
            return events;
        };
        var on = $.fn.on;
        function kendoJQuery(selector, context) {
            return new kendoJQuery.fn.init(selector, context);
        }
        extend(true, kendoJQuery, $);
        kendoJQuery.fn = kendoJQuery.prototype = new $();
        kendoJQuery.fn.constructor = kendoJQuery;
        kendoJQuery.fn.init = function (selector, context) {
            if (context && context instanceof $ && !(context instanceof kendoJQuery)) {
                context = kendoJQuery(context);
            }
            return $.fn.init.call(this, selector, context, rootjQuery);
        };
        kendoJQuery.fn.init.prototype = kendoJQuery.fn;
        var rootjQuery = kendoJQuery(document);
        extend(kendoJQuery.fn, {
            handler: function (handler) {
                this.data('handler', handler);
                return this;
            },
            autoApplyNS: function (ns) {
                this.data('kendoNS', ns || kendo.guid());
                return this;
            },
            on: function () {
                var that = this, ns = that.data('kendoNS');
                if (arguments.length === 1) {
                    return on.call(that, arguments[0]);
                }
                var context = that, args = slice.call(arguments);
                if (typeof args[args.length - 1] === UNDEFINED) {
                    args.pop();
                }
                var callback = args[args.length - 1], events = kendo.applyEventMap(args[0], ns);
                if (support.mouseAndTouchPresent && events.search(/mouse|click/) > -1 && this[0] !== document.documentElement) {
                    MouseEventNormalizer.setupMouseMute();
                    var selector = args.length === 2 ? null : args[1], bustClick = events.indexOf('click') > -1 && events.indexOf('touchend') > -1;
                    on.call(this, {
                        touchstart: MouseEventNormalizer.muteMouse,
                        touchend: MouseEventNormalizer.unMuteMouse
                    }, selector, { bustClick: bustClick });
                }
                if (typeof callback === STRING) {
                    context = that.data('handler');
                    callback = context[callback];
                    args[args.length - 1] = function (e) {
                        callback.call(context, e);
                    };
                }
                args[0] = events;
                on.apply(that, args);
                return that;
            },
            kendoDestroy: function (ns) {
                ns = ns || this.data('kendoNS');
                if (ns) {
                    this.off('.' + ns);
                }
                return this;
            }
        });
        kendo.jQuery = kendoJQuery;
        kendo.eventMap = eventMap;
        kendo.timezone = function () {
            var months = {
                Jan: 0,
                Feb: 1,
                Mar: 2,
                Apr: 3,
                May: 4,
                Jun: 5,
                Jul: 6,
                Aug: 7,
                Sep: 8,
                Oct: 9,
                Nov: 10,
                Dec: 11
            };
            var days = {
                Sun: 0,
                Mon: 1,
                Tue: 2,
                Wed: 3,
                Thu: 4,
                Fri: 5,
                Sat: 6
            };
            function ruleToDate(year, rule) {
                var date;
                var targetDay;
                var ourDay;
                var month = rule[3];
                var on = rule[4];
                var time = rule[5];
                var cache = rule[8];
                if (!cache) {
                    rule[8] = cache = {};
                }
                if (cache[year]) {
                    return cache[year];
                }
                if (!isNaN(on)) {
                    date = new Date(Date.UTC(year, months[month], on, time[0], time[1], time[2], 0));
                } else if (on.indexOf('last') === 0) {
                    date = new Date(Date.UTC(year, months[month] + 1, 1, time[0] - 24, time[1], time[2], 0));
                    targetDay = days[on.substr(4, 3)];
                    ourDay = date.getUTCDay();
                    date.setUTCDate(date.getUTCDate() + targetDay - ourDay - (targetDay > ourDay ? 7 : 0));
                } else if (on.indexOf('>=') >= 0) {
                    date = new Date(Date.UTC(year, months[month], on.substr(5), time[0], time[1], time[2], 0));
                    targetDay = days[on.substr(0, 3)];
                    ourDay = date.getUTCDay();
                    date.setUTCDate(date.getUTCDate() + targetDay - ourDay + (targetDay < ourDay ? 7 : 0));
                }
                return cache[year] = date;
            }
            function findRule(utcTime, rules, zone) {
                rules = rules[zone];
                if (!rules) {
                    var time = zone.split(':');
                    var offset = 0;
                    if (time.length > 1) {
                        offset = time[0] * 60 + Number(time[1]);
                    }
                    return [
                        -1000000,
                        'max',
                        '-',
                        'Jan',
                        1,
                        [
                            0,
                            0,
                            0
                        ],
                        offset,
                        '-'
                    ];
                }
                var year = new Date(utcTime).getUTCFullYear();
                rules = jQuery.grep(rules, function (rule) {
                    var from = rule[0];
                    var to = rule[1];
                    return from <= year && (to >= year || from == year && to == 'only' || to == 'max');
                });
                rules.push(utcTime);
                rules.sort(function (a, b) {
                    if (typeof a != 'number') {
                        a = Number(ruleToDate(year, a));
                    }
                    if (typeof b != 'number') {
                        b = Number(ruleToDate(year, b));
                    }
                    return a - b;
                });
                var rule = rules[jQuery.inArray(utcTime, rules) - 1] || rules[rules.length - 1];
                return isNaN(rule) ? rule : null;
            }
            function findZone(utcTime, zones, timezone) {
                var zoneRules = zones[timezone];
                if (typeof zoneRules === 'string') {
                    zoneRules = zones[zoneRules];
                }
                if (!zoneRules) {
                    throw new Error('Timezone "' + timezone + '" is either incorrect, or kendo.timezones.min.js is not included.');
                }
                for (var idx = zoneRules.length - 1; idx >= 0; idx--) {
                    var until = zoneRules[idx][3];
                    if (until && utcTime > until) {
                        break;
                    }
                }
                var zone = zoneRules[idx + 1];
                if (!zone) {
                    throw new Error('Timezone "' + timezone + '" not found on ' + utcTime + '.');
                }
                return zone;
            }
            function zoneAndRule(utcTime, zones, rules, timezone) {
                if (typeof utcTime != NUMBER) {
                    utcTime = Date.UTC(utcTime.getFullYear(), utcTime.getMonth(), utcTime.getDate(), utcTime.getHours(), utcTime.getMinutes(), utcTime.getSeconds(), utcTime.getMilliseconds());
                }
                var zone = findZone(utcTime, zones, timezone);
                return {
                    zone: zone,
                    rule: findRule(utcTime, rules, zone[1])
                };
            }
            function offset(utcTime, timezone) {
                if (timezone == 'Etc/UTC' || timezone == 'Etc/GMT') {
                    return 0;
                }
                var info = zoneAndRule(utcTime, this.zones, this.rules, timezone);
                var zone = info.zone;
                var rule = info.rule;
                return kendo.parseFloat(rule ? zone[0] - rule[6] : zone[0]);
            }
            function abbr(utcTime, timezone) {
                var info = zoneAndRule(utcTime, this.zones, this.rules, timezone);
                var zone = info.zone;
                var rule = info.rule;
                var base = zone[2];
                if (base.indexOf('/') >= 0) {
                    return base.split('/')[rule && +rule[6] ? 1 : 0];
                } else if (base.indexOf('%s') >= 0) {
                    return base.replace('%s', !rule || rule[7] == '-' ? '' : rule[7]);
                }
                return base;
            }
            function convert(date, fromOffset, toOffset) {
                if (typeof fromOffset == STRING) {
                    fromOffset = this.offset(date, fromOffset);
                }
                if (typeof toOffset == STRING) {
                    toOffset = this.offset(date, toOffset);
                }
                var fromLocalOffset = date.getTimezoneOffset();
                date = new Date(date.getTime() + (fromOffset - toOffset) * 60000);
                var toLocalOffset = date.getTimezoneOffset();
                return new Date(date.getTime() + (toLocalOffset - fromLocalOffset) * 60000);
            }
            function apply(date, timezone) {
                return this.convert(date, date.getTimezoneOffset(), timezone);
            }
            function remove(date, timezone) {
                return this.convert(date, timezone, date.getTimezoneOffset());
            }
            function toLocalDate(time) {
                return this.apply(new Date(time), 'Etc/UTC');
            }
            return {
                zones: {},
                rules: {},
                offset: offset,
                convert: convert,
                apply: apply,
                remove: remove,
                abbr: abbr,
                toLocalDate: toLocalDate
            };
        }();
        kendo.date = function () {
            var MS_PER_MINUTE = 60000, MS_PER_DAY = 86400000;
            function adjustDST(date, hours) {
                if (hours === 0 && date.getHours() === 23) {
                    date.setHours(date.getHours() + 2);
                    return true;
                }
                return false;
            }
            function setDayOfWeek(date, day, dir) {
                var hours = date.getHours();
                dir = dir || 1;
                day = (day - date.getDay() + 7 * dir) % 7;
                date.setDate(date.getDate() + day);
                adjustDST(date, hours);
            }
            function dayOfWeek(date, day, dir) {
                date = new Date(date);
                setDayOfWeek(date, day, dir);
                return date;
            }
            function firstDayOfMonth(date) {
                return new Date(date.getFullYear(), date.getMonth(), 1);
            }
            function lastDayOfMonth(date) {
                var last = new Date(date.getFullYear(), date.getMonth() + 1, 0), first = firstDayOfMonth(date), timeOffset = Math.abs(last.getTimezoneOffset() - first.getTimezoneOffset());
                if (timeOffset) {
                    last.setHours(first.getHours() + timeOffset / 60);
                }
                return last;
            }
            function moveDateToWeekStart(date, weekStartDay) {
                if (weekStartDay !== 1) {
                    return addDays(dayOfWeek(date, weekStartDay, -1), 4);
                }
                return addDays(date, 4 - (date.getDay() || 7));
            }
            function calcWeekInYear(date, weekStartDay) {
                var firstWeekInYear = new Date(date.getFullYear(), 0, 1, -6);
                var newDate = moveDateToWeekStart(date, weekStartDay);
                var diffInMS = newDate.getTime() - firstWeekInYear.getTime();
                var days = Math.floor(diffInMS / MS_PER_DAY);
                return 1 + Math.floor(days / 7);
            }
            function weekInYear(date, weekStartDay) {
                var prevWeekDate = addDays(date, -7);
                var nextWeekDate = addDays(date, 7);
                var weekNumber = calcWeekInYear(date, weekStartDay);
                if (weekNumber === 0) {
                    return calcWeekInYear(prevWeekDate, weekStartDay) + 1;
                }
                if (weekNumber === 53 && calcWeekInYear(nextWeekDate, weekStartDay) > 1) {
                    return 1;
                }
                return weekNumber;
            }
            function getDate(date) {
                date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
                adjustDST(date, 0);
                return date;
            }
            function toUtcTime(date) {
                return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
            }
            function getMilliseconds(date) {
                return date.getTime() - getDate(date);
            }
            function isInTimeRange(value, min, max) {
                var msMin = getMilliseconds(min), msMax = getMilliseconds(max), msValue;
                if (!value || msMin == msMax) {
                    return true;
                }
                if (min >= max) {
                    max += MS_PER_DAY;
                }
                msValue = getMilliseconds(value);
                if (msMin > msValue) {
                    msValue += MS_PER_DAY;
                }
                if (msMax < msMin) {
                    msMax += MS_PER_DAY;
                }
                return msValue >= msMin && msValue <= msMax;
            }
            function isInDateRange(value, min, max) {
                var msMin = min.getTime(), msMax = max.getTime(), msValue;
                if (msMin >= msMax) {
                    msMax += MS_PER_DAY;
                }
                msValue = value.getTime();
                return msValue >= msMin && msValue <= msMax;
            }
            function addDays(date, offset) {
                var hours = date.getHours();
                date = new Date(date);
                setTime(date, offset * MS_PER_DAY);
                adjustDST(date, hours);
                return date;
            }
            function setTime(date, milliseconds, ignoreDST) {
                var offset = date.getTimezoneOffset();
                var difference;
                date.setTime(date.getTime() + milliseconds);
                if (!ignoreDST) {
                    difference = date.getTimezoneOffset() - offset;
                    date.setTime(date.getTime() + difference * MS_PER_MINUTE);
                }
            }
            function setHours(date, time) {
                date = new Date(kendo.date.getDate(date).getTime() + kendo.date.getMilliseconds(time));
                adjustDST(date, time.getHours());
                return date;
            }
            function today() {
                return getDate(new Date());
            }
            function isToday(date) {
                return getDate(date).getTime() == today().getTime();
            }
            function toInvariantTime(date) {
                var staticDate = new Date(1980, 1, 1, 0, 0, 0);
                if (date) {
                    staticDate.setHours(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
                }
                return staticDate;
            }
            return {
                adjustDST: adjustDST,
                dayOfWeek: dayOfWeek,
                setDayOfWeek: setDayOfWeek,
                getDate: getDate,
                isInDateRange: isInDateRange,
                isInTimeRange: isInTimeRange,
                isToday: isToday,
                nextDay: function (date) {
                    return addDays(date, 1);
                },
                previousDay: function (date) {
                    return addDays(date, -1);
                },
                toUtcTime: toUtcTime,
                MS_PER_DAY: MS_PER_DAY,
                MS_PER_HOUR: 60 * MS_PER_MINUTE,
                MS_PER_MINUTE: MS_PER_MINUTE,
                setTime: setTime,
                setHours: setHours,
                addDays: addDays,
                today: today,
                toInvariantTime: toInvariantTime,
                firstDayOfMonth: firstDayOfMonth,
                lastDayOfMonth: lastDayOfMonth,
                weekInYear: weekInYear,
                getMilliseconds: getMilliseconds
            };
        }();
        kendo.stripWhitespace = function (element) {
            if (document.createNodeIterator) {
                var iterator = document.createNodeIterator(element, NodeFilter.SHOW_TEXT, function (node) {
                    return node.parentNode == element ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
                }, false);
                while (iterator.nextNode()) {
                    if (iterator.referenceNode && !iterator.referenceNode.textContent.trim()) {
                        iterator.referenceNode.parentNode.removeChild(iterator.referenceNode);
                    }
                }
            } else {
                for (var i = 0; i < element.childNodes.length; i++) {
                    var child = element.childNodes[i];
                    if (child.nodeType == 3 && !/\S/.test(child.nodeValue)) {
                        element.removeChild(child);
                        i--;
                    }
                    if (child.nodeType == 1) {
                        kendo.stripWhitespace(child);
                    }
                }
            }
        };
        var animationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
            setTimeout(callback, 1000 / 60);
        };
        kendo.animationFrame = function (callback) {
            animationFrame.call(window, callback);
        };
        var animationQueue = [];
        kendo.queueAnimation = function (callback) {
            animationQueue[animationQueue.length] = callback;
            if (animationQueue.length === 1) {
                kendo.runNextAnimation();
            }
        };
        kendo.runNextAnimation = function () {
            kendo.animationFrame(function () {
                if (animationQueue[0]) {
                    animationQueue.shift()();
                    if (animationQueue[0]) {
                        kendo.runNextAnimation();
                    }
                }
            });
        };
        kendo.parseQueryStringParams = function (url) {
            var queryString = url.split('?')[1] || '', params = {}, paramParts = queryString.split(/&|=/), length = paramParts.length, idx = 0;
            for (; idx < length; idx += 2) {
                if (paramParts[idx] !== '') {
                    params[decodeURIComponent(paramParts[idx])] = decodeURIComponent(paramParts[idx + 1]);
                }
            }
            return params;
        };
        kendo.elementUnderCursor = function (e) {
            if (typeof e.x.client != 'undefined') {
                return document.elementFromPoint(e.x.client, e.y.client);
            }
        };
        kendo.wheelDeltaY = function (jQueryEvent) {
            var e = jQueryEvent.originalEvent, deltaY = e.wheelDeltaY, delta;
            if (e.wheelDelta) {
                if (deltaY === undefined || deltaY) {
                    delta = e.wheelDelta;
                }
            } else if (e.detail && e.axis === e.VERTICAL_AXIS) {
                delta = -e.detail * 10;
            }
            return delta;
        };
        kendo.throttle = function (fn, delay) {
            var timeout;
            var lastExecTime = 0;
            if (!delay || delay <= 0) {
                return fn;
            }
            var throttled = function () {
                var that = this;
                var elapsed = +new Date() - lastExecTime;
                var args = arguments;
                function exec() {
                    fn.apply(that, args);
                    lastExecTime = +new Date();
                }
                if (!lastExecTime) {
                    return exec();
                }
                if (timeout) {
                    clearTimeout(timeout);
                }
                if (elapsed > delay) {
                    exec();
                } else {
                    timeout = setTimeout(exec, delay - elapsed);
                }
            };
            throttled.cancel = function () {
                clearTimeout(timeout);
            };
            return throttled;
        };
        kendo.caret = function (element, start, end) {
            var rangeElement;
            var isPosition = start !== undefined;
            if (end === undefined) {
                end = start;
            }
            if (element[0]) {
                element = element[0];
            }
            if (isPosition && element.disabled) {
                return;
            }
            try {
                if (element.selectionStart !== undefined) {
                    if (isPosition) {
                        element.focus();
                        var mobile = support.mobileOS;
                        if (mobile.wp || mobile.android) {
                            setTimeout(function () {
                                element.setSelectionRange(start, end);
                            }, 0);
                        } else {
                            element.setSelectionRange(start, end);
                        }
                    } else {
                        start = [
                            element.selectionStart,
                            element.selectionEnd
                        ];
                    }
                } else if (document.selection) {
                    if ($(element).is(':visible')) {
                        element.focus();
                    }
                    rangeElement = element.createTextRange();
                    if (isPosition) {
                        rangeElement.collapse(true);
                        rangeElement.moveStart('character', start);
                        rangeElement.moveEnd('character', end - start);
                        rangeElement.select();
                    } else {
                        var rangeDuplicated = rangeElement.duplicate(), selectionStart, selectionEnd;
                        rangeElement.moveToBookmark(document.selection.createRange().getBookmark());
                        rangeDuplicated.setEndPoint('EndToStart', rangeElement);
                        selectionStart = rangeDuplicated.text.length;
                        selectionEnd = selectionStart + rangeElement.text.length;
                        start = [
                            selectionStart,
                            selectionEnd
                        ];
                    }
                }
            } catch (e) {
                start = [];
            }
            return start;
        };
        kendo.compileMobileDirective = function (element, scope) {
            var angular = window.angular;
            element.attr('data-' + kendo.ns + 'role', element[0].tagName.toLowerCase().replace('kendo-mobile-', '').replace('-', ''));
            angular.element(element).injector().invoke([
                '$compile',
                function ($compile) {
                    $compile(element)(scope);
                    if (!/^\$(digest|apply)$/.test(scope.$$phase)) {
                        scope.$digest();
                    }
                }
            ]);
            return kendo.widgetInstance(element, kendo.mobile.ui);
        };
        kendo.antiForgeryTokens = function () {
            var tokens = {}, csrf_token = $('meta[name=csrf-token],meta[name=_csrf]').attr('content'), csrf_param = $('meta[name=csrf-param],meta[name=_csrf_header]').attr('content');
            $('input[name^=\'__RequestVerificationToken\']').each(function () {
                tokens[this.name] = this.value;
            });
            if (csrf_param !== undefined && csrf_token !== undefined) {
                tokens[csrf_param] = csrf_token;
            }
            return tokens;
        };
        kendo.cycleForm = function (form) {
            var firstElement = form.find('input, .k-widget').first();
            var lastElement = form.find('button, .k-button').last();
            function focus(el) {
                var widget = kendo.widgetInstance(el);
                if (widget && widget.focus) {
                    widget.focus();
                } else {
                    el.focus();
                }
            }
            lastElement.on('keydown', function (e) {
                if (e.keyCode == kendo.keys.TAB && !e.shiftKey) {
                    e.preventDefault();
                    focus(firstElement);
                }
            });
            firstElement.on('keydown', function (e) {
                if (e.keyCode == kendo.keys.TAB && e.shiftKey) {
                    e.preventDefault();
                    focus(lastElement);
                }
            });
        };
        (function () {
            function postToProxy(dataURI, fileName, proxyURL, proxyTarget) {
                var form = $('<form>').attr({
                    action: proxyURL,
                    method: 'POST',
                    target: proxyTarget
                });
                var data = kendo.antiForgeryTokens();
                data.fileName = fileName;
                var parts = dataURI.split(';base64,');
                data.contentType = parts[0].replace('data:', '');
                data.base64 = parts[1];
                for (var name in data) {
                    if (data.hasOwnProperty(name)) {
                        $('<input>').attr({
                            value: data[name],
                            name: name,
                            type: 'hidden'
                        }).appendTo(form);
                    }
                }
                form.appendTo('body').submit().remove();
            }
            var fileSaver = document.createElement('a');
            var downloadAttribute = 'download' in fileSaver && !kendo.support.browser.edge;
            function saveAsBlob(dataURI, fileName) {
                var blob = dataURI;
                if (typeof dataURI == 'string') {
                    var parts = dataURI.split(';base64,');
                    var contentType = parts[0];
                    var base64 = atob(parts[1]);
                    var array = new Uint8Array(base64.length);
                    for (var idx = 0; idx < base64.length; idx++) {
                        array[idx] = base64.charCodeAt(idx);
                    }
                    blob = new Blob([array.buffer], { type: contentType });
                }
                navigator.msSaveBlob(blob, fileName);
            }
            function saveAsDataURI(dataURI, fileName) {
                if (window.Blob && dataURI instanceof Blob) {
                    dataURI = URL.createObjectURL(dataURI);
                }
                fileSaver.download = fileName;
                fileSaver.href = dataURI;
                var e = document.createEvent('MouseEvents');
                e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                fileSaver.dispatchEvent(e);
                setTimeout(function () {
                    URL.revokeObjectURL(dataURI);
                });
            }
            kendo.saveAs = function (options) {
                var save = postToProxy;
                if (!options.forceProxy) {
                    if (downloadAttribute) {
                        save = saveAsDataURI;
                    } else if (navigator.msSaveBlob) {
                        save = saveAsBlob;
                    }
                }
                save(options.dataURI, options.fileName, options.proxyURL, options.proxyTarget);
            };
        }());
        kendo.proxyModelSetters = function proxyModelSetters(data) {
            var observable = {};
            Object.keys(data || {}).forEach(function (property) {
                Object.defineProperty(observable, property, {
                    get: function () {
                        return data[property];
                    },
                    set: function (value) {
                        data[property] = value;
                        data.dirty = true;
                    }
                });
            });
            return observable;
        };
    }(jQuery, window));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.router', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'router',
        name: 'Router',
        category: 'framework',
        description: 'The Router class is responsible for tracking the application state and navigating between the application states.',
        depends: ['core'],
        hidden: false
    };
    (function ($, undefined) {
        var kendo = window.kendo, CHANGE = 'change', BACK = 'back', SAME = 'same', support = kendo.support, location = window.location, history = window.history, CHECK_URL_INTERVAL = 50, BROKEN_BACK_NAV = kendo.support.browser.msie, hashStrip = /^#*/, document = window.document;
        function absoluteURL(path, pathPrefix) {
            if (!pathPrefix) {
                return path;
            }
            if (path + '/' === pathPrefix) {
                path = pathPrefix;
            }
            var regEx = new RegExp('^' + pathPrefix, 'i');
            if (!regEx.test(path)) {
                path = pathPrefix + '/' + path;
            }
            return location.protocol + '//' + (location.host + '/' + path).replace(/\/\/+/g, '/');
        }
        function hashDelimiter(bang) {
            return bang ? '#!' : '#';
        }
        function locationHash(hashDelimiter) {
            var href = location.href;
            if (hashDelimiter === '#!' && href.indexOf('#') > -1 && href.indexOf('#!') < 0) {
                return null;
            }
            return href.split(hashDelimiter)[1] || '';
        }
        function stripRoot(root, url) {
            if (url.indexOf(root) === 0) {
                return url.substr(root.length).replace(/\/\//g, '/');
            } else {
                return url;
            }
        }
        var HistoryAdapter = kendo.Class.extend({
            back: function () {
                if (BROKEN_BACK_NAV) {
                    setTimeout(function () {
                        history.back();
                    });
                } else {
                    history.back();
                }
            },
            forward: function () {
                if (BROKEN_BACK_NAV) {
                    setTimeout(function () {
                        history.forward();
                    });
                } else {
                    history.forward();
                }
            },
            length: function () {
                return history.length;
            },
            replaceLocation: function (url) {
                location.replace(url);
            }
        });
        var PushStateAdapter = HistoryAdapter.extend({
            init: function (root) {
                this.root = root;
            },
            navigate: function (to) {
                history.pushState({}, document.title, absoluteURL(to, this.root));
            },
            replace: function (to) {
                history.replaceState({}, document.title, absoluteURL(to, this.root));
            },
            normalize: function (url) {
                return stripRoot(this.root, url);
            },
            current: function () {
                var current = location.pathname;
                if (location.search) {
                    current += location.search;
                }
                return stripRoot(this.root, current);
            },
            change: function (callback) {
                $(window).bind('popstate.kendo', callback);
            },
            stop: function () {
                $(window).unbind('popstate.kendo');
            },
            normalizeCurrent: function (options) {
                var fixedUrl, root = options.root, pathname = location.pathname, hash = locationHash(hashDelimiter(options.hashBang));
                if (root === pathname + '/') {
                    fixedUrl = root;
                }
                if (root === pathname && hash) {
                    fixedUrl = absoluteURL(hash.replace(hashStrip, ''), root);
                }
                if (fixedUrl) {
                    history.pushState({}, document.title, fixedUrl);
                }
            }
        });
        function fixHash(url) {
            return url.replace(/^(#)?/, '#');
        }
        function fixBang(url) {
            return url.replace(/^(#(!)?)?/, '#!');
        }
        var HashAdapter = HistoryAdapter.extend({
            init: function (bang) {
                this._id = kendo.guid();
                this.prefix = hashDelimiter(bang);
                this.fix = bang ? fixBang : fixHash;
            },
            navigate: function (to) {
                location.hash = this.fix(to);
            },
            replace: function (to) {
                this.replaceLocation(this.fix(to));
            },
            normalize: function (url) {
                if (url.indexOf(this.prefix) < 0) {
                    return url;
                } else {
                    return url.split(this.prefix)[1];
                }
            },
            change: function (callback) {
                if (support.hashChange) {
                    $(window).on('hashchange.' + this._id, callback);
                } else {
                    this._interval = setInterval(callback, CHECK_URL_INTERVAL);
                }
            },
            stop: function () {
                $(window).off('hashchange.' + this._id);
                clearInterval(this._interval);
            },
            current: function () {
                return locationHash(this.prefix);
            },
            normalizeCurrent: function (options) {
                var pathname = location.pathname, root = options.root;
                if (options.pushState && root !== pathname) {
                    this.replaceLocation(root + this.prefix + stripRoot(root, pathname));
                    return true;
                }
                return false;
            }
        });
        var History = kendo.Observable.extend({
            start: function (options) {
                options = options || {};
                this.bind([
                    CHANGE,
                    BACK,
                    SAME
                ], options);
                if (this._started) {
                    return;
                }
                this._started = true;
                options.root = options.root || '/';
                var adapter = this.createAdapter(options), current;
                if (adapter.normalizeCurrent(options)) {
                    return;
                }
                current = adapter.current();
                $.extend(this, {
                    adapter: adapter,
                    root: options.root,
                    historyLength: adapter.length(),
                    current: current,
                    locations: [current]
                });
                adapter.change($.proxy(this, '_checkUrl'));
            },
            createAdapter: function (options) {
                return support.pushState && options.pushState ? new PushStateAdapter(options.root) : new HashAdapter(options.hashBang);
            },
            stop: function () {
                if (!this._started) {
                    return;
                }
                this.adapter.stop();
                this.unbind(CHANGE);
                this._started = false;
            },
            change: function (callback) {
                this.bind(CHANGE, callback);
            },
            replace: function (to, silent) {
                this._navigate(to, silent, function (adapter) {
                    adapter.replace(to);
                    this.locations[this.locations.length - 1] = this.current;
                });
            },
            navigate: function (to, silent) {
                if (to === '#:back') {
                    this.backCalled = true;
                    this.adapter.back();
                    return;
                }
                this._navigate(to, silent, function (adapter) {
                    adapter.navigate(to);
                    this.locations.push(this.current);
                });
            },
            _navigate: function (to, silent, callback) {
                var adapter = this.adapter;
                to = adapter.normalize(to);
                if (this.current === to || this.current === decodeURIComponent(to)) {
                    this.trigger(SAME);
                    return;
                }
                if (!silent) {
                    if (this.trigger(CHANGE, {
                            url: to,
                            decode: false
                        })) {
                        return;
                    }
                }
                this.current = to;
                callback.call(this, adapter);
                this.historyLength = adapter.length();
            },
            _checkUrl: function () {
                var adapter = this.adapter, current = adapter.current(), newLength = adapter.length(), navigatingInExisting = this.historyLength === newLength, back = current === this.locations[this.locations.length - 2] && navigatingInExisting, backCalled = this.backCalled, prev = this.current;
                if (current === null || this.current === current || this.current === decodeURIComponent(current)) {
                    return true;
                }
                this.historyLength = newLength;
                this.backCalled = false;
                this.current = current;
                if (back && this.trigger('back', {
                        url: prev,
                        to: current
                    })) {
                    adapter.forward();
                    this.current = prev;
                    return;
                }
                if (this.trigger(CHANGE, {
                        url: current,
                        backButtonPressed: !backCalled
                    })) {
                    if (back) {
                        adapter.forward();
                    } else {
                        adapter.back();
                        this.historyLength--;
                    }
                    this.current = prev;
                    return;
                }
                if (back) {
                    this.locations.pop();
                } else {
                    this.locations.push(current);
                }
            }
        });
        kendo.History = History;
        kendo.History.HistoryAdapter = HistoryAdapter;
        kendo.History.HashAdapter = HashAdapter;
        kendo.History.PushStateAdapter = PushStateAdapter;
        kendo.absoluteURL = absoluteURL;
        kendo.history = new History();
    }(window.kendo.jQuery));
    (function () {
        var kendo = window.kendo, history = kendo.history, Observable = kendo.Observable, INIT = 'init', ROUTE_MISSING = 'routeMissing', CHANGE = 'change', BACK = 'back', SAME = 'same', optionalParam = /\((.*?)\)/g, namedParam = /(\(\?)?:\w+/g, splatParam = /\*\w+/g, escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
        function namedParamReplace(match, optional) {
            return optional ? match : '([^/]+)';
        }
        function routeToRegExp(route, ignoreCase) {
            return new RegExp('^' + route.replace(escapeRegExp, '\\$&').replace(optionalParam, '(?:$1)?').replace(namedParam, namedParamReplace).replace(splatParam, '(.*?)') + '$', ignoreCase ? 'i' : '');
        }
        function stripUrl(url) {
            return url.replace(/(\?.*)|(#.*)/g, '');
        }
        var Route = kendo.Class.extend({
            init: function (route, callback, ignoreCase) {
                if (!(route instanceof RegExp)) {
                    route = routeToRegExp(route, ignoreCase);
                }
                this.route = route;
                this._callback = callback;
            },
            callback: function (url, back, decode) {
                var params, idx = 0, length, queryStringParams = kendo.parseQueryStringParams(url);
                queryStringParams._back = back;
                url = stripUrl(url);
                params = this.route.exec(url).slice(1);
                length = params.length;
                if (decode) {
                    for (; idx < length; idx++) {
                        if (typeof params[idx] !== 'undefined') {
                            params[idx] = decodeURIComponent(params[idx]);
                        }
                    }
                }
                params.push(queryStringParams);
                this._callback.apply(null, params);
            },
            worksWith: function (url, back, decode) {
                if (this.route.test(stripUrl(url))) {
                    this.callback(url, back, decode);
                    return true;
                } else {
                    return false;
                }
            }
        });
        var Router = Observable.extend({
            init: function (options) {
                if (!options) {
                    options = {};
                }
                Observable.fn.init.call(this);
                this.routes = [];
                this.pushState = options.pushState;
                this.hashBang = options.hashBang;
                this.root = options.root;
                this.ignoreCase = options.ignoreCase !== false;
                this.bind([
                    INIT,
                    ROUTE_MISSING,
                    CHANGE,
                    SAME
                ], options);
            },
            destroy: function () {
                history.unbind(CHANGE, this._urlChangedProxy);
                history.unbind(SAME, this._sameProxy);
                history.unbind(BACK, this._backProxy);
                this.unbind();
            },
            start: function () {
                var that = this, sameProxy = function () {
                        that._same();
                    }, backProxy = function (e) {
                        that._back(e);
                    }, urlChangedProxy = function (e) {
                        that._urlChanged(e);
                    };
                history.start({
                    same: sameProxy,
                    change: urlChangedProxy,
                    back: backProxy,
                    pushState: that.pushState,
                    hashBang: that.hashBang,
                    root: that.root
                });
                var initEventObject = {
                    url: history.current || '/',
                    preventDefault: $.noop
                };
                if (!that.trigger(INIT, initEventObject)) {
                    that._urlChanged(initEventObject);
                }
                this._urlChangedProxy = urlChangedProxy;
                this._backProxy = backProxy;
            },
            route: function (route, callback) {
                this.routes.push(new Route(route, callback, this.ignoreCase));
            },
            navigate: function (url, silent) {
                kendo.history.navigate(url, silent);
            },
            replace: function (url, silent) {
                kendo.history.replace(url, silent);
            },
            _back: function (e) {
                if (this.trigger(BACK, {
                        url: e.url,
                        to: e.to
                    })) {
                    e.preventDefault();
                }
            },
            _same: function () {
                this.trigger(SAME);
            },
            _urlChanged: function (e) {
                var url = e.url;
                var decode = typeof e.decode === 'undefined';
                var back = e.backButtonPressed;
                if (!url) {
                    url = '/';
                }
                if (this.trigger(CHANGE, {
                        url: e.url,
                        params: kendo.parseQueryStringParams(e.url),
                        backButtonPressed: back
                    })) {
                    e.preventDefault();
                    return;
                }
                var idx = 0, routes = this.routes, route, length = routes.length;
                for (; idx < length; idx++) {
                    route = routes[idx];
                    if (route.worksWith(url, back, decode)) {
                        return;
                    }
                }
                if (this.trigger(ROUTE_MISSING, {
                        url: url,
                        params: kendo.parseQueryStringParams(url),
                        backButtonPressed: back
                    })) {
                    e.preventDefault();
                }
            }
        });
        kendo.Router = Router;
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.data.odata', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'data.odata',
        name: 'OData',
        category: 'framework',
        depends: ['core'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, odataFilters = {
                eq: 'eq',
                neq: 'ne',
                gt: 'gt',
                gte: 'ge',
                lt: 'lt',
                lte: 'le',
                contains: 'substringof',
                doesnotcontain: 'substringof',
                endswith: 'endswith',
                startswith: 'startswith',
                isnull: 'eq',
                isnotnull: 'ne',
                isempty: 'eq',
                isnotempty: 'ne'
            }, odataFiltersVersionFour = extend({}, odataFilters, { contains: 'contains' }), mappers = {
                pageSize: $.noop,
                page: $.noop,
                filter: function (params, filter, useVersionFour) {
                    if (filter) {
                        filter = toOdataFilter(filter, useVersionFour);
                        if (filter) {
                            params.$filter = filter;
                        }
                    }
                },
                sort: function (params, orderby) {
                    var expr = $.map(orderby, function (value) {
                        var order = value.field.replace(/\./g, '/');
                        if (value.dir === 'desc') {
                            order += ' desc';
                        }
                        return order;
                    }).join(',');
                    if (expr) {
                        params.$orderby = expr;
                    }
                },
                skip: function (params, skip) {
                    if (skip) {
                        params.$skip = skip;
                    }
                },
                take: function (params, take) {
                    if (take) {
                        params.$top = take;
                    }
                }
            }, defaultDataType = { read: { dataType: 'jsonp' } };
        function toOdataFilter(filter, useOdataFour) {
            var result = [], logic = filter.logic || 'and', idx, length, field, type, format, operator, value, ignoreCase, filters = filter.filters;
            for (idx = 0, length = filters.length; idx < length; idx++) {
                filter = filters[idx];
                field = filter.field;
                value = filter.value;
                operator = filter.operator;
                if (filter.filters) {
                    filter = toOdataFilter(filter, useOdataFour);
                } else {
                    ignoreCase = filter.ignoreCase;
                    field = field.replace(/\./g, '/');
                    filter = odataFilters[operator];
                    if (useOdataFour) {
                        filter = odataFiltersVersionFour[operator];
                    }
                    if (operator === 'isnull' || operator === 'isnotnull') {
                        filter = kendo.format('{0} {1} null', field, filter);
                    } else if (operator === 'isempty' || operator === 'isnotempty') {
                        filter = kendo.format('{0} {1} \'\'', field, filter);
                    } else if (filter && value !== undefined) {
                        type = $.type(value);
                        if (type === 'string') {
                            format = '\'{1}\'';
                            value = value.replace(/'/g, '\'\'');
                            if (ignoreCase === true) {
                                field = 'tolower(' + field + ')';
                            }
                        } else if (type === 'date') {
                            if (useOdataFour) {
                                format = '{1:yyyy-MM-ddTHH:mm:ss+00:00}';
                                value = kendo.timezone.apply(value, 'Etc/UTC');
                            } else {
                                format = 'datetime\'{1:yyyy-MM-ddTHH:mm:ss}\'';
                            }
                        } else {
                            format = '{1}';
                        }
                        if (filter.length > 3) {
                            if (filter !== 'substringof') {
                                format = '{0}({2},' + format + ')';
                            } else {
                                format = '{0}(' + format + ',{2})';
                                if (operator === 'doesnotcontain') {
                                    if (useOdataFour) {
                                        format = '{0}({2},\'{1}\') eq -1';
                                        filter = 'indexof';
                                    } else {
                                        format += ' eq false';
                                    }
                                }
                            }
                        } else {
                            format = '{2} {0} ' + format;
                        }
                        filter = kendo.format(format, filter, value, field);
                    }
                }
                result.push(filter);
            }
            filter = result.join(' ' + logic + ' ');
            if (result.length > 1) {
                filter = '(' + filter + ')';
            }
            return filter;
        }
        function stripMetadata(obj) {
            for (var name in obj) {
                if (name.indexOf('@odata') === 0) {
                    delete obj[name];
                }
            }
        }
        extend(true, kendo.data, {
            schemas: {
                odata: {
                    type: 'json',
                    data: function (data) {
                        return data.d.results || [data.d];
                    },
                    total: 'd.__count'
                }
            },
            transports: {
                odata: {
                    read: {
                        cache: true,
                        dataType: 'jsonp',
                        jsonp: '$callback'
                    },
                    update: {
                        cache: true,
                        dataType: 'json',
                        contentType: 'application/json',
                        type: 'PUT'
                    },
                    create: {
                        cache: true,
                        dataType: 'json',
                        contentType: 'application/json',
                        type: 'POST'
                    },
                    destroy: {
                        cache: true,
                        dataType: 'json',
                        type: 'DELETE'
                    },
                    parameterMap: function (options, type, useVersionFour) {
                        var params, value, option, dataType;
                        options = options || {};
                        type = type || 'read';
                        dataType = (this.options || defaultDataType)[type];
                        dataType = dataType ? dataType.dataType : 'json';
                        if (type === 'read') {
                            params = { $inlinecount: 'allpages' };
                            if (dataType != 'json') {
                                params.$format = 'json';
                            }
                            for (option in options) {
                                if (mappers[option]) {
                                    mappers[option](params, options[option], useVersionFour);
                                } else {
                                    params[option] = options[option];
                                }
                            }
                        } else {
                            if (dataType !== 'json') {
                                throw new Error('Only json dataType can be used for ' + type + ' operation.');
                            }
                            if (type !== 'destroy') {
                                for (option in options) {
                                    value = options[option];
                                    if (typeof value === 'number') {
                                        options[option] = value + '';
                                    }
                                }
                                params = kendo.stringify(options);
                            }
                        }
                        return params;
                    }
                }
            }
        });
        extend(true, kendo.data, {
            schemas: {
                'odata-v4': {
                    type: 'json',
                    data: function (data) {
                        data = $.extend({}, data);
                        stripMetadata(data);
                        if (data.value) {
                            return data.value;
                        }
                        return [data];
                    },
                    total: function (data) {
                        return data['@odata.count'];
                    }
                }
            },
            transports: {
                'odata-v4': {
                    read: {
                        cache: true,
                        dataType: 'json'
                    },
                    update: {
                        cache: true,
                        dataType: 'json',
                        contentType: 'application/json;IEEE754Compatible=true',
                        type: 'PUT'
                    },
                    create: {
                        cache: true,
                        dataType: 'json',
                        contentType: 'application/json;IEEE754Compatible=true',
                        type: 'POST'
                    },
                    destroy: {
                        cache: true,
                        dataType: 'json',
                        type: 'DELETE'
                    },
                    parameterMap: function (options, type) {
                        var result = kendo.data.transports.odata.parameterMap(options, type, true);
                        if (type == 'read') {
                            result.$count = true;
                            delete result.$inlinecount;
                        }
                        return result;
                    }
                }
            }
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.data.xml', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'data.xml',
        name: 'XML',
        category: 'framework',
        depends: ['core'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, isArray = $.isArray, isPlainObject = $.isPlainObject, map = $.map, each = $.each, extend = $.extend, getter = kendo.getter, Class = kendo.Class;
        var XmlDataReader = Class.extend({
            init: function (options) {
                var that = this, total = options.total, model = options.model, parse = options.parse, errors = options.errors, serialize = options.serialize, data = options.data;
                if (model) {
                    if (isPlainObject(model)) {
                        var base = options.modelBase || kendo.data.Model;
                        if (model.fields) {
                            each(model.fields, function (field, value) {
                                if (isPlainObject(value) && value.field) {
                                    if (!$.isFunction(value.field)) {
                                        value = extend(value, { field: that.getter(value.field) });
                                    }
                                } else {
                                    value = { field: that.getter(value) };
                                }
                                model.fields[field] = value;
                            });
                        }
                        var id = model.id;
                        if (id) {
                            var idField = {};
                            idField[that.xpathToMember(id, true)] = { field: that.getter(id) };
                            model.fields = extend(idField, model.fields);
                            model.id = that.xpathToMember(id);
                        }
                        model = base.define(model);
                    }
                    that.model = model;
                }
                if (total) {
                    if (typeof total == 'string') {
                        total = that.getter(total);
                        that.total = function (data) {
                            return parseInt(total(data), 10);
                        };
                    } else if (typeof total == 'function') {
                        that.total = total;
                    }
                }
                if (errors) {
                    if (typeof errors == 'string') {
                        errors = that.getter(errors);
                        that.errors = function (data) {
                            return errors(data) || null;
                        };
                    } else if (typeof errors == 'function') {
                        that.errors = errors;
                    }
                }
                if (data) {
                    if (typeof data == 'string') {
                        data = that.xpathToMember(data);
                        that.data = function (value) {
                            var result = that.evaluate(value, data), modelInstance;
                            result = isArray(result) ? result : [result];
                            if (that.model && model.fields) {
                                modelInstance = new that.model();
                                return map(result, function (value) {
                                    if (value) {
                                        var record = {}, field;
                                        for (field in model.fields) {
                                            record[field] = modelInstance._parse(field, model.fields[field].field(value));
                                        }
                                        return record;
                                    }
                                });
                            }
                            return result;
                        };
                    } else if (typeof data == 'function') {
                        that.data = data;
                    }
                }
                if (typeof parse == 'function') {
                    var xmlParse = that.parse;
                    that.parse = function (data) {
                        var xml = parse.call(that, data);
                        return xmlParse.call(that, xml);
                    };
                }
                if (typeof serialize == 'function') {
                    that.serialize = serialize;
                }
            },
            total: function (result) {
                return this.data(result).length;
            },
            errors: function (data) {
                return data ? data.errors : null;
            },
            serialize: function (data) {
                return data;
            },
            parseDOM: function (element) {
                var result = {}, parsedNode, node, nodeType, nodeName, member, attribute, attributes = element.attributes, attributeCount = attributes.length, idx;
                for (idx = 0; idx < attributeCount; idx++) {
                    attribute = attributes[idx];
                    result['@' + attribute.nodeName] = attribute.nodeValue;
                }
                for (node = element.firstChild; node; node = node.nextSibling) {
                    nodeType = node.nodeType;
                    if (nodeType === 3 || nodeType === 4) {
                        result['#text'] = node.nodeValue;
                    } else if (nodeType === 1) {
                        parsedNode = this.parseDOM(node);
                        nodeName = node.nodeName;
                        member = result[nodeName];
                        if (isArray(member)) {
                            member.push(parsedNode);
                        } else if (member !== undefined) {
                            member = [
                                member,
                                parsedNode
                            ];
                        } else {
                            member = parsedNode;
                        }
                        result[nodeName] = member;
                    }
                }
                return result;
            },
            evaluate: function (value, expression) {
                var members = expression.split('.'), member, result, length, intermediateResult, idx;
                while (member = members.shift()) {
                    value = value[member];
                    if (isArray(value)) {
                        result = [];
                        expression = members.join('.');
                        for (idx = 0, length = value.length; idx < length; idx++) {
                            intermediateResult = this.evaluate(value[idx], expression);
                            intermediateResult = isArray(intermediateResult) ? intermediateResult : [intermediateResult];
                            result.push.apply(result, intermediateResult);
                        }
                        return result;
                    }
                }
                return value;
            },
            parse: function (xml) {
                var documentElement, tree, result = {};
                documentElement = xml.documentElement || $.parseXML(xml).documentElement;
                tree = this.parseDOM(documentElement);
                result[documentElement.nodeName] = tree;
                return result;
            },
            xpathToMember: function (member, raw) {
                if (!member) {
                    return '';
                }
                member = member.replace(/^\//, '').replace(/\//g, '.');
                if (member.indexOf('@') >= 0) {
                    return member.replace(/\.?(@.*)/, raw ? '$1' : '["$1"]');
                }
                if (member.indexOf('text()') >= 0) {
                    return member.replace(/(\.?text\(\))/, raw ? '#text' : '["#text"]');
                }
                return member;
            },
            getter: function (member) {
                return getter(this.xpathToMember(member), true);
            }
        });
        $.extend(true, kendo.data, {
            XmlDataReader: XmlDataReader,
            readers: { xml: XmlDataReader }
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.data', [
        'kendo.core',
        'kendo.data.odata',
        'kendo.data.xml'
    ], f);
}(function () {
    var __meta__ = {
        id: 'data',
        name: 'Data source',
        category: 'framework',
        description: 'Powerful component for using local and remote data.Fully supports CRUD, Sorting, Paging, Filtering, Grouping, and Aggregates.',
        depends: ['core'],
        features: [
            {
                id: 'data-odata',
                name: 'OData',
                description: 'Support for accessing Open Data Protocol (OData) services.',
                depends: ['data.odata']
            },
            {
                id: 'data-signalr',
                name: 'SignalR',
                description: 'Support for binding to SignalR hubs.',
                depends: ['data.signalr']
            },
            {
                id: 'data-XML',
                name: 'XML',
                description: 'Support for binding to XML.',
                depends: ['data.xml']
            }
        ]
    };
    (function ($, undefined) {
        var extend = $.extend, proxy = $.proxy, isPlainObject = $.isPlainObject, isEmptyObject = $.isEmptyObject, isArray = $.isArray, grep = $.grep, ajax = $.ajax, map, each = $.each, noop = $.noop, kendo = window.kendo, isFunction = kendo.isFunction, Observable = kendo.Observable, Class = kendo.Class, STRING = 'string', FUNCTION = 'function', CREATE = 'create', READ = 'read', UPDATE = 'update', DESTROY = 'destroy', CHANGE = 'change', SYNC = 'sync', GET = 'get', ERROR = 'error', REQUESTSTART = 'requestStart', PROGRESS = 'progress', REQUESTEND = 'requestEnd', crud = [
                CREATE,
                READ,
                UPDATE,
                DESTROY
            ], identity = function (o) {
                return o;
            }, getter = kendo.getter, stringify = kendo.stringify, math = Math, push = [].push, join = [].join, pop = [].pop, splice = [].splice, shift = [].shift, slice = [].slice, unshift = [].unshift, toString = {}.toString, stableSort = kendo.support.stableSort, dateRegExp = /^\/Date\((.*?)\)\/$/;
        var ObservableArray = Observable.extend({
            init: function (array, type) {
                var that = this;
                that.type = type || ObservableObject;
                Observable.fn.init.call(that);
                that.length = array.length;
                that.wrapAll(array, that);
            },
            at: function (index) {
                return this[index];
            },
            toJSON: function () {
                var idx, length = this.length, value, json = new Array(length);
                for (idx = 0; idx < length; idx++) {
                    value = this[idx];
                    if (value instanceof ObservableObject) {
                        value = value.toJSON();
                    }
                    json[idx] = value;
                }
                return json;
            },
            parent: noop,
            wrapAll: function (source, target) {
                var that = this, idx, length, parent = function () {
                        return that;
                    };
                target = target || [];
                for (idx = 0, length = source.length; idx < length; idx++) {
                    target[idx] = that.wrap(source[idx], parent);
                }
                return target;
            },
            wrap: function (object, parent) {
                var that = this, observable;
                if (object !== null && toString.call(object) === '[object Object]') {
                    observable = object instanceof that.type || object instanceof Model;
                    if (!observable) {
                        object = object instanceof ObservableObject ? object.toJSON() : object;
                        object = new that.type(object);
                    }
                    object.parent = parent;
                    object.bind(CHANGE, function (e) {
                        that.trigger(CHANGE, {
                            field: e.field,
                            node: e.node,
                            index: e.index,
                            items: e.items || [this],
                            action: e.node ? e.action || 'itemloaded' : 'itemchange'
                        });
                    });
                }
                return object;
            },
            push: function () {
                var index = this.length, items = this.wrapAll(arguments), result;
                result = push.apply(this, items);
                this.trigger(CHANGE, {
                    action: 'add',
                    index: index,
                    items: items
                });
                return result;
            },
            slice: slice,
            sort: [].sort,
            join: join,
            pop: function () {
                var length = this.length, result = pop.apply(this);
                if (length) {
                    this.trigger(CHANGE, {
                        action: 'remove',
                        index: length - 1,
                        items: [result]
                    });
                }
                return result;
            },
            splice: function (index, howMany, item) {
                var items = this.wrapAll(slice.call(arguments, 2)), result, i, len;
                result = splice.apply(this, [
                    index,
                    howMany
                ].concat(items));
                if (result.length) {
                    this.trigger(CHANGE, {
                        action: 'remove',
                        index: index,
                        items: result
                    });
                    for (i = 0, len = result.length; i < len; i++) {
                        if (result[i] && result[i].children) {
                            result[i].unbind(CHANGE);
                        }
                    }
                }
                if (item) {
                    this.trigger(CHANGE, {
                        action: 'add',
                        index: index,
                        items: items
                    });
                }
                return result;
            },
            shift: function () {
                var length = this.length, result = shift.apply(this);
                if (length) {
                    this.trigger(CHANGE, {
                        action: 'remove',
                        index: 0,
                        items: [result]
                    });
                }
                return result;
            },
            unshift: function () {
                var items = this.wrapAll(arguments), result;
                result = unshift.apply(this, items);
                this.trigger(CHANGE, {
                    action: 'add',
                    index: 0,
                    items: items
                });
                return result;
            },
            indexOf: function (item) {
                var that = this, idx, length;
                for (idx = 0, length = that.length; idx < length; idx++) {
                    if (that[idx] === item) {
                        return idx;
                    }
                }
                return -1;
            },
            forEach: function (callback) {
                var idx = 0, length = this.length;
                for (; idx < length; idx++) {
                    callback(this[idx], idx, this);
                }
            },
            map: function (callback) {
                var idx = 0, result = [], length = this.length;
                for (; idx < length; idx++) {
                    result[idx] = callback(this[idx], idx, this);
                }
                return result;
            },
            reduce: function (callback) {
                var idx = 0, result, length = this.length;
                if (arguments.length == 2) {
                    result = arguments[1];
                } else if (idx < length) {
                    result = this[idx++];
                }
                for (; idx < length; idx++) {
                    result = callback(result, this[idx], idx, this);
                }
                return result;
            },
            reduceRight: function (callback) {
                var idx = this.length - 1, result;
                if (arguments.length == 2) {
                    result = arguments[1];
                } else if (idx > 0) {
                    result = this[idx--];
                }
                for (; idx >= 0; idx--) {
                    result = callback(result, this[idx], idx, this);
                }
                return result;
            },
            filter: function (callback) {
                var idx = 0, result = [], item, length = this.length;
                for (; idx < length; idx++) {
                    item = this[idx];
                    if (callback(item, idx, this)) {
                        result[result.length] = item;
                    }
                }
                return result;
            },
            find: function (callback) {
                var idx = 0, item, length = this.length;
                for (; idx < length; idx++) {
                    item = this[idx];
                    if (callback(item, idx, this)) {
                        return item;
                    }
                }
            },
            every: function (callback) {
                var idx = 0, item, length = this.length;
                for (; idx < length; idx++) {
                    item = this[idx];
                    if (!callback(item, idx, this)) {
                        return false;
                    }
                }
                return true;
            },
            some: function (callback) {
                var idx = 0, item, length = this.length;
                for (; idx < length; idx++) {
                    item = this[idx];
                    if (callback(item, idx, this)) {
                        return true;
                    }
                }
                return false;
            },
            remove: function (item) {
                var idx = this.indexOf(item);
                if (idx !== -1) {
                    this.splice(idx, 1);
                }
            },
            empty: function () {
                this.splice(0, this.length);
            }
        });
        if (typeof Symbol !== 'undefined' && Symbol.iterator && !ObservableArray.prototype[Symbol.iterator]) {
            ObservableArray.prototype[Symbol.iterator] = [][Symbol.iterator];
        }
        var LazyObservableArray = ObservableArray.extend({
            init: function (data, type) {
                Observable.fn.init.call(this);
                this.type = type || ObservableObject;
                for (var idx = 0; idx < data.length; idx++) {
                    this[idx] = data[idx];
                }
                this.length = idx;
                this._parent = proxy(function () {
                    return this;
                }, this);
            },
            at: function (index) {
                var item = this[index];
                if (!(item instanceof this.type)) {
                    item = this[index] = this.wrap(item, this._parent);
                } else {
                    item.parent = this._parent;
                }
                return item;
            }
        });
        function eventHandler(context, type, field, prefix) {
            return function (e) {
                var event = {}, key;
                for (key in e) {
                    event[key] = e[key];
                }
                if (prefix) {
                    event.field = field + '.' + e.field;
                } else {
                    event.field = field;
                }
                if (type == CHANGE && context._notifyChange) {
                    context._notifyChange(event);
                }
                context.trigger(type, event);
            };
        }
        var ObservableObject = Observable.extend({
            init: function (value) {
                var that = this, member, field, parent = function () {
                        return that;
                    };
                Observable.fn.init.call(this);
                this._handlers = {};
                for (field in value) {
                    member = value[field];
                    if (typeof member === 'object' && member && !member.getTime && field.charAt(0) != '_') {
                        member = that.wrap(member, field, parent);
                    }
                    that[field] = member;
                }
                that.uid = kendo.guid();
            },
            shouldSerialize: function (field) {
                return this.hasOwnProperty(field) && field !== '_handlers' && field !== '_events' && typeof this[field] !== FUNCTION && field !== 'uid';
            },
            forEach: function (f) {
                for (var i in this) {
                    if (this.shouldSerialize(i)) {
                        f(this[i], i);
                    }
                }
            },
            toJSON: function () {
                var result = {}, value, field;
                for (field in this) {
                    if (this.shouldSerialize(field)) {
                        value = this[field];
                        if (value instanceof ObservableObject || value instanceof ObservableArray) {
                            value = value.toJSON();
                        }
                        result[field] = value;
                    }
                }
                return result;
            },
            get: function (field) {
                var that = this, result;
                that.trigger(GET, { field: field });
                if (field === 'this') {
                    result = that;
                } else {
                    result = kendo.getter(field, true)(that);
                }
                return result;
            },
            _set: function (field, value) {
                var that = this;
                var composite = field.indexOf('.') >= 0;
                if (composite) {
                    var paths = field.split('.'), path = '';
                    while (paths.length > 1) {
                        path += paths.shift();
                        var obj = kendo.getter(path, true)(that);
                        if (obj instanceof ObservableObject) {
                            obj.set(paths.join('.'), value);
                            return composite;
                        }
                        path += '.';
                    }
                }
                kendo.setter(field)(that, value);
                return composite;
            },
            set: function (field, value) {
                var that = this, isSetPrevented = false, composite = field.indexOf('.') >= 0, current = kendo.getter(field, true)(that);
                if (current !== value) {
                    if (current instanceof Observable && this._handlers[field]) {
                        if (this._handlers[field].get) {
                            current.unbind(GET, this._handlers[field].get);
                        }
                        current.unbind(CHANGE, this._handlers[field].change);
                    }
                    isSetPrevented = that.trigger('set', {
                        field: field,
                        value: value
                    });
                    if (!isSetPrevented) {
                        if (!composite) {
                            value = that.wrap(value, field, function () {
                                return that;
                            });
                        }
                        if (!that._set(field, value) || field.indexOf('(') >= 0 || field.indexOf('[') >= 0) {
                            that.trigger(CHANGE, { field: field });
                        }
                    }
                }
                return isSetPrevented;
            },
            parent: noop,
            wrap: function (object, field, parent) {
                var that = this;
                var get;
                var change;
                var type = toString.call(object);
                if (object != null && (type === '[object Object]' || type === '[object Array]')) {
                    var isObservableArray = object instanceof ObservableArray;
                    var isDataSource = object instanceof DataSource;
                    if (type === '[object Object]' && !isDataSource && !isObservableArray) {
                        if (!(object instanceof ObservableObject)) {
                            object = new ObservableObject(object);
                        }
                        get = eventHandler(that, GET, field, true);
                        object.bind(GET, get);
                        change = eventHandler(that, CHANGE, field, true);
                        object.bind(CHANGE, change);
                        that._handlers[field] = {
                            get: get,
                            change: change
                        };
                    } else if (type === '[object Array]' || isObservableArray || isDataSource) {
                        if (!isObservableArray && !isDataSource) {
                            object = new ObservableArray(object);
                        }
                        change = eventHandler(that, CHANGE, field, false);
                        object.bind(CHANGE, change);
                        that._handlers[field] = { change: change };
                    }
                    object.parent = parent;
                }
                return object;
            }
        });
        function equal(x, y) {
            if (x === y) {
                return true;
            }
            var xtype = $.type(x), ytype = $.type(y), field;
            if (xtype !== ytype) {
                return false;
            }
            if (xtype === 'date') {
                return x.getTime() === y.getTime();
            }
            if (xtype !== 'object' && xtype !== 'array') {
                return false;
            }
            for (field in x) {
                if (!equal(x[field], y[field])) {
                    return false;
                }
            }
            return true;
        }
        var parsers = {
            'number': function (value) {
                return kendo.parseFloat(value);
            },
            'date': function (value) {
                return kendo.parseDate(value);
            },
            'boolean': function (value) {
                if (typeof value === STRING) {
                    return value.toLowerCase() === 'true';
                }
                return value != null ? !!value : value;
            },
            'string': function (value) {
                return value != null ? value + '' : value;
            },
            'default': function (value) {
                return value;
            }
        };
        var defaultValues = {
            'string': '',
            'number': 0,
            'date': new Date(),
            'boolean': false,
            'default': ''
        };
        function getFieldByName(obj, name) {
            var field, fieldName;
            for (fieldName in obj) {
                field = obj[fieldName];
                if (isPlainObject(field) && field.field && field.field === name) {
                    return field;
                } else if (field === name) {
                    return field;
                }
            }
            return null;
        }
        var Model = ObservableObject.extend({
            init: function (data) {
                var that = this;
                if (!data || $.isEmptyObject(data)) {
                    data = $.extend({}, that.defaults, data);
                    if (that._initializers) {
                        for (var idx = 0; idx < that._initializers.length; idx++) {
                            var name = that._initializers[idx];
                            data[name] = that.defaults[name]();
                        }
                    }
                }
                ObservableObject.fn.init.call(that, data);
                that.dirty = false;
                if (that.idField) {
                    that.id = that.get(that.idField);
                    if (that.id === undefined) {
                        that.id = that._defaultId;
                    }
                }
            },
            shouldSerialize: function (field) {
                return ObservableObject.fn.shouldSerialize.call(this, field) && field !== 'uid' && !(this.idField !== 'id' && field === 'id') && field !== 'dirty' && field !== '_accessors';
            },
            _parse: function (field, value) {
                var that = this, fieldName = field, fields = that.fields || {}, parse;
                field = fields[field];
                if (!field) {
                    field = getFieldByName(fields, fieldName);
                }
                if (field) {
                    parse = field.parse;
                    if (!parse && field.type) {
                        parse = parsers[field.type.toLowerCase()];
                    }
                }
                return parse ? parse(value) : value;
            },
            _notifyChange: function (e) {
                var action = e.action;
                if (action == 'add' || action == 'remove') {
                    this.dirty = true;
                }
            },
            editable: function (field) {
                field = (this.fields || {})[field];
                return field ? field.editable !== false : true;
            },
            set: function (field, value, initiator) {
                var that = this;
                var dirty = that.dirty;
                if (that.editable(field)) {
                    value = that._parse(field, value);
                    if (!equal(value, that.get(field))) {
                        that.dirty = true;
                        if (ObservableObject.fn.set.call(that, field, value, initiator) && !dirty) {
                            that.dirty = dirty;
                        }
                    }
                }
            },
            accept: function (data) {
                var that = this, parent = function () {
                        return that;
                    }, field;
                for (field in data) {
                    var value = data[field];
                    if (field.charAt(0) != '_') {
                        value = that.wrap(data[field], field, parent);
                    }
                    that._set(field, value);
                }
                if (that.idField) {
                    that.id = that.get(that.idField);
                }
                that.dirty = false;
            },
            isNew: function () {
                return this.id === this._defaultId;
            }
        });
        Model.define = function (base, options) {
            if (options === undefined) {
                options = base;
                base = Model;
            }
            var model, proto = extend({ defaults: {} }, options), name, field, type, value, idx, length, fields = {}, originalName, id = proto.id, functionFields = [];
            if (id) {
                proto.idField = id;
            }
            if (proto.id) {
                delete proto.id;
            }
            if (id) {
                proto.defaults[id] = proto._defaultId = '';
            }
            if (toString.call(proto.fields) === '[object Array]') {
                for (idx = 0, length = proto.fields.length; idx < length; idx++) {
                    field = proto.fields[idx];
                    if (typeof field === STRING) {
                        fields[field] = {};
                    } else if (field.field) {
                        fields[field.field] = field;
                    }
                }
                proto.fields = fields;
            }
            for (name in proto.fields) {
                field = proto.fields[name];
                type = field.type || 'default';
                value = null;
                originalName = name;
                name = typeof field.field === STRING ? field.field : name;
                if (!field.nullable) {
                    value = proto.defaults[originalName !== name ? originalName : name] = field.defaultValue !== undefined ? field.defaultValue : defaultValues[type.toLowerCase()];
                    if (typeof value === 'function') {
                        functionFields.push(name);
                    }
                }
                if (options.id === name) {
                    proto._defaultId = value;
                }
                proto.defaults[originalName !== name ? originalName : name] = value;
                field.parse = field.parse || parsers[type];
            }
            if (functionFields.length > 0) {
                proto._initializers = functionFields;
            }
            model = base.extend(proto);
            model.define = function (options) {
                return Model.define(model, options);
            };
            if (proto.fields) {
                model.fields = proto.fields;
                model.idField = proto.idField;
            }
            return model;
        };
        var Comparer = {
            selector: function (field) {
                return isFunction(field) ? field : getter(field);
            },
            compare: function (field) {
                var selector = this.selector(field);
                return function (a, b) {
                    a = selector(a);
                    b = selector(b);
                    if (a == null && b == null) {
                        return 0;
                    }
                    if (a == null) {
                        return -1;
                    }
                    if (b == null) {
                        return 1;
                    }
                    if (a.localeCompare) {
                        return a.localeCompare(b);
                    }
                    return a > b ? 1 : a < b ? -1 : 0;
                };
            },
            create: function (sort) {
                var compare = sort.compare || this.compare(sort.field);
                if (sort.dir == 'desc') {
                    return function (a, b) {
                        return compare(b, a, true);
                    };
                }
                return compare;
            },
            combine: function (comparers) {
                return function (a, b) {
                    var result = comparers[0](a, b), idx, length;
                    for (idx = 1, length = comparers.length; idx < length; idx++) {
                        result = result || comparers[idx](a, b);
                    }
                    return result;
                };
            }
        };
        var StableComparer = extend({}, Comparer, {
            asc: function (field) {
                var selector = this.selector(field);
                return function (a, b) {
                    var valueA = selector(a);
                    var valueB = selector(b);
                    if (valueA && valueA.getTime && valueB && valueB.getTime) {
                        valueA = valueA.getTime();
                        valueB = valueB.getTime();
                    }
                    if (valueA === valueB) {
                        return a.__position - b.__position;
                    }
                    if (valueA == null) {
                        return -1;
                    }
                    if (valueB == null) {
                        return 1;
                    }
                    if (valueA.localeCompare) {
                        return valueA.localeCompare(valueB);
                    }
                    return valueA > valueB ? 1 : -1;
                };
            },
            desc: function (field) {
                var selector = this.selector(field);
                return function (a, b) {
                    var valueA = selector(a);
                    var valueB = selector(b);
                    if (valueA && valueA.getTime && valueB && valueB.getTime) {
                        valueA = valueA.getTime();
                        valueB = valueB.getTime();
                    }
                    if (valueA === valueB) {
                        return a.__position - b.__position;
                    }
                    if (valueA == null) {
                        return 1;
                    }
                    if (valueB == null) {
                        return -1;
                    }
                    if (valueB.localeCompare) {
                        return valueB.localeCompare(valueA);
                    }
                    return valueA < valueB ? 1 : -1;
                };
            },
            create: function (sort) {
                return this[sort.dir](sort.field);
            }
        });
        map = function (array, callback) {
            var idx, length = array.length, result = new Array(length);
            for (idx = 0; idx < length; idx++) {
                result[idx] = callback(array[idx], idx, array);
            }
            return result;
        };
        var operators = function () {
            function quote(str) {
                if (typeof str == 'string') {
                    str = str.replace(/[\r\n]+/g, '');
                }
                return JSON.stringify(str);
            }
            function textOp(impl) {
                return function (a, b, ignore) {
                    b += '';
                    if (ignore) {
                        a = '(' + a + ' || \'\').toLowerCase()';
                        b = b.toLowerCase();
                    }
                    return impl(a, quote(b), ignore);
                };
            }
            function operator(op, a, b, ignore) {
                if (b != null) {
                    if (typeof b === STRING) {
                        var date = dateRegExp.exec(b);
                        if (date) {
                            b = new Date(+date[1]);
                        } else if (ignore) {
                            b = quote(b.toLowerCase());
                            a = '((' + a + ' || \'\')+\'\').toLowerCase()';
                        } else {
                            b = quote(b);
                        }
                    }
                    if (b.getTime) {
                        a = '(' + a + '&&' + a + '.getTime?' + a + '.getTime():' + a + ')';
                        b = b.getTime();
                    }
                }
                return a + ' ' + op + ' ' + b;
            }
            function getMatchRegexp(pattern) {
                for (var rx = '/^', esc = false, i = 0; i < pattern.length; ++i) {
                    var ch = pattern.charAt(i);
                    if (esc) {
                        rx += '\\' + ch;
                    } else if (ch == '~') {
                        esc = true;
                        continue;
                    } else if (ch == '*') {
                        rx += '.*';
                    } else if (ch == '?') {
                        rx += '.';
                    } else if ('.+^$()[]{}|\\/\n\r\u2028\u2029\xA0'.indexOf(ch) >= 0) {
                        rx += '\\' + ch;
                    } else {
                        rx += ch;
                    }
                    esc = false;
                }
                return rx + '$/';
            }
            return {
                quote: function (value) {
                    if (value && value.getTime) {
                        return 'new Date(' + value.getTime() + ')';
                    }
                    return quote(value);
                },
                eq: function (a, b, ignore) {
                    return operator('==', a, b, ignore);
                },
                neq: function (a, b, ignore) {
                    return operator('!=', a, b, ignore);
                },
                gt: function (a, b, ignore) {
                    return operator('>', a, b, ignore);
                },
                gte: function (a, b, ignore) {
                    return operator('>=', a, b, ignore);
                },
                lt: function (a, b, ignore) {
                    return operator('<', a, b, ignore);
                },
                lte: function (a, b, ignore) {
                    return operator('<=', a, b, ignore);
                },
                startswith: textOp(function (a, b) {
                    return a + '.lastIndexOf(' + b + ', 0) == 0';
                }),
                doesnotstartwith: textOp(function (a, b) {
                    return a + '.lastIndexOf(' + b + ', 0) == -1';
                }),
                endswith: textOp(function (a, b) {
                    var n = b ? b.length - 2 : 0;
                    return a + '.indexOf(' + b + ', ' + a + '.length - ' + n + ') >= 0';
                }),
                doesnotendwith: textOp(function (a, b) {
                    var n = b ? b.length - 2 : 0;
                    return a + '.indexOf(' + b + ', ' + a + '.length - ' + n + ') < 0';
                }),
                contains: textOp(function (a, b) {
                    return a + '.indexOf(' + b + ') >= 0';
                }),
                doesnotcontain: textOp(function (a, b) {
                    return a + '.indexOf(' + b + ') == -1';
                }),
                matches: textOp(function (a, b) {
                    b = b.substring(1, b.length - 1);
                    return getMatchRegexp(b) + '.test(' + a + ')';
                }),
                doesnotmatch: textOp(function (a, b) {
                    b = b.substring(1, b.length - 1);
                    return '!' + getMatchRegexp(b) + '.test(' + a + ')';
                }),
                isempty: function (a) {
                    return a + ' === \'\'';
                },
                isnotempty: function (a) {
                    return a + ' !== \'\'';
                },
                isnull: function (a) {
                    return '(' + a + ' == null)';
                },
                isnotnull: function (a) {
                    return '(' + a + ' != null)';
                }
            };
        }();
        function Query(data) {
            this.data = data || [];
        }
        Query.filterExpr = function (expression) {
            var expressions = [], logic = {
                    and: ' && ',
                    or: ' || '
                }, idx, length, filter, expr, fieldFunctions = [], operatorFunctions = [], field, operator, filters = expression.filters;
            for (idx = 0, length = filters.length; idx < length; idx++) {
                filter = filters[idx];
                field = filter.field;
                operator = filter.operator;
                if (filter.filters) {
                    expr = Query.filterExpr(filter);
                    filter = expr.expression.replace(/__o\[(\d+)\]/g, function (match, index) {
                        index = +index;
                        return '__o[' + (operatorFunctions.length + index) + ']';
                    }).replace(/__f\[(\d+)\]/g, function (match, index) {
                        index = +index;
                        return '__f[' + (fieldFunctions.length + index) + ']';
                    });
                    operatorFunctions.push.apply(operatorFunctions, expr.operators);
                    fieldFunctions.push.apply(fieldFunctions, expr.fields);
                } else {
                    if (typeof field === FUNCTION) {
                        expr = '__f[' + fieldFunctions.length + '](d)';
                        fieldFunctions.push(field);
                    } else {
                        expr = kendo.expr(field);
                    }
                    if (typeof operator === FUNCTION) {
                        filter = '__o[' + operatorFunctions.length + '](' + expr + ', ' + operators.quote(filter.value) + ')';
                        operatorFunctions.push(operator);
                    } else {
                        filter = operators[(operator || 'eq').toLowerCase()](expr, filter.value, filter.ignoreCase !== undefined ? filter.ignoreCase : true);
                    }
                }
                expressions.push(filter);
            }
            return {
                expression: '(' + expressions.join(logic[expression.logic]) + ')',
                fields: fieldFunctions,
                operators: operatorFunctions
            };
        };
        function normalizeSort(field, dir) {
            if (field) {
                var descriptor = typeof field === STRING ? {
                        field: field,
                        dir: dir
                    } : field, descriptors = isArray(descriptor) ? descriptor : descriptor !== undefined ? [descriptor] : [];
                return grep(descriptors, function (d) {
                    return !!d.dir;
                });
            }
        }
        var operatorMap = {
            '==': 'eq',
            equals: 'eq',
            isequalto: 'eq',
            equalto: 'eq',
            equal: 'eq',
            '!=': 'neq',
            ne: 'neq',
            notequals: 'neq',
            isnotequalto: 'neq',
            notequalto: 'neq',
            notequal: 'neq',
            '<': 'lt',
            islessthan: 'lt',
            lessthan: 'lt',
            less: 'lt',
            '<=': 'lte',
            le: 'lte',
            islessthanorequalto: 'lte',
            lessthanequal: 'lte',
            '>': 'gt',
            isgreaterthan: 'gt',
            greaterthan: 'gt',
            greater: 'gt',
            '>=': 'gte',
            isgreaterthanorequalto: 'gte',
            greaterthanequal: 'gte',
            ge: 'gte',
            notsubstringof: 'doesnotcontain',
            isnull: 'isnull',
            isempty: 'isempty',
            isnotempty: 'isnotempty'
        };
        function normalizeOperator(expression) {
            var idx, length, filter, operator, filters = expression.filters;
            if (filters) {
                for (idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    operator = filter.operator;
                    if (operator && typeof operator === STRING) {
                        filter.operator = operatorMap[operator.toLowerCase()] || operator;
                    }
                    normalizeOperator(filter);
                }
            }
        }
        function normalizeFilter(expression) {
            if (expression && !isEmptyObject(expression)) {
                if (isArray(expression) || !expression.filters) {
                    expression = {
                        logic: 'and',
                        filters: isArray(expression) ? expression : [expression]
                    };
                }
                normalizeOperator(expression);
                return expression;
            }
        }
        Query.normalizeFilter = normalizeFilter;
        function compareDescriptor(f1, f2) {
            if (f1.logic || f2.logic) {
                return false;
            }
            return f1.field === f2.field && f1.value === f2.value && f1.operator === f2.operator;
        }
        function normalizeDescriptor(filter) {
            filter = filter || {};
            if (isEmptyObject(filter)) {
                return {
                    logic: 'and',
                    filters: []
                };
            }
            return normalizeFilter(filter);
        }
        function fieldComparer(a, b) {
            if (b.logic || a.field > b.field) {
                return 1;
            } else if (a.field < b.field) {
                return -1;
            } else {
                return 0;
            }
        }
        function compareFilters(expr1, expr2) {
            expr1 = normalizeDescriptor(expr1);
            expr2 = normalizeDescriptor(expr2);
            if (expr1.logic !== expr2.logic) {
                return false;
            }
            var f1, f2;
            var filters1 = (expr1.filters || []).slice();
            var filters2 = (expr2.filters || []).slice();
            if (filters1.length !== filters2.length) {
                return false;
            }
            filters1 = filters1.sort(fieldComparer);
            filters2 = filters2.sort(fieldComparer);
            for (var idx = 0; idx < filters1.length; idx++) {
                f1 = filters1[idx];
                f2 = filters2[idx];
                if (f1.logic && f2.logic) {
                    if (!compareFilters(f1, f2)) {
                        return false;
                    }
                } else if (!compareDescriptor(f1, f2)) {
                    return false;
                }
            }
            return true;
        }
        Query.compareFilters = compareFilters;
        function normalizeAggregate(expressions) {
            return isArray(expressions) ? expressions : [expressions];
        }
        function normalizeGroup(field, dir) {
            var descriptor = typeof field === STRING ? {
                    field: field,
                    dir: dir
                } : field, descriptors = isArray(descriptor) ? descriptor : descriptor !== undefined ? [descriptor] : [];
            return map(descriptors, function (d) {
                return {
                    field: d.field,
                    dir: d.dir || 'asc',
                    aggregates: d.aggregates
                };
            });
        }
        Query.prototype = {
            toArray: function () {
                return this.data;
            },
            range: function (index, count) {
                return new Query(this.data.slice(index, index + count));
            },
            skip: function (count) {
                return new Query(this.data.slice(count));
            },
            take: function (count) {
                return new Query(this.data.slice(0, count));
            },
            select: function (selector) {
                return new Query(map(this.data, selector));
            },
            order: function (selector, dir) {
                var sort = { dir: dir };
                if (selector) {
                    if (selector.compare) {
                        sort.compare = selector.compare;
                    } else {
                        sort.field = selector;
                    }
                }
                return new Query(this.data.slice(0).sort(Comparer.create(sort)));
            },
            orderBy: function (selector) {
                return this.order(selector, 'asc');
            },
            orderByDescending: function (selector) {
                return this.order(selector, 'desc');
            },
            sort: function (field, dir, comparer) {
                var idx, length, descriptors = normalizeSort(field, dir), comparers = [];
                comparer = comparer || Comparer;
                if (descriptors.length) {
                    for (idx = 0, length = descriptors.length; idx < length; idx++) {
                        comparers.push(comparer.create(descriptors[idx]));
                    }
                    return this.orderBy({ compare: comparer.combine(comparers) });
                }
                return this;
            },
            filter: function (expressions) {
                var idx, current, length, compiled, predicate, data = this.data, fields, operators, result = [], filter;
                expressions = normalizeFilter(expressions);
                if (!expressions || expressions.filters.length === 0) {
                    return this;
                }
                compiled = Query.filterExpr(expressions);
                fields = compiled.fields;
                operators = compiled.operators;
                predicate = filter = new Function('d, __f, __o', 'return ' + compiled.expression);
                if (fields.length || operators.length) {
                    filter = function (d) {
                        return predicate(d, fields, operators);
                    };
                }
                for (idx = 0, length = data.length; idx < length; idx++) {
                    current = data[idx];
                    if (filter(current)) {
                        result.push(current);
                    }
                }
                return new Query(result);
            },
            group: function (descriptors, allData) {
                descriptors = normalizeGroup(descriptors || []);
                allData = allData || this.data;
                var that = this, result = new Query(that.data), descriptor;
                if (descriptors.length > 0) {
                    descriptor = descriptors[0];
                    result = result.groupBy(descriptor).select(function (group) {
                        var data = new Query(allData).filter([{
                                field: group.field,
                                operator: 'eq',
                                value: group.value,
                                ignoreCase: false
                            }]);
                        return {
                            field: group.field,
                            value: group.value,
                            items: descriptors.length > 1 ? new Query(group.items).group(descriptors.slice(1), data.toArray()).toArray() : group.items,
                            hasSubgroups: descriptors.length > 1,
                            aggregates: data.aggregate(descriptor.aggregates)
                        };
                    });
                }
                return result;
            },
            groupBy: function (descriptor) {
                if (isEmptyObject(descriptor) || !this.data.length) {
                    return new Query([]);
                }
                var field = descriptor.field, sorted = this._sortForGrouping(field, descriptor.dir || 'asc'), accessor = kendo.accessor(field), item, groupValue = accessor.get(sorted[0], field), group = {
                        field: field,
                        value: groupValue,
                        items: []
                    }, currentValue, idx, len, result = [group];
                for (idx = 0, len = sorted.length; idx < len; idx++) {
                    item = sorted[idx];
                    currentValue = accessor.get(item, field);
                    if (!groupValueComparer(groupValue, currentValue)) {
                        groupValue = currentValue;
                        group = {
                            field: field,
                            value: groupValue,
                            items: []
                        };
                        result.push(group);
                    }
                    group.items.push(item);
                }
                return new Query(result);
            },
            _sortForGrouping: function (field, dir) {
                var idx, length, data = this.data;
                if (!stableSort) {
                    for (idx = 0, length = data.length; idx < length; idx++) {
                        data[idx].__position = idx;
                    }
                    data = new Query(data).sort(field, dir, StableComparer).toArray();
                    for (idx = 0, length = data.length; idx < length; idx++) {
                        delete data[idx].__position;
                    }
                    return data;
                }
                return this.sort(field, dir).toArray();
            },
            aggregate: function (aggregates) {
                var idx, len, result = {}, state = {};
                if (aggregates && aggregates.length) {
                    for (idx = 0, len = this.data.length; idx < len; idx++) {
                        calculateAggregate(result, aggregates, this.data[idx], idx, len, state);
                    }
                }
                return result;
            }
        };
        function groupValueComparer(a, b) {
            if (a && a.getTime && b && b.getTime) {
                return a.getTime() === b.getTime();
            }
            return a === b;
        }
        function calculateAggregate(accumulator, aggregates, item, index, length, state) {
            aggregates = aggregates || [];
            var idx, aggr, functionName, len = aggregates.length;
            for (idx = 0; idx < len; idx++) {
                aggr = aggregates[idx];
                functionName = aggr.aggregate;
                var field = aggr.field;
                accumulator[field] = accumulator[field] || {};
                state[field] = state[field] || {};
                state[field][functionName] = state[field][functionName] || {};
                accumulator[field][functionName] = functions[functionName.toLowerCase()](accumulator[field][functionName], item, kendo.accessor(field), index, length, state[field][functionName]);
            }
        }
        var functions = {
            sum: function (accumulator, item, accessor) {
                var value = accessor.get(item);
                if (!isNumber(accumulator)) {
                    accumulator = value;
                } else if (isNumber(value)) {
                    accumulator += value;
                }
                return accumulator;
            },
            count: function (accumulator) {
                return (accumulator || 0) + 1;
            },
            average: function (accumulator, item, accessor, index, length, state) {
                var value = accessor.get(item);
                if (state.count === undefined) {
                    state.count = 0;
                }
                if (!isNumber(accumulator)) {
                    accumulator = value;
                } else if (isNumber(value)) {
                    accumulator += value;
                }
                if (isNumber(value)) {
                    state.count++;
                }
                if (index == length - 1 && isNumber(accumulator)) {
                    accumulator = accumulator / state.count;
                }
                return accumulator;
            },
            max: function (accumulator, item, accessor) {
                var value = accessor.get(item);
                if (!isNumber(accumulator) && !isDate(accumulator)) {
                    accumulator = value;
                }
                if (accumulator < value && (isNumber(value) || isDate(value))) {
                    accumulator = value;
                }
                return accumulator;
            },
            min: function (accumulator, item, accessor) {
                var value = accessor.get(item);
                if (!isNumber(accumulator) && !isDate(accumulator)) {
                    accumulator = value;
                }
                if (accumulator > value && (isNumber(value) || isDate(value))) {
                    accumulator = value;
                }
                return accumulator;
            }
        };
        function isNumber(val) {
            return typeof val === 'number' && !isNaN(val);
        }
        function isDate(val) {
            return val && val.getTime;
        }
        function toJSON(array) {
            var idx, length = array.length, result = new Array(length);
            for (idx = 0; idx < length; idx++) {
                result[idx] = array[idx].toJSON();
            }
            return result;
        }
        Query.process = function (data, options) {
            options = options || {};
            var query = new Query(data), group = options.group, sort = normalizeGroup(group || []).concat(normalizeSort(options.sort || [])), total, filterCallback = options.filterCallback, filter = options.filter, skip = options.skip, take = options.take;
            if (filter) {
                query = query.filter(filter);
                if (filterCallback) {
                    query = filterCallback(query);
                }
                total = query.toArray().length;
            }
            if (sort) {
                query = query.sort(sort);
                if (group) {
                    data = query.toArray();
                }
            }
            if (skip !== undefined && take !== undefined) {
                query = query.range(skip, take);
            }
            if (group) {
                query = query.group(group, data);
            }
            return {
                total: total,
                data: query.toArray()
            };
        };
        var LocalTransport = Class.extend({
            init: function (options) {
                this.data = options.data;
            },
            read: function (options) {
                options.success(this.data);
            },
            update: function (options) {
                options.success(options.data);
            },
            create: function (options) {
                options.success(options.data);
            },
            destroy: function (options) {
                options.success(options.data);
            }
        });
        var RemoteTransport = Class.extend({
            init: function (options) {
                var that = this, parameterMap;
                options = that.options = extend({}, that.options, options);
                each(crud, function (index, type) {
                    if (typeof options[type] === STRING) {
                        options[type] = { url: options[type] };
                    }
                });
                that.cache = options.cache ? Cache.create(options.cache) : {
                    find: noop,
                    add: noop
                };
                parameterMap = options.parameterMap;
                if (isFunction(options.push)) {
                    that.push = options.push;
                }
                if (!that.push) {
                    that.push = identity;
                }
                that.parameterMap = isFunction(parameterMap) ? parameterMap : function (options) {
                    var result = {};
                    each(options, function (option, value) {
                        if (option in parameterMap) {
                            option = parameterMap[option];
                            if (isPlainObject(option)) {
                                value = option.value(value);
                                option = option.key;
                            }
                        }
                        result[option] = value;
                    });
                    return result;
                };
            },
            options: { parameterMap: identity },
            create: function (options) {
                return ajax(this.setup(options, CREATE));
            },
            read: function (options) {
                var that = this, success, error, result, cache = that.cache;
                options = that.setup(options, READ);
                success = options.success || noop;
                error = options.error || noop;
                result = cache.find(options.data);
                if (result !== undefined) {
                    success(result);
                } else {
                    options.success = function (result) {
                        cache.add(options.data, result);
                        success(result);
                    };
                    $.ajax(options);
                }
            },
            update: function (options) {
                return ajax(this.setup(options, UPDATE));
            },
            destroy: function (options) {
                return ajax(this.setup(options, DESTROY));
            },
            setup: function (options, type) {
                options = options || {};
                var that = this, parameters, operation = that.options[type], data = isFunction(operation.data) ? operation.data(options.data) : operation.data;
                options = extend(true, {}, operation, options);
                parameters = extend(true, {}, data, options.data);
                options.data = that.parameterMap(parameters, type);
                if (isFunction(options.url)) {
                    options.url = options.url(parameters);
                }
                return options;
            }
        });
        var Cache = Class.extend({
            init: function () {
                this._store = {};
            },
            add: function (key, data) {
                if (key !== undefined) {
                    this._store[stringify(key)] = data;
                }
            },
            find: function (key) {
                return this._store[stringify(key)];
            },
            clear: function () {
                this._store = {};
            },
            remove: function (key) {
                delete this._store[stringify(key)];
            }
        });
        Cache.create = function (options) {
            var store = {
                'inmemory': function () {
                    return new Cache();
                }
            };
            if (isPlainObject(options) && isFunction(options.find)) {
                return options;
            }
            if (options === true) {
                return new Cache();
            }
            return store[options]();
        };
        function serializeRecords(data, getters, modelInstance, originalFieldNames, fieldNames) {
            var record, getter, originalName, idx, setters = {}, length;
            for (idx = 0, length = data.length; idx < length; idx++) {
                record = data[idx];
                for (getter in getters) {
                    originalName = fieldNames[getter];
                    if (originalName && originalName !== getter) {
                        if (!setters[originalName]) {
                            setters[originalName] = kendo.setter(originalName);
                        }
                        setters[originalName](record, getters[getter](record));
                        delete record[getter];
                    }
                }
            }
        }
        function convertRecords(data, getters, modelInstance, originalFieldNames, fieldNames) {
            var record, getter, originalName, idx, length;
            for (idx = 0, length = data.length; idx < length; idx++) {
                record = data[idx];
                for (getter in getters) {
                    record[getter] = modelInstance._parse(getter, getters[getter](record));
                    originalName = fieldNames[getter];
                    if (originalName && originalName !== getter) {
                        delete record[originalName];
                    }
                }
            }
        }
        function convertGroup(data, getters, modelInstance, originalFieldNames, fieldNames) {
            var record, idx, fieldName, length;
            for (idx = 0, length = data.length; idx < length; idx++) {
                record = data[idx];
                fieldName = originalFieldNames[record.field];
                if (fieldName && fieldName != record.field) {
                    record.field = fieldName;
                }
                record.value = modelInstance._parse(record.field, record.value);
                if (record.hasSubgroups) {
                    convertGroup(record.items, getters, modelInstance, originalFieldNames, fieldNames);
                } else {
                    convertRecords(record.items, getters, modelInstance, originalFieldNames, fieldNames);
                }
            }
        }
        function wrapDataAccess(originalFunction, model, converter, getters, originalFieldNames, fieldNames) {
            return function (data) {
                data = originalFunction(data);
                if (data && !isEmptyObject(getters)) {
                    if (toString.call(data) !== '[object Array]' && !(data instanceof ObservableArray)) {
                        data = [data];
                    }
                    converter(data, getters, new model(), originalFieldNames, fieldNames);
                }
                return data || [];
            };
        }
        var DataReader = Class.extend({
            init: function (schema) {
                var that = this, member, get, model, base;
                schema = schema || {};
                for (member in schema) {
                    get = schema[member];
                    that[member] = typeof get === STRING ? getter(get) : get;
                }
                base = schema.modelBase || Model;
                if (isPlainObject(that.model)) {
                    that.model = model = base.define(that.model);
                }
                var dataFunction = proxy(that.data, that);
                that._dataAccessFunction = dataFunction;
                if (that.model) {
                    var groupsFunction = proxy(that.groups, that), serializeFunction = proxy(that.serialize, that), originalFieldNames = {}, getters = {}, serializeGetters = {}, fieldNames = {}, shouldSerialize = false, fieldName;
                    model = that.model;
                    if (model.fields) {
                        each(model.fields, function (field, value) {
                            var fromName;
                            fieldName = field;
                            if (isPlainObject(value) && value.field) {
                                fieldName = value.field;
                            } else if (typeof value === STRING) {
                                fieldName = value;
                            }
                            if (isPlainObject(value) && value.from) {
                                fromName = value.from;
                            }
                            shouldSerialize = shouldSerialize || fromName && fromName !== field || fieldName !== field;
                            getters[field] = getter(fromName || fieldName);
                            serializeGetters[field] = getter(field);
                            originalFieldNames[fromName || fieldName] = field;
                            fieldNames[field] = fromName || fieldName;
                        });
                        if (!schema.serialize && shouldSerialize) {
                            that.serialize = wrapDataAccess(serializeFunction, model, serializeRecords, serializeGetters, originalFieldNames, fieldNames);
                        }
                    }
                    that._dataAccessFunction = dataFunction;
                    that.data = wrapDataAccess(dataFunction, model, convertRecords, getters, originalFieldNames, fieldNames);
                    that.groups = wrapDataAccess(groupsFunction, model, convertGroup, getters, originalFieldNames, fieldNames);
                }
            },
            errors: function (data) {
                return data ? data.errors : null;
            },
            parse: identity,
            data: identity,
            total: function (data) {
                return data.length;
            },
            groups: identity,
            aggregates: function () {
                return {};
            },
            serialize: function (data) {
                return data;
            }
        });
        function mergeGroups(target, dest, skip, take) {
            var group, idx = 0, items;
            while (dest.length && take) {
                group = dest[idx];
                items = group.items;
                var length = items.length;
                if (target && target.field === group.field && target.value === group.value) {
                    if (target.hasSubgroups && target.items.length) {
                        mergeGroups(target.items[target.items.length - 1], group.items, skip, take);
                    } else {
                        items = items.slice(skip, skip + take);
                        target.items = target.items.concat(items);
                    }
                    dest.splice(idx--, 1);
                } else if (group.hasSubgroups && items.length) {
                    mergeGroups(group, items, skip, take);
                    if (!group.items.length) {
                        dest.splice(idx--, 1);
                    }
                } else {
                    items = items.slice(skip, skip + take);
                    group.items = items;
                    if (!group.items.length) {
                        dest.splice(idx--, 1);
                    }
                }
                if (items.length === 0) {
                    skip -= length;
                } else {
                    skip = 0;
                    take -= items.length;
                }
                if (++idx >= dest.length) {
                    break;
                }
            }
            if (idx < dest.length) {
                dest.splice(idx, dest.length - idx);
            }
        }
        function flattenGroups(data) {
            var idx, result = [], length, items, itemIndex;
            for (idx = 0, length = data.length; idx < length; idx++) {
                var group = data.at(idx);
                if (group.hasSubgroups) {
                    result = result.concat(flattenGroups(group.items));
                } else {
                    items = group.items;
                    for (itemIndex = 0; itemIndex < items.length; itemIndex++) {
                        result.push(items.at(itemIndex));
                    }
                }
            }
            return result;
        }
        function wrapGroupItems(data, model) {
            var idx, length, group;
            if (model) {
                for (idx = 0, length = data.length; idx < length; idx++) {
                    group = data.at(idx);
                    if (group.hasSubgroups) {
                        wrapGroupItems(group.items, model);
                    } else {
                        group.items = new LazyObservableArray(group.items, model);
                    }
                }
            }
        }
        function eachGroupItems(data, func) {
            for (var idx = 0, length = data.length; idx < length; idx++) {
                if (data[idx].hasSubgroups) {
                    if (eachGroupItems(data[idx].items, func)) {
                        return true;
                    }
                } else if (func(data[idx].items, data[idx])) {
                    return true;
                }
            }
        }
        function replaceInRanges(ranges, data, item, observable) {
            for (var idx = 0; idx < ranges.length; idx++) {
                if (ranges[idx].data === data) {
                    break;
                }
                if (replaceInRange(ranges[idx].data, item, observable)) {
                    break;
                }
            }
        }
        function replaceInRange(items, item, observable) {
            for (var idx = 0, length = items.length; idx < length; idx++) {
                if (items[idx] && items[idx].hasSubgroups) {
                    return replaceInRange(items[idx].items, item, observable);
                } else if (items[idx] === item || items[idx] === observable) {
                    items[idx] = observable;
                    return true;
                }
            }
        }
        function replaceWithObservable(view, data, ranges, type, serverGrouping) {
            for (var viewIndex = 0, length = view.length; viewIndex < length; viewIndex++) {
                var item = view[viewIndex];
                if (!item || item instanceof type) {
                    continue;
                }
                if (item.hasSubgroups !== undefined && !serverGrouping) {
                    replaceWithObservable(item.items, data, ranges, type, serverGrouping);
                } else {
                    for (var idx = 0; idx < data.length; idx++) {
                        if (data[idx] === item) {
                            view[viewIndex] = data.at(idx);
                            replaceInRanges(ranges, data, item, view[viewIndex]);
                            break;
                        }
                    }
                }
            }
        }
        function removeModel(data, model) {
            var idx, length;
            for (idx = 0, length = data.length; idx < length; idx++) {
                var dataItem = data.at(idx);
                if (dataItem.uid == model.uid) {
                    data.splice(idx, 1);
                    return dataItem;
                }
            }
        }
        function indexOfPristineModel(data, model) {
            if (model) {
                return indexOf(data, function (item) {
                    return item.uid && item.uid == model.uid || item[model.idField] === model.id && model.id !== model._defaultId;
                });
            }
            return -1;
        }
        function indexOfModel(data, model) {
            if (model) {
                return indexOf(data, function (item) {
                    return item.uid == model.uid;
                });
            }
            return -1;
        }
        function indexOf(data, comparer) {
            var idx, length;
            for (idx = 0, length = data.length; idx < length; idx++) {
                if (comparer(data[idx])) {
                    return idx;
                }
            }
            return -1;
        }
        function fieldNameFromModel(fields, name) {
            if (fields && !isEmptyObject(fields)) {
                var descriptor = fields[name];
                var fieldName;
                if (isPlainObject(descriptor)) {
                    fieldName = descriptor.from || descriptor.field || name;
                } else {
                    fieldName = fields[name] || name;
                }
                if (isFunction(fieldName)) {
                    return name;
                }
                return fieldName;
            }
            return name;
        }
        function convertFilterDescriptorsField(descriptor, model) {
            var idx, length, target = {};
            for (var field in descriptor) {
                if (field !== 'filters') {
                    target[field] = descriptor[field];
                }
            }
            if (descriptor.filters) {
                target.filters = [];
                for (idx = 0, length = descriptor.filters.length; idx < length; idx++) {
                    target.filters[idx] = convertFilterDescriptorsField(descriptor.filters[idx], model);
                }
            } else {
                target.field = fieldNameFromModel(model.fields, target.field);
            }
            return target;
        }
        function convertDescriptorsField(descriptors, model) {
            var idx, length, result = [], target, descriptor;
            for (idx = 0, length = descriptors.length; idx < length; idx++) {
                target = {};
                descriptor = descriptors[idx];
                for (var field in descriptor) {
                    target[field] = descriptor[field];
                }
                target.field = fieldNameFromModel(model.fields, target.field);
                if (target.aggregates && isArray(target.aggregates)) {
                    target.aggregates = convertDescriptorsField(target.aggregates, model);
                }
                result.push(target);
            }
            return result;
        }
        var DataSource = Observable.extend({
            init: function (options) {
                var that = this, model, data;
                if (options) {
                    data = options.data;
                }
                options = that.options = extend({}, that.options, options);
                that._map = {};
                that._prefetch = {};
                that._data = [];
                that._pristineData = [];
                that._ranges = [];
                that._view = [];
                that._pristineTotal = 0;
                that._destroyed = [];
                that._pageSize = options.pageSize;
                that._page = options.page || (options.pageSize ? 1 : undefined);
                that._sort = normalizeSort(options.sort);
                that._filter = normalizeFilter(options.filter);
                that._group = normalizeGroup(options.group);
                that._aggregate = options.aggregate;
                that._total = options.total;
                that._shouldDetachObservableParents = true;
                Observable.fn.init.call(that);
                that.transport = Transport.create(options, data, that);
                if (isFunction(that.transport.push)) {
                    that.transport.push({
                        pushCreate: proxy(that._pushCreate, that),
                        pushUpdate: proxy(that._pushUpdate, that),
                        pushDestroy: proxy(that._pushDestroy, that)
                    });
                }
                if (options.offlineStorage != null) {
                    if (typeof options.offlineStorage == 'string') {
                        var key = options.offlineStorage;
                        that._storage = {
                            getItem: function () {
                                return JSON.parse(localStorage.getItem(key));
                            },
                            setItem: function (item) {
                                localStorage.setItem(key, stringify(that.reader.serialize(item)));
                            }
                        };
                    } else {
                        that._storage = options.offlineStorage;
                    }
                }
                that.reader = new kendo.data.readers[options.schema.type || 'json'](options.schema);
                model = that.reader.model || {};
                that._detachObservableParents();
                that._data = that._observe(that._data);
                that._online = true;
                that.bind([
                    'push',
                    ERROR,
                    CHANGE,
                    REQUESTSTART,
                    SYNC,
                    REQUESTEND,
                    PROGRESS
                ], options);
            },
            options: {
                data: null,
                schema: { modelBase: Model },
                offlineStorage: null,
                serverSorting: false,
                serverPaging: false,
                serverFiltering: false,
                serverGrouping: false,
                serverAggregates: false,
                batch: false
            },
            clone: function () {
                return this;
            },
            online: function (value) {
                if (value !== undefined) {
                    if (this._online != value) {
                        this._online = value;
                        if (value) {
                            return this.sync();
                        }
                    }
                    return $.Deferred().resolve().promise();
                } else {
                    return this._online;
                }
            },
            offlineData: function (state) {
                if (this.options.offlineStorage == null) {
                    return null;
                }
                if (state !== undefined) {
                    return this._storage.setItem(state);
                }
                return this._storage.getItem() || [];
            },
            _isServerGrouped: function () {
                var group = this.group() || [];
                return this.options.serverGrouping && group.length;
            },
            _pushCreate: function (result) {
                this._push(result, 'pushCreate');
            },
            _pushUpdate: function (result) {
                this._push(result, 'pushUpdate');
            },
            _pushDestroy: function (result) {
                this._push(result, 'pushDestroy');
            },
            _push: function (result, operation) {
                var data = this._readData(result);
                if (!data) {
                    data = result;
                }
                this[operation](data);
            },
            _flatData: function (data, skip) {
                if (data) {
                    if (this._isServerGrouped()) {
                        return flattenGroups(data);
                    }
                    if (!skip) {
                        for (var idx = 0; idx < data.length; idx++) {
                            data.at(idx);
                        }
                    }
                }
                return data;
            },
            parent: noop,
            get: function (id) {
                var idx, length, data = this._flatData(this._data);
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].id == id) {
                        return data[idx];
                    }
                }
            },
            getByUid: function (id) {
                var idx, length, data = this._flatData(this._data);
                if (!data) {
                    return;
                }
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].uid == id) {
                        return data[idx];
                    }
                }
            },
            indexOf: function (model) {
                return indexOfModel(this._data, model);
            },
            at: function (index) {
                return this._data.at(index);
            },
            data: function (value) {
                var that = this;
                if (value !== undefined) {
                    that._detachObservableParents();
                    that._data = this._observe(value);
                    that._pristineData = value.slice(0);
                    that._storeData();
                    that._ranges = [];
                    that.trigger('reset');
                    that._addRange(that._data);
                    that._total = that._data.length;
                    that._pristineTotal = that._total;
                    that._process(that._data);
                } else {
                    if (that._data) {
                        for (var idx = 0; idx < that._data.length; idx++) {
                            that._data.at(idx);
                        }
                    }
                    return that._data;
                }
            },
            view: function (value) {
                if (value === undefined) {
                    return this._view;
                } else {
                    this._view = this._observeView(value);
                }
            },
            _observeView: function (data) {
                var that = this;
                replaceWithObservable(data, that._data, that._ranges, that.reader.model || ObservableObject, that._isServerGrouped());
                var view = new LazyObservableArray(data, that.reader.model);
                view.parent = function () {
                    return that.parent();
                };
                return view;
            },
            flatView: function () {
                var groups = this.group() || [];
                if (groups.length) {
                    return flattenGroups(this._view);
                } else {
                    return this._view;
                }
            },
            add: function (model) {
                return this.insert(this._data.length, model);
            },
            _createNewModel: function (model) {
                if (this.reader.model) {
                    return new this.reader.model(model);
                }
                if (model instanceof ObservableObject) {
                    return model;
                }
                return new ObservableObject(model);
            },
            insert: function (index, model) {
                if (!model) {
                    model = index;
                    index = 0;
                }
                if (!(model instanceof Model)) {
                    model = this._createNewModel(model);
                }
                if (this._isServerGrouped()) {
                    this._data.splice(index, 0, this._wrapInEmptyGroup(model));
                } else {
                    this._data.splice(index, 0, model);
                }
                return model;
            },
            pushInsert: function (index, items) {
                if (!items) {
                    items = index;
                    index = 0;
                }
                if (!isArray(items)) {
                    items = [items];
                }
                var pushed = [];
                var autoSync = this.options.autoSync;
                this.options.autoSync = false;
                try {
                    for (var idx = 0; idx < items.length; idx++) {
                        var item = items[idx];
                        var result = this.insert(index, item);
                        pushed.push(result);
                        var pristine = result.toJSON();
                        if (this._isServerGrouped()) {
                            pristine = this._wrapInEmptyGroup(pristine);
                        }
                        this._pristineData.push(pristine);
                        index++;
                    }
                } finally {
                    this.options.autoSync = autoSync;
                }
                if (pushed.length) {
                    this.trigger('push', {
                        type: 'create',
                        items: pushed
                    });
                }
            },
            pushCreate: function (items) {
                this.pushInsert(this._data.length, items);
            },
            pushUpdate: function (items) {
                if (!isArray(items)) {
                    items = [items];
                }
                var pushed = [];
                for (var idx = 0; idx < items.length; idx++) {
                    var item = items[idx];
                    var model = this._createNewModel(item);
                    var target = this.get(model.id);
                    if (target) {
                        pushed.push(target);
                        target.accept(item);
                        target.trigger(CHANGE);
                        this._updatePristineForModel(target, item);
                    } else {
                        this.pushCreate(item);
                    }
                }
                if (pushed.length) {
                    this.trigger('push', {
                        type: 'update',
                        items: pushed
                    });
                }
            },
            pushDestroy: function (items) {
                var pushed = this._removeItems(items);
                if (pushed.length) {
                    this.trigger('push', {
                        type: 'destroy',
                        items: pushed
                    });
                }
            },
            _removeItems: function (items) {
                if (!isArray(items)) {
                    items = [items];
                }
                var destroyed = [];
                var autoSync = this.options.autoSync;
                this.options.autoSync = false;
                try {
                    for (var idx = 0; idx < items.length; idx++) {
                        var item = items[idx];
                        var model = this._createNewModel(item);
                        var found = false;
                        this._eachItem(this._data, function (items) {
                            for (var idx = 0; idx < items.length; idx++) {
                                var item = items.at(idx);
                                if (item.id === model.id) {
                                    destroyed.push(item);
                                    items.splice(idx, 1);
                                    found = true;
                                    break;
                                }
                            }
                        });
                        if (found) {
                            this._removePristineForModel(model);
                            this._destroyed.pop();
                        }
                    }
                } finally {
                    this.options.autoSync = autoSync;
                }
                return destroyed;
            },
            remove: function (model) {
                var result, that = this, hasGroups = that._isServerGrouped();
                this._eachItem(that._data, function (items) {
                    result = removeModel(items, model);
                    if (result && hasGroups) {
                        if (!result.isNew || !result.isNew()) {
                            that._destroyed.push(result);
                        }
                        return true;
                    }
                });
                this._removeModelFromRanges(model);
                this._updateRangesLength();
                return model;
            },
            destroyed: function () {
                return this._destroyed;
            },
            created: function () {
                var idx, length, result = [], data = this._flatData(this._data);
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].isNew && data[idx].isNew()) {
                        result.push(data[idx]);
                    }
                }
                return result;
            },
            updated: function () {
                var idx, length, result = [], data = this._flatData(this._data);
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].isNew && !data[idx].isNew() && data[idx].dirty) {
                        result.push(data[idx]);
                    }
                }
                return result;
            },
            sync: function () {
                var that = this, created = [], updated = [], destroyed = that._destroyed;
                var promise = $.Deferred().resolve().promise();
                if (that.online()) {
                    if (!that.reader.model) {
                        return promise;
                    }
                    created = that.created();
                    updated = that.updated();
                    var promises = [];
                    if (that.options.batch && that.transport.submit) {
                        promises = that._sendSubmit(created, updated, destroyed);
                    } else {
                        promises.push.apply(promises, that._send('create', created));
                        promises.push.apply(promises, that._send('update', updated));
                        promises.push.apply(promises, that._send('destroy', destroyed));
                    }
                    promise = $.when.apply(null, promises).then(function () {
                        var idx, length;
                        for (idx = 0, length = arguments.length; idx < length; idx++) {
                            if (arguments[idx]) {
                                that._accept(arguments[idx]);
                            }
                        }
                        that._storeData(true);
                        that._change({ action: 'sync' });
                        that.trigger(SYNC);
                    });
                } else {
                    that._storeData(true);
                    that._change({ action: 'sync' });
                }
                return promise;
            },
            cancelChanges: function (model) {
                var that = this;
                if (model instanceof kendo.data.Model) {
                    that._cancelModel(model);
                } else {
                    that._destroyed = [];
                    that._detachObservableParents();
                    that._data = that._observe(that._pristineData);
                    if (that.options.serverPaging) {
                        that._total = that._pristineTotal;
                    }
                    that._ranges = [];
                    that._addRange(that._data);
                    that._change();
                    that._markOfflineUpdatesAsDirty();
                }
            },
            _markOfflineUpdatesAsDirty: function () {
                var that = this;
                if (that.options.offlineStorage != null) {
                    that._eachItem(that._data, function (items) {
                        for (var idx = 0; idx < items.length; idx++) {
                            var item = items.at(idx);
                            if (item.__state__ == 'update' || item.__state__ == 'create') {
                                item.dirty = true;
                            }
                        }
                    });
                }
            },
            hasChanges: function () {
                var idx, length, data = this._flatData(this._data);
                if (this._destroyed.length) {
                    return true;
                }
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].isNew && data[idx].isNew() || data[idx].dirty) {
                        return true;
                    }
                }
                return false;
            },
            _accept: function (result) {
                var that = this, models = result.models, response = result.response, idx = 0, serverGroup = that._isServerGrouped(), pristine = that._pristineData, type = result.type, length;
                that.trigger(REQUESTEND, {
                    response: response,
                    type: type
                });
                if (response && !isEmptyObject(response)) {
                    response = that.reader.parse(response);
                    if (that._handleCustomErrors(response)) {
                        return;
                    }
                    response = that.reader.data(response);
                    if (!isArray(response)) {
                        response = [response];
                    }
                } else {
                    response = $.map(models, function (model) {
                        return model.toJSON();
                    });
                }
                if (type === 'destroy') {
                    that._destroyed = [];
                }
                for (idx = 0, length = models.length; idx < length; idx++) {
                    if (type !== 'destroy') {
                        models[idx].accept(response[idx]);
                        if (type === 'create') {
                            pristine.push(serverGroup ? that._wrapInEmptyGroup(models[idx]) : response[idx]);
                        } else if (type === 'update') {
                            that._updatePristineForModel(models[idx], response[idx]);
                        }
                    } else {
                        that._removePristineForModel(models[idx]);
                    }
                }
            },
            _updatePristineForModel: function (model, values) {
                this._executeOnPristineForModel(model, function (index, items) {
                    kendo.deepExtend(items[index], values);
                });
            },
            _executeOnPristineForModel: function (model, callback) {
                this._eachPristineItem(function (items) {
                    var index = indexOfPristineModel(items, model);
                    if (index > -1) {
                        callback(index, items);
                        return true;
                    }
                });
            },
            _removePristineForModel: function (model) {
                this._executeOnPristineForModel(model, function (index, items) {
                    items.splice(index, 1);
                });
            },
            _readData: function (data) {
                var read = !this._isServerGrouped() ? this.reader.data : this.reader.groups;
                return read.call(this.reader, data);
            },
            _eachPristineItem: function (callback) {
                this._eachItem(this._pristineData, callback);
            },
            _eachItem: function (data, callback) {
                if (data && data.length) {
                    if (this._isServerGrouped()) {
                        eachGroupItems(data, callback);
                    } else {
                        callback(data);
                    }
                }
            },
            _pristineForModel: function (model) {
                var pristine, idx, callback = function (items) {
                        idx = indexOfPristineModel(items, model);
                        if (idx > -1) {
                            pristine = items[idx];
                            return true;
                        }
                    };
                this._eachPristineItem(callback);
                return pristine;
            },
            _cancelModel: function (model) {
                var pristine = this._pristineForModel(model);
                this._eachItem(this._data, function (items) {
                    var idx = indexOfModel(items, model);
                    if (idx >= 0) {
                        if (pristine && (!model.isNew() || pristine.__state__)) {
                            items[idx].accept(pristine);
                            if (pristine.__state__ == 'update') {
                                items[idx].dirty = true;
                            }
                        } else {
                            items.splice(idx, 1);
                        }
                    }
                });
            },
            _submit: function (promises, data) {
                var that = this;
                that.trigger(REQUESTSTART, { type: 'submit' });
                that.trigger(PROGRESS);
                that.transport.submit(extend({
                    success: function (response, type) {
                        var promise = $.grep(promises, function (x) {
                            return x.type == type;
                        })[0];
                        if (promise) {
                            promise.resolve({
                                response: response,
                                models: promise.models,
                                type: type
                            });
                        }
                    },
                    error: function (response, status, error) {
                        for (var idx = 0; idx < promises.length; idx++) {
                            promises[idx].reject(response);
                        }
                        that.error(response, status, error);
                    }
                }, data));
            },
            _sendSubmit: function (created, updated, destroyed) {
                var that = this, promises = [];
                if (that.options.batch) {
                    if (created.length) {
                        promises.push($.Deferred(function (deferred) {
                            deferred.type = 'create';
                            deferred.models = created;
                        }));
                    }
                    if (updated.length) {
                        promises.push($.Deferred(function (deferred) {
                            deferred.type = 'update';
                            deferred.models = updated;
                        }));
                    }
                    if (destroyed.length) {
                        promises.push($.Deferred(function (deferred) {
                            deferred.type = 'destroy';
                            deferred.models = destroyed;
                        }));
                    }
                    that._submit(promises, {
                        data: {
                            created: that.reader.serialize(toJSON(created)),
                            updated: that.reader.serialize(toJSON(updated)),
                            destroyed: that.reader.serialize(toJSON(destroyed))
                        }
                    });
                }
                return promises;
            },
            _promise: function (data, models, type) {
                var that = this;
                return $.Deferred(function (deferred) {
                    that.trigger(REQUESTSTART, { type: type });
                    that.trigger(PROGRESS);
                    that.transport[type].call(that.transport, extend({
                        success: function (response) {
                            deferred.resolve({
                                response: response,
                                models: models,
                                type: type
                            });
                        },
                        error: function (response, status, error) {
                            deferred.reject(response);
                            that.error(response, status, error);
                        }
                    }, data));
                }).promise();
            },
            _send: function (method, data) {
                var that = this, idx, length, promises = [], converted = that.reader.serialize(toJSON(data));
                if (that.options.batch) {
                    if (data.length) {
                        promises.push(that._promise({ data: { models: converted } }, data, method));
                    }
                } else {
                    for (idx = 0, length = data.length; idx < length; idx++) {
                        promises.push(that._promise({ data: converted[idx] }, [data[idx]], method));
                    }
                }
                return promises;
            },
            read: function (data) {
                var that = this, params = that._params(data);
                var deferred = $.Deferred();
                that._queueRequest(params, function () {
                    var isPrevented = that.trigger(REQUESTSTART, { type: 'read' });
                    if (!isPrevented) {
                        that.trigger(PROGRESS);
                        that._ranges = [];
                        that.trigger('reset');
                        if (that.online()) {
                            that.transport.read({
                                data: params,
                                success: function (data) {
                                    that._ranges = [];
                                    that.success(data, params);
                                    deferred.resolve();
                                },
                                error: function () {
                                    var args = slice.call(arguments);
                                    that.error.apply(that, args);
                                    deferred.reject.apply(deferred, args);
                                }
                            });
                        } else if (that.options.offlineStorage != null) {
                            that.success(that.offlineData(), params);
                            deferred.resolve();
                        }
                    } else {
                        that._dequeueRequest();
                        deferred.resolve(isPrevented);
                    }
                });
                return deferred.promise();
            },
            _readAggregates: function (data) {
                return this.reader.aggregates(data);
            },
            success: function (data) {
                var that = this, options = that.options;
                that.trigger(REQUESTEND, {
                    response: data,
                    type: 'read'
                });
                if (that.online()) {
                    data = that.reader.parse(data);
                    if (that._handleCustomErrors(data)) {
                        that._dequeueRequest();
                        return;
                    }
                    that._total = that.reader.total(data);
                    if (that._aggregate && options.serverAggregates) {
                        that._aggregateResult = that._readAggregates(data);
                    }
                    data = that._readData(data);
                    that._destroyed = [];
                } else {
                    data = that._readData(data);
                    var items = [];
                    var itemIds = {};
                    var model = that.reader.model;
                    var idField = model ? model.idField : 'id';
                    var idx;
                    for (idx = 0; idx < this._destroyed.length; idx++) {
                        var id = this._destroyed[idx][idField];
                        itemIds[id] = id;
                    }
                    for (idx = 0; idx < data.length; idx++) {
                        var item = data[idx];
                        var state = item.__state__;
                        if (state == 'destroy') {
                            if (!itemIds[item[idField]]) {
                                this._destroyed.push(this._createNewModel(item));
                            }
                        } else {
                            items.push(item);
                        }
                    }
                    data = items;
                    that._total = data.length;
                }
                that._pristineTotal = that._total;
                that._pristineData = data.slice(0);
                that._detachObservableParents();
                that._data = that._observe(data);
                that._markOfflineUpdatesAsDirty();
                that._storeData();
                that._addRange(that._data);
                that._process(that._data);
                that._dequeueRequest();
            },
            _detachObservableParents: function () {
                if (this._data && this._shouldDetachObservableParents) {
                    for (var idx = 0; idx < this._data.length; idx++) {
                        if (this._data[idx].parent) {
                            this._data[idx].parent = noop;
                        }
                    }
                }
            },
            _storeData: function (updatePristine) {
                var serverGrouping = this._isServerGrouped();
                var model = this.reader.model;
                function items(data) {
                    var state = [];
                    for (var idx = 0; idx < data.length; idx++) {
                        var dataItem = data.at(idx);
                        var item = dataItem.toJSON();
                        if (serverGrouping && dataItem.items) {
                            item.items = items(dataItem.items);
                        } else {
                            item.uid = dataItem.uid;
                            if (model) {
                                if (dataItem.isNew()) {
                                    item.__state__ = 'create';
                                } else if (dataItem.dirty) {
                                    item.__state__ = 'update';
                                }
                            }
                        }
                        state.push(item);
                    }
                    return state;
                }
                if (this.options.offlineStorage != null) {
                    var state = items(this._data);
                    var destroyed = [];
                    for (var idx = 0; idx < this._destroyed.length; idx++) {
                        var item = this._destroyed[idx].toJSON();
                        item.__state__ = 'destroy';
                        destroyed.push(item);
                    }
                    this.offlineData(state.concat(destroyed));
                    if (updatePristine) {
                        this._pristineData = this._readData(state);
                    }
                }
            },
            _addRange: function (data) {
                var that = this, start = that._skip || 0, end = start + that._flatData(data, true).length;
                that._ranges.push({
                    start: start,
                    end: end,
                    data: data,
                    timestamp: new Date().getTime()
                });
                that._ranges.sort(function (x, y) {
                    return x.start - y.start;
                });
            },
            error: function (xhr, status, errorThrown) {
                this._dequeueRequest();
                this.trigger(REQUESTEND, {});
                this.trigger(ERROR, {
                    xhr: xhr,
                    status: status,
                    errorThrown: errorThrown
                });
            },
            _params: function (data) {
                var that = this, options = extend({
                        take: that.take(),
                        skip: that.skip(),
                        page: that.page(),
                        pageSize: that.pageSize(),
                        sort: that._sort,
                        filter: that._filter,
                        group: that._group,
                        aggregate: that._aggregate
                    }, data);
                if (!that.options.serverPaging) {
                    delete options.take;
                    delete options.skip;
                    delete options.page;
                    delete options.pageSize;
                }
                if (!that.options.serverGrouping) {
                    delete options.group;
                } else if (that.reader.model && options.group) {
                    options.group = convertDescriptorsField(options.group, that.reader.model);
                }
                if (!that.options.serverFiltering) {
                    delete options.filter;
                } else if (that.reader.model && options.filter) {
                    options.filter = convertFilterDescriptorsField(options.filter, that.reader.model);
                }
                if (!that.options.serverSorting) {
                    delete options.sort;
                } else if (that.reader.model && options.sort) {
                    options.sort = convertDescriptorsField(options.sort, that.reader.model);
                }
                if (!that.options.serverAggregates) {
                    delete options.aggregate;
                } else if (that.reader.model && options.aggregate) {
                    options.aggregate = convertDescriptorsField(options.aggregate, that.reader.model);
                }
                return options;
            },
            _queueRequest: function (options, callback) {
                var that = this;
                if (!that._requestInProgress) {
                    that._requestInProgress = true;
                    that._pending = undefined;
                    callback();
                } else {
                    that._pending = {
                        callback: proxy(callback, that),
                        options: options
                    };
                }
            },
            _dequeueRequest: function () {
                var that = this;
                that._requestInProgress = false;
                if (that._pending) {
                    that._queueRequest(that._pending.options, that._pending.callback);
                }
            },
            _handleCustomErrors: function (response) {
                if (this.reader.errors) {
                    var errors = this.reader.errors(response);
                    if (errors) {
                        this.trigger(ERROR, {
                            xhr: null,
                            status: 'customerror',
                            errorThrown: 'custom error',
                            errors: errors
                        });
                        return true;
                    }
                }
                return false;
            },
            _shouldWrap: function (data) {
                var model = this.reader.model;
                if (model && data.length) {
                    return !(data[0] instanceof model);
                }
                return false;
            },
            _observe: function (data) {
                var that = this, model = that.reader.model;
                that._shouldDetachObservableParents = true;
                if (data instanceof ObservableArray) {
                    that._shouldDetachObservableParents = false;
                    if (that._shouldWrap(data)) {
                        data.type = that.reader.model;
                        data.wrapAll(data, data);
                    }
                } else {
                    var arrayType = that.pageSize() && !that.options.serverPaging ? LazyObservableArray : ObservableArray;
                    data = new arrayType(data, that.reader.model);
                    data.parent = function () {
                        return that.parent();
                    };
                }
                if (that._isServerGrouped()) {
                    wrapGroupItems(data, model);
                }
                if (that._changeHandler && that._data && that._data instanceof ObservableArray) {
                    that._data.unbind(CHANGE, that._changeHandler);
                } else {
                    that._changeHandler = proxy(that._change, that);
                }
                return data.bind(CHANGE, that._changeHandler);
            },
            _updateTotalForAction: function (action, items) {
                var that = this;
                var total = parseInt(that._total, 10);
                if (!isNumber(that._total)) {
                    total = parseInt(that._pristineTotal, 10);
                }
                if (action === 'add') {
                    total += items.length;
                } else if (action === 'remove') {
                    total -= items.length;
                } else if (action !== 'itemchange' && action !== 'sync' && !that.options.serverPaging) {
                    total = that._pristineTotal;
                } else if (action === 'sync') {
                    total = that._pristineTotal = parseInt(that._total, 10);
                }
                that._total = total;
            },
            _change: function (e) {
                var that = this, idx, length, action = e ? e.action : '';
                if (action === 'remove') {
                    for (idx = 0, length = e.items.length; idx < length; idx++) {
                        if (!e.items[idx].isNew || !e.items[idx].isNew()) {
                            that._destroyed.push(e.items[idx]);
                        }
                    }
                }
                if (that.options.autoSync && (action === 'add' || action === 'remove' || action === 'itemchange')) {
                    var handler = function (args) {
                        if (args.action === 'sync') {
                            that.unbind('change', handler);
                            that._updateTotalForAction(action, e.items);
                        }
                    };
                    that.first('change', handler);
                    that.sync();
                } else {
                    that._updateTotalForAction(action, e ? e.items : []);
                    that._process(that._data, e);
                }
            },
            _calculateAggregates: function (data, options) {
                options = options || {};
                var query = new Query(data), aggregates = options.aggregate, filter = options.filter;
                if (filter) {
                    query = query.filter(filter);
                }
                return query.aggregate(aggregates);
            },
            _process: function (data, e) {
                var that = this, options = {}, result;
                if (that.options.serverPaging !== true) {
                    options.skip = that._skip;
                    options.take = that._take || that._pageSize;
                    if (options.skip === undefined && that._page !== undefined && that._pageSize !== undefined) {
                        options.skip = (that._page - 1) * that._pageSize;
                    }
                }
                if (that.options.serverSorting !== true) {
                    options.sort = that._sort;
                }
                if (that.options.serverFiltering !== true) {
                    options.filter = that._filter;
                }
                if (that.options.serverGrouping !== true) {
                    options.group = that._group;
                }
                if (that.options.serverAggregates !== true) {
                    options.aggregate = that._aggregate;
                    that._aggregateResult = that._calculateAggregates(data, options);
                }
                result = that._queryProcess(data, options);
                that.view(result.data);
                if (result.total !== undefined && !that.options.serverFiltering) {
                    that._total = result.total;
                }
                e = e || {};
                e.items = e.items || that._view;
                that.trigger(CHANGE, e);
            },
            _queryProcess: function (data, options) {
                return Query.process(data, options);
            },
            _mergeState: function (options) {
                var that = this;
                if (options !== undefined) {
                    that._pageSize = options.pageSize;
                    that._page = options.page;
                    that._sort = options.sort;
                    that._filter = options.filter;
                    that._group = options.group;
                    that._aggregate = options.aggregate;
                    that._skip = that._currentRangeStart = options.skip;
                    that._take = options.take;
                    if (that._skip === undefined) {
                        that._skip = that._currentRangeStart = that.skip();
                        options.skip = that.skip();
                    }
                    if (that._take === undefined && that._pageSize !== undefined) {
                        that._take = that._pageSize;
                        options.take = that._take;
                    }
                    if (options.sort) {
                        that._sort = options.sort = normalizeSort(options.sort);
                    }
                    if (options.filter) {
                        that._filter = options.filter = normalizeFilter(options.filter);
                    }
                    if (options.group) {
                        that._group = options.group = normalizeGroup(options.group);
                    }
                    if (options.aggregate) {
                        that._aggregate = options.aggregate = normalizeAggregate(options.aggregate);
                    }
                }
                return options;
            },
            query: function (options) {
                var result;
                var remote = this.options.serverSorting || this.options.serverPaging || this.options.serverFiltering || this.options.serverGrouping || this.options.serverAggregates;
                if (remote || (this._data === undefined || this._data.length === 0) && !this._destroyed.length) {
                    return this.read(this._mergeState(options));
                }
                var isPrevented = this.trigger(REQUESTSTART, { type: 'read' });
                if (!isPrevented) {
                    this.trigger(PROGRESS);
                    result = this._queryProcess(this._data, this._mergeState(options));
                    if (!this.options.serverFiltering) {
                        if (result.total !== undefined) {
                            this._total = result.total;
                        } else {
                            this._total = this._data.length;
                        }
                    }
                    this._aggregateResult = this._calculateAggregates(this._data, options);
                    this.view(result.data);
                    this.trigger(REQUESTEND, { type: 'read' });
                    this.trigger(CHANGE, { items: result.data });
                }
                return $.Deferred().resolve(isPrevented).promise();
            },
            fetch: function (callback) {
                var that = this;
                var fn = function (isPrevented) {
                    if (isPrevented !== true && isFunction(callback)) {
                        callback.call(that);
                    }
                };
                return this._query().then(fn);
            },
            _query: function (options) {
                var that = this;
                return that.query(extend({}, {
                    page: that.page(),
                    pageSize: that.pageSize(),
                    sort: that.sort(),
                    filter: that.filter(),
                    group: that.group(),
                    aggregate: that.aggregate()
                }, options));
            },
            next: function (options) {
                var that = this, page = that.page(), total = that.total();
                options = options || {};
                if (!page || total && page + 1 > that.totalPages()) {
                    return;
                }
                that._skip = that._currentRangeStart = page * that.take();
                page += 1;
                options.page = page;
                that._query(options);
                return page;
            },
            prev: function (options) {
                var that = this, page = that.page();
                options = options || {};
                if (!page || page === 1) {
                    return;
                }
                that._skip = that._currentRangeStart = that._skip - that.take();
                page -= 1;
                options.page = page;
                that._query(options);
                return page;
            },
            page: function (val) {
                var that = this, skip;
                if (val !== undefined) {
                    val = math.max(math.min(math.max(val, 1), that.totalPages()), 1);
                    that._query({ page: val });
                    return;
                }
                skip = that.skip();
                return skip !== undefined ? math.round((skip || 0) / (that.take() || 1)) + 1 : undefined;
            },
            pageSize: function (val) {
                var that = this;
                if (val !== undefined) {
                    that._query({
                        pageSize: val,
                        page: 1
                    });
                    return;
                }
                return that.take();
            },
            sort: function (val) {
                var that = this;
                if (val !== undefined) {
                    that._query({ sort: val });
                    return;
                }
                return that._sort;
            },
            filter: function (val) {
                var that = this;
                if (val === undefined) {
                    return that._filter;
                }
                that.trigger('reset');
                that._query({
                    filter: val,
                    page: 1
                });
            },
            group: function (val) {
                var that = this;
                if (val !== undefined) {
                    that._query({ group: val });
                    return;
                }
                return that._group;
            },
            total: function () {
                return parseInt(this._total || 0, 10);
            },
            aggregate: function (val) {
                var that = this;
                if (val !== undefined) {
                    that._query({ aggregate: val });
                    return;
                }
                return that._aggregate;
            },
            aggregates: function () {
                var result = this._aggregateResult;
                if (isEmptyObject(result)) {
                    result = this._emptyAggregates(this.aggregate());
                }
                return result;
            },
            _emptyAggregates: function (aggregates) {
                var result = {};
                if (!isEmptyObject(aggregates)) {
                    var aggregate = {};
                    if (!isArray(aggregates)) {
                        aggregates = [aggregates];
                    }
                    for (var idx = 0; idx < aggregates.length; idx++) {
                        aggregate[aggregates[idx].aggregate] = 0;
                        result[aggregates[idx].field] = aggregate;
                    }
                }
                return result;
            },
            _wrapInEmptyGroup: function (model) {
                var groups = this.group(), parent, group, idx, length;
                for (idx = groups.length - 1, length = 0; idx >= length; idx--) {
                    group = groups[idx];
                    parent = {
                        value: model.get(group.field),
                        field: group.field,
                        items: parent ? [parent] : [model],
                        hasSubgroups: !!parent,
                        aggregates: this._emptyAggregates(group.aggregates)
                    };
                }
                return parent;
            },
            totalPages: function () {
                var that = this, pageSize = that.pageSize() || that.total();
                return math.ceil((that.total() || 0) / pageSize);
            },
            inRange: function (skip, take) {
                var that = this, end = math.min(skip + take, that.total());
                if (!that.options.serverPaging && that._data.length > 0) {
                    return true;
                }
                return that._findRange(skip, end).length > 0;
            },
            lastRange: function () {
                var ranges = this._ranges;
                return ranges[ranges.length - 1] || {
                    start: 0,
                    end: 0,
                    data: []
                };
            },
            firstItemUid: function () {
                var ranges = this._ranges;
                return ranges.length && ranges[0].data.length && ranges[0].data[0].uid;
            },
            enableRequestsInProgress: function () {
                this._skipRequestsInProgress = false;
            },
            _timeStamp: function () {
                return new Date().getTime();
            },
            range: function (skip, take) {
                this._currentRequestTimeStamp = this._timeStamp();
                this._skipRequestsInProgress = true;
                skip = math.min(skip || 0, this.total());
                var that = this, pageSkip = math.max(math.floor(skip / take), 0) * take, size = math.min(pageSkip + take, that.total()), data;
                data = that._findRange(skip, math.min(skip + take, that.total()));
                if (data.length) {
                    that._pending = undefined;
                    that._skip = skip > that.skip() ? math.min(size, (that.totalPages() - 1) * that.take()) : pageSkip;
                    that._currentRangeStart = skip;
                    that._take = take;
                    var paging = that.options.serverPaging;
                    var sorting = that.options.serverSorting;
                    var filtering = that.options.serverFiltering;
                    var aggregates = that.options.serverAggregates;
                    try {
                        that.options.serverPaging = true;
                        if (!that._isServerGrouped() && !(that.group() && that.group().length)) {
                            that.options.serverSorting = true;
                        }
                        that.options.serverFiltering = true;
                        that.options.serverPaging = true;
                        that.options.serverAggregates = true;
                        if (paging) {
                            that._detachObservableParents();
                            that._data = data = that._observe(data);
                        }
                        that._process(data);
                    } finally {
                        that.options.serverPaging = paging;
                        that.options.serverSorting = sorting;
                        that.options.serverFiltering = filtering;
                        that.options.serverAggregates = aggregates;
                    }
                    return;
                }
                if (take !== undefined) {
                    if (!that._rangeExists(pageSkip, size)) {
                        that.prefetch(pageSkip, take, function () {
                            if (skip > pageSkip && size < that.total() && !that._rangeExists(size, math.min(size + take, that.total()))) {
                                that.prefetch(size, take, function () {
                                    that.range(skip, take);
                                });
                            } else {
                                that.range(skip, take);
                            }
                        });
                    } else if (pageSkip < skip) {
                        that.prefetch(size, take, function () {
                            that.range(skip, take);
                        });
                    }
                }
            },
            _findRange: function (start, end) {
                var that = this, ranges = that._ranges, range, data = [], skipIdx, takeIdx, startIndex, endIndex, rangeData, rangeEnd, processed, options = that.options, remote = options.serverSorting || options.serverPaging || options.serverFiltering || options.serverGrouping || options.serverAggregates, flatData, count, length;
                for (skipIdx = 0, length = ranges.length; skipIdx < length; skipIdx++) {
                    range = ranges[skipIdx];
                    if (start >= range.start && start <= range.end) {
                        count = 0;
                        for (takeIdx = skipIdx; takeIdx < length; takeIdx++) {
                            range = ranges[takeIdx];
                            flatData = that._flatData(range.data, true);
                            if (flatData.length && start + count >= range.start) {
                                rangeData = range.data;
                                rangeEnd = range.end;
                                if (!remote) {
                                    var sort = normalizeGroup(that.group() || []).concat(normalizeSort(that.sort() || []));
                                    processed = that._queryProcess(range.data, {
                                        sort: sort,
                                        filter: that.filter()
                                    });
                                    flatData = rangeData = processed.data;
                                    if (processed.total !== undefined) {
                                        rangeEnd = processed.total;
                                    }
                                }
                                startIndex = 0;
                                if (start + count > range.start) {
                                    startIndex = start + count - range.start;
                                }
                                endIndex = flatData.length;
                                if (rangeEnd > end) {
                                    endIndex = endIndex - (rangeEnd - end);
                                }
                                count += endIndex - startIndex;
                                data = that._mergeGroups(data, rangeData, startIndex, endIndex);
                                if (end <= range.end && count == end - start) {
                                    return data;
                                }
                            }
                        }
                        break;
                    }
                }
                return [];
            },
            _mergeGroups: function (data, range, skip, take) {
                if (this._isServerGrouped()) {
                    var temp = range.toJSON(), prevGroup;
                    if (data.length) {
                        prevGroup = data[data.length - 1];
                    }
                    mergeGroups(prevGroup, temp, skip, take);
                    return data.concat(temp);
                }
                return data.concat(range.slice(skip, take));
            },
            skip: function () {
                var that = this;
                if (that._skip === undefined) {
                    return that._page !== undefined ? (that._page - 1) * (that.take() || 1) : undefined;
                }
                return that._skip;
            },
            currentRangeStart: function () {
                return this._currentRangeStart || 0;
            },
            take: function () {
                return this._take || this._pageSize;
            },
            _prefetchSuccessHandler: function (skip, size, callback, force) {
                var that = this;
                var timestamp = that._timeStamp();
                return function (data) {
                    var found = false, range = {
                            start: skip,
                            end: size,
                            data: [],
                            timestamp: that._timeStamp()
                        }, idx, length, temp;
                    that._dequeueRequest();
                    that.trigger(REQUESTEND, {
                        response: data,
                        type: 'read'
                    });
                    data = that.reader.parse(data);
                    temp = that._readData(data);
                    if (temp.length) {
                        for (idx = 0, length = that._ranges.length; idx < length; idx++) {
                            if (that._ranges[idx].start === skip) {
                                found = true;
                                range = that._ranges[idx];
                                break;
                            }
                        }
                        if (!found) {
                            that._ranges.push(range);
                        }
                    }
                    range.data = that._observe(temp);
                    range.end = range.start + that._flatData(range.data, true).length;
                    that._ranges.sort(function (x, y) {
                        return x.start - y.start;
                    });
                    that._total = that.reader.total(data);
                    if (force || (timestamp >= that._currentRequestTimeStamp || !that._skipRequestsInProgress)) {
                        if (callback && temp.length) {
                            callback();
                        } else {
                            that.trigger(CHANGE, {});
                        }
                    }
                };
            },
            prefetch: function (skip, take, callback) {
                var that = this, size = math.min(skip + take, that.total()), options = {
                        take: take,
                        skip: skip,
                        page: skip / take + 1,
                        pageSize: take,
                        sort: that._sort,
                        filter: that._filter,
                        group: that._group,
                        aggregate: that._aggregate
                    };
                if (!that._rangeExists(skip, size)) {
                    clearTimeout(that._timeout);
                    that._timeout = setTimeout(function () {
                        that._queueRequest(options, function () {
                            if (!that.trigger(REQUESTSTART, { type: 'read' })) {
                                that.transport.read({
                                    data: that._params(options),
                                    success: that._prefetchSuccessHandler(skip, size, callback),
                                    error: function () {
                                        var args = slice.call(arguments);
                                        that.error.apply(that, args);
                                    }
                                });
                            } else {
                                that._dequeueRequest();
                            }
                        });
                    }, 100);
                } else if (callback) {
                    callback();
                }
            },
            _multiplePrefetch: function (skip, take, callback) {
                var that = this, size = math.min(skip + take, that.total()), options = {
                        take: take,
                        skip: skip,
                        page: skip / take + 1,
                        pageSize: take,
                        sort: that._sort,
                        filter: that._filter,
                        group: that._group,
                        aggregate: that._aggregate
                    };
                if (!that._rangeExists(skip, size)) {
                    if (!that.trigger(REQUESTSTART, { type: 'read' })) {
                        that.transport.read({
                            data: that._params(options),
                            success: that._prefetchSuccessHandler(skip, size, callback, true)
                        });
                    }
                } else if (callback) {
                    callback();
                }
            },
            _rangeExists: function (start, end) {
                var that = this, ranges = that._ranges, idx, length;
                for (idx = 0, length = ranges.length; idx < length; idx++) {
                    if (ranges[idx].start <= start && ranges[idx].end >= end) {
                        return true;
                    }
                }
                return false;
            },
            _removeModelFromRanges: function (model) {
                var result, found, range;
                for (var idx = 0, length = this._ranges.length; idx < length; idx++) {
                    range = this._ranges[idx];
                    this._eachItem(range.data, function (items) {
                        result = removeModel(items, model);
                        if (result) {
                            found = true;
                        }
                    });
                    if (found) {
                        break;
                    }
                }
            },
            _updateRangesLength: function () {
                var startOffset = 0, range, rangeLength;
                for (var idx = 0, length = this._ranges.length; idx < length; idx++) {
                    range = this._ranges[idx];
                    range.start = range.start - startOffset;
                    rangeLength = this._flatData(range.data, true).length;
                    startOffset = range.end - rangeLength;
                    range.end = range.start + rangeLength;
                }
            }
        });
        var Transport = {};
        Transport.create = function (options, data, dataSource) {
            var transport, transportOptions = options.transport ? $.extend({}, options.transport) : null;
            if (transportOptions) {
                transportOptions.read = typeof transportOptions.read === STRING ? { url: transportOptions.read } : transportOptions.read;
                if (options.type === 'jsdo') {
                    transportOptions.dataSource = dataSource;
                }
                if (options.type) {
                    kendo.data.transports = kendo.data.transports || {};
                    kendo.data.schemas = kendo.data.schemas || {};
                    if (!kendo.data.transports[options.type]) {
                        kendo.logToConsole('Unknown DataSource transport type \'' + options.type + '\'.\nVerify that registration scripts for this type are included after Kendo UI on the page.', 'warn');
                    } else if (!isPlainObject(kendo.data.transports[options.type])) {
                        transport = new kendo.data.transports[options.type](extend(transportOptions, { data: data }));
                    } else {
                        transportOptions = extend(true, {}, kendo.data.transports[options.type], transportOptions);
                    }
                    options.schema = extend(true, {}, kendo.data.schemas[options.type], options.schema);
                }
                if (!transport) {
                    transport = isFunction(transportOptions.read) ? transportOptions : new RemoteTransport(transportOptions);
                }
            } else {
                transport = new LocalTransport({ data: options.data || [] });
            }
            return transport;
        };
        DataSource.create = function (options) {
            if (isArray(options) || options instanceof ObservableArray) {
                options = { data: options };
            }
            var dataSource = options || {}, data = dataSource.data, fields = dataSource.fields, table = dataSource.table, select = dataSource.select, idx, length, model = {}, field;
            if (!data && fields && !dataSource.transport) {
                if (table) {
                    data = inferTable(table, fields);
                } else if (select) {
                    data = inferSelect(select, fields);
                    if (dataSource.group === undefined && data[0] && data[0].optgroup !== undefined) {
                        dataSource.group = 'optgroup';
                    }
                }
            }
            if (kendo.data.Model && fields && (!dataSource.schema || !dataSource.schema.model)) {
                for (idx = 0, length = fields.length; idx < length; idx++) {
                    field = fields[idx];
                    if (field.type) {
                        model[field.field] = field;
                    }
                }
                if (!isEmptyObject(model)) {
                    dataSource.schema = extend(true, dataSource.schema, { model: { fields: model } });
                }
            }
            dataSource.data = data;
            select = null;
            dataSource.select = null;
            table = null;
            dataSource.table = null;
            return dataSource instanceof DataSource ? dataSource : new DataSource(dataSource);
        };
        function inferSelect(select, fields) {
            select = $(select)[0];
            var options = select.options;
            var firstField = fields[0];
            var secondField = fields[1];
            var data = [];
            var idx, length;
            var optgroup;
            var option;
            var record;
            var value;
            for (idx = 0, length = options.length; idx < length; idx++) {
                record = {};
                option = options[idx];
                optgroup = option.parentNode;
                if (optgroup === select) {
                    optgroup = null;
                }
                if (option.disabled || optgroup && optgroup.disabled) {
                    continue;
                }
                if (optgroup) {
                    record.optgroup = optgroup.label;
                }
                record[firstField.field] = option.text;
                value = option.attributes.value;
                if (value && value.specified) {
                    value = option.value;
                } else {
                    value = option.text;
                }
                record[secondField.field] = value;
                data.push(record);
            }
            return data;
        }
        function inferTable(table, fields) {
            var tbody = $(table)[0].tBodies[0], rows = tbody ? tbody.rows : [], idx, length, fieldIndex, fieldCount = fields.length, data = [], cells, record, cell, empty;
            for (idx = 0, length = rows.length; idx < length; idx++) {
                record = {};
                empty = true;
                cells = rows[idx].cells;
                for (fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
                    cell = cells[fieldIndex];
                    if (cell.nodeName.toLowerCase() !== 'th') {
                        empty = false;
                        record[fields[fieldIndex].field] = cell.innerHTML;
                    }
                }
                if (!empty) {
                    data.push(record);
                }
            }
            return data;
        }
        var Node = Model.define({
            idField: 'id',
            init: function (value) {
                var that = this, hasChildren = that.hasChildren || value && value.hasChildren, childrenField = 'items', childrenOptions = {};
                kendo.data.Model.fn.init.call(that, value);
                if (typeof that.children === STRING) {
                    childrenField = that.children;
                }
                childrenOptions = {
                    schema: {
                        data: childrenField,
                        model: {
                            hasChildren: hasChildren,
                            id: that.idField,
                            fields: that.fields
                        }
                    }
                };
                if (typeof that.children !== STRING) {
                    extend(childrenOptions, that.children);
                }
                childrenOptions.data = value;
                if (!hasChildren) {
                    hasChildren = childrenOptions.schema.data;
                }
                if (typeof hasChildren === STRING) {
                    hasChildren = kendo.getter(hasChildren);
                }
                if (isFunction(hasChildren)) {
                    that.hasChildren = !!hasChildren.call(that, that);
                }
                that._childrenOptions = childrenOptions;
                if (that.hasChildren) {
                    that._initChildren();
                }
                that._loaded = !!(value && value._loaded);
            },
            _initChildren: function () {
                var that = this;
                var children, transport, parameterMap;
                if (!(that.children instanceof HierarchicalDataSource)) {
                    children = that.children = new HierarchicalDataSource(that._childrenOptions);
                    transport = children.transport;
                    parameterMap = transport.parameterMap;
                    transport.parameterMap = function (data, type) {
                        data[that.idField || 'id'] = that.id;
                        if (parameterMap) {
                            data = parameterMap(data, type);
                        }
                        return data;
                    };
                    children.parent = function () {
                        return that;
                    };
                    children.bind(CHANGE, function (e) {
                        e.node = e.node || that;
                        that.trigger(CHANGE, e);
                    });
                    children.bind(ERROR, function (e) {
                        var collection = that.parent();
                        if (collection) {
                            e.node = e.node || that;
                            collection.trigger(ERROR, e);
                        }
                    });
                    that._updateChildrenField();
                }
            },
            append: function (model) {
                this._initChildren();
                this.loaded(true);
                this.children.add(model);
            },
            hasChildren: false,
            level: function () {
                var parentNode = this.parentNode(), level = 0;
                while (parentNode && parentNode.parentNode) {
                    level++;
                    parentNode = parentNode.parentNode ? parentNode.parentNode() : null;
                }
                return level;
            },
            _updateChildrenField: function () {
                var fieldName = this._childrenOptions.schema.data;
                this[fieldName || 'items'] = this.children.data();
            },
            _childrenLoaded: function () {
                this._loaded = true;
                this._updateChildrenField();
            },
            load: function () {
                var options = {};
                var method = '_query';
                var children, promise;
                if (this.hasChildren) {
                    this._initChildren();
                    children = this.children;
                    options[this.idField || 'id'] = this.id;
                    if (!this._loaded) {
                        children._data = undefined;
                        method = 'read';
                    }
                    children.one(CHANGE, proxy(this._childrenLoaded, this));
                    if (this._matchFilter) {
                        options.filter = {
                            field: '_matchFilter',
                            operator: 'eq',
                            value: true
                        };
                    }
                    promise = children[method](options);
                } else {
                    this.loaded(true);
                }
                return promise || $.Deferred().resolve().promise();
            },
            parentNode: function () {
                var array = this.parent();
                return array.parent();
            },
            loaded: function (value) {
                if (value !== undefined) {
                    this._loaded = value;
                } else {
                    return this._loaded;
                }
            },
            shouldSerialize: function (field) {
                return Model.fn.shouldSerialize.call(this, field) && field !== 'children' && field !== '_loaded' && field !== 'hasChildren' && field !== '_childrenOptions';
            }
        });
        function dataMethod(name) {
            return function () {
                var data = this._data, result = DataSource.fn[name].apply(this, slice.call(arguments));
                if (this._data != data) {
                    this._attachBubbleHandlers();
                }
                return result;
            };
        }
        var HierarchicalDataSource = DataSource.extend({
            init: function (options) {
                var node = Node.define({ children: options });
                if (options.filter) {
                    this._hierarchicalFilter = options.filter;
                    options.filter = null;
                }
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: node,
                        model: node
                    }
                }, options));
                this._attachBubbleHandlers();
            },
            _attachBubbleHandlers: function () {
                var that = this;
                that._data.bind(ERROR, function (e) {
                    that.trigger(ERROR, e);
                });
            },
            read: function (data) {
                var result = DataSource.fn.read.call(this, data);
                if (this._hierarchicalFilter) {
                    this.filter(this._hierarchicalFilter);
                }
                return result;
            },
            remove: function (node) {
                var parentNode = node.parentNode(), dataSource = this, result;
                if (parentNode && parentNode._initChildren) {
                    dataSource = parentNode.children;
                }
                result = DataSource.fn.remove.call(dataSource, node);
                if (parentNode && !dataSource.data().length) {
                    parentNode.hasChildren = false;
                }
                return result;
            },
            success: dataMethod('success'),
            data: dataMethod('data'),
            insert: function (index, model) {
                var parentNode = this.parent();
                if (parentNode && parentNode._initChildren) {
                    parentNode.hasChildren = true;
                    parentNode._initChildren();
                }
                return DataSource.fn.insert.call(this, index, model);
            },
            filter: function (val) {
                if (val === undefined) {
                    return this._filter;
                }
                if (!this.options.serverFiltering) {
                    this._markHierarchicalQuery(val);
                    val = {
                        logic: 'or',
                        filters: [
                            val,
                            {
                                field: '_matchFilter',
                                operator: 'equals',
                                value: true
                            }
                        ]
                    };
                }
                this.trigger('reset');
                this._query({
                    filter: val,
                    page: 1
                });
            },
            _markHierarchicalQuery: function (expressions) {
                var compiled;
                var predicate;
                var fields;
                var operators;
                var filter;
                expressions = normalizeFilter(expressions);
                if (!expressions || expressions.filters.length === 0) {
                    return this;
                }
                compiled = Query.filterExpr(expressions);
                fields = compiled.fields;
                operators = compiled.operators;
                predicate = filter = new Function('d, __f, __o', 'return ' + compiled.expression);
                if (fields.length || operators.length) {
                    filter = function (d) {
                        return predicate(d, fields, operators);
                    };
                }
                this._updateHierarchicalFilter(filter);
            },
            _updateHierarchicalFilter: function (filter) {
                var current;
                var data = this._data;
                var result = false;
                for (var idx = 0; idx < data.length; idx++) {
                    current = data[idx];
                    if (current.hasChildren) {
                        current._matchFilter = current.children._updateHierarchicalFilter(filter);
                        if (!current._matchFilter) {
                            current._matchFilter = filter(current);
                        }
                    } else {
                        current._matchFilter = filter(current);
                    }
                    if (current._matchFilter) {
                        result = true;
                    }
                }
                return result;
            },
            _find: function (method, value) {
                var idx, length, node, children;
                var data = this._data;
                if (!data) {
                    return;
                }
                node = DataSource.fn[method].call(this, value);
                if (node) {
                    return node;
                }
                data = this._flatData(this._data);
                for (idx = 0, length = data.length; idx < length; idx++) {
                    children = data[idx].children;
                    if (!(children instanceof HierarchicalDataSource)) {
                        continue;
                    }
                    node = children[method](value);
                    if (node) {
                        return node;
                    }
                }
            },
            get: function (id) {
                return this._find('get', id);
            },
            getByUid: function (uid) {
                return this._find('getByUid', uid);
            }
        });
        function inferList(list, fields) {
            var items = $(list).children(), idx, length, data = [], record, textField = fields[0].field, urlField = fields[1] && fields[1].field, spriteCssClassField = fields[2] && fields[2].field, imageUrlField = fields[3] && fields[3].field, item, id, textChild, className, children;
            function elements(collection, tagName) {
                return collection.filter(tagName).add(collection.find(tagName));
            }
            for (idx = 0, length = items.length; idx < length; idx++) {
                record = { _loaded: true };
                item = items.eq(idx);
                textChild = item[0].firstChild;
                children = item.children();
                list = children.filter('ul');
                children = children.filter(':not(ul)');
                id = item.attr('data-id');
                if (id) {
                    record.id = id;
                }
                if (textChild) {
                    record[textField] = textChild.nodeType == 3 ? textChild.nodeValue : children.text();
                }
                if (urlField) {
                    record[urlField] = elements(children, 'a').attr('href');
                }
                if (imageUrlField) {
                    record[imageUrlField] = elements(children, 'img').attr('src');
                }
                if (spriteCssClassField) {
                    className = elements(children, '.k-sprite').prop('className');
                    record[spriteCssClassField] = className && $.trim(className.replace('k-sprite', ''));
                }
                if (list.length) {
                    record.items = inferList(list.eq(0), fields);
                }
                if (item.attr('data-hasChildren') == 'true') {
                    record.hasChildren = true;
                }
                data.push(record);
            }
            return data;
        }
        HierarchicalDataSource.create = function (options) {
            options = options && options.push ? { data: options } : options;
            var dataSource = options || {}, data = dataSource.data, fields = dataSource.fields, list = dataSource.list;
            if (data && data._dataSource) {
                return data._dataSource;
            }
            if (!data && fields && !dataSource.transport) {
                if (list) {
                    data = inferList(list, fields);
                }
            }
            dataSource.data = data;
            return dataSource instanceof HierarchicalDataSource ? dataSource : new HierarchicalDataSource(dataSource);
        };
        var Buffer = kendo.Observable.extend({
            init: function (dataSource, viewSize, disablePrefetch) {
                kendo.Observable.fn.init.call(this);
                this._prefetching = false;
                this.dataSource = dataSource;
                this.prefetch = !disablePrefetch;
                var buffer = this;
                dataSource.bind('change', function () {
                    buffer._change();
                });
                dataSource.bind('reset', function () {
                    buffer._reset();
                });
                this._syncWithDataSource();
                this.setViewSize(viewSize);
            },
            setViewSize: function (viewSize) {
                this.viewSize = viewSize;
                this._recalculate();
            },
            at: function (index) {
                var pageSize = this.pageSize, itemPresent = true;
                if (index >= this.total()) {
                    this.trigger('endreached', { index: index });
                    return null;
                }
                if (!this.useRanges) {
                    return this.dataSource.view()[index];
                }
                if (this.useRanges) {
                    if (index < this.dataOffset || index >= this.skip + pageSize) {
                        itemPresent = this.range(Math.floor(index / pageSize) * pageSize);
                    }
                    if (index === this.prefetchThreshold) {
                        this._prefetch();
                    }
                    if (index === this.midPageThreshold) {
                        this.range(this.nextMidRange, true);
                    } else if (index === this.nextPageThreshold) {
                        this.range(this.nextFullRange);
                    } else if (index === this.pullBackThreshold) {
                        if (this.offset === this.skip) {
                            this.range(this.previousMidRange);
                        } else {
                            this.range(this.previousFullRange);
                        }
                    }
                    if (itemPresent) {
                        return this.dataSource.at(index - this.dataOffset);
                    } else {
                        this.trigger('endreached', { index: index });
                        return null;
                    }
                }
            },
            indexOf: function (item) {
                return this.dataSource.data().indexOf(item) + this.dataOffset;
            },
            total: function () {
                return parseInt(this.dataSource.total(), 10);
            },
            next: function () {
                var buffer = this, pageSize = buffer.pageSize, offset = buffer.skip - buffer.viewSize + pageSize, pageSkip = math.max(math.floor(offset / pageSize), 0) * pageSize;
                this.offset = offset;
                this.dataSource.prefetch(pageSkip, pageSize, function () {
                    buffer._goToRange(offset, true);
                });
            },
            range: function (offset, nextRange) {
                if (this.offset === offset) {
                    return true;
                }
                var buffer = this, pageSize = this.pageSize, pageSkip = math.max(math.floor(offset / pageSize), 0) * pageSize, dataSource = this.dataSource;
                if (nextRange) {
                    pageSkip += pageSize;
                }
                if (dataSource.inRange(offset, pageSize)) {
                    this.offset = offset;
                    this._recalculate();
                    this._goToRange(offset);
                    return true;
                } else if (this.prefetch) {
                    dataSource.prefetch(pageSkip, pageSize, function () {
                        buffer.offset = offset;
                        buffer._recalculate();
                        buffer._goToRange(offset, true);
                    });
                    return false;
                }
                return true;
            },
            syncDataSource: function () {
                var offset = this.offset;
                this.offset = null;
                this.range(offset);
            },
            destroy: function () {
                this.unbind();
            },
            _prefetch: function () {
                var buffer = this, pageSize = this.pageSize, prefetchOffset = this.skip + pageSize, dataSource = this.dataSource;
                if (!dataSource.inRange(prefetchOffset, pageSize) && !this._prefetching && this.prefetch) {
                    this._prefetching = true;
                    this.trigger('prefetching', {
                        skip: prefetchOffset,
                        take: pageSize
                    });
                    dataSource.prefetch(prefetchOffset, pageSize, function () {
                        buffer._prefetching = false;
                        buffer.trigger('prefetched', {
                            skip: prefetchOffset,
                            take: pageSize
                        });
                    });
                }
            },
            _goToRange: function (offset, expanding) {
                if (this.offset !== offset) {
                    return;
                }
                this.dataOffset = offset;
                this._expanding = expanding;
                this.dataSource.range(offset, this.pageSize);
                this.dataSource.enableRequestsInProgress();
            },
            _reset: function () {
                this._syncPending = true;
            },
            _change: function () {
                var dataSource = this.dataSource;
                this.length = this.useRanges ? dataSource.lastRange().end : dataSource.view().length;
                if (this._syncPending) {
                    this._syncWithDataSource();
                    this._recalculate();
                    this._syncPending = false;
                    this.trigger('reset', { offset: this.offset });
                }
                this.trigger('resize');
                if (this._expanding) {
                    this.trigger('expand');
                }
                delete this._expanding;
            },
            _syncWithDataSource: function () {
                var dataSource = this.dataSource;
                this._firstItemUid = dataSource.firstItemUid();
                this.dataOffset = this.offset = dataSource.skip() || 0;
                this.pageSize = dataSource.pageSize();
                this.useRanges = dataSource.options.serverPaging;
            },
            _recalculate: function () {
                var pageSize = this.pageSize, offset = this.offset, viewSize = this.viewSize, skip = Math.ceil(offset / pageSize) * pageSize;
                this.skip = skip;
                this.midPageThreshold = skip + pageSize - 1;
                this.nextPageThreshold = skip + viewSize - 1;
                this.prefetchThreshold = skip + Math.floor(pageSize / 3 * 2);
                this.pullBackThreshold = this.offset - 1;
                this.nextMidRange = skip + pageSize - viewSize;
                this.nextFullRange = skip;
                this.previousMidRange = offset - viewSize;
                this.previousFullRange = skip - pageSize;
            }
        });
        var BatchBuffer = kendo.Observable.extend({
            init: function (dataSource, batchSize) {
                var batchBuffer = this;
                kendo.Observable.fn.init.call(batchBuffer);
                this.dataSource = dataSource;
                this.batchSize = batchSize;
                this._total = 0;
                this.buffer = new Buffer(dataSource, batchSize * 3);
                this.buffer.bind({
                    'endreached': function (e) {
                        batchBuffer.trigger('endreached', { index: e.index });
                    },
                    'prefetching': function (e) {
                        batchBuffer.trigger('prefetching', {
                            skip: e.skip,
                            take: e.take
                        });
                    },
                    'prefetched': function (e) {
                        batchBuffer.trigger('prefetched', {
                            skip: e.skip,
                            take: e.take
                        });
                    },
                    'reset': function () {
                        batchBuffer._total = 0;
                        batchBuffer.trigger('reset');
                    },
                    'resize': function () {
                        batchBuffer._total = Math.ceil(this.length / batchBuffer.batchSize);
                        batchBuffer.trigger('resize', {
                            total: batchBuffer.total(),
                            offset: this.offset
                        });
                    }
                });
            },
            syncDataSource: function () {
                this.buffer.syncDataSource();
            },
            at: function (index) {
                var buffer = this.buffer, skip = index * this.batchSize, take = this.batchSize, view = [], item;
                if (buffer.offset > skip) {
                    buffer.at(buffer.offset - 1);
                }
                for (var i = 0; i < take; i++) {
                    item = buffer.at(skip + i);
                    if (item === null) {
                        break;
                    }
                    view.push(item);
                }
                return view;
            },
            total: function () {
                return this._total;
            },
            destroy: function () {
                this.buffer.destroy();
                this.unbind();
            }
        });
        extend(true, kendo.data, {
            readers: { json: DataReader },
            Query: Query,
            DataSource: DataSource,
            HierarchicalDataSource: HierarchicalDataSource,
            Node: Node,
            ObservableObject: ObservableObject,
            ObservableArray: ObservableArray,
            LazyObservableArray: LazyObservableArray,
            LocalTransport: LocalTransport,
            RemoteTransport: RemoteTransport,
            Cache: Cache,
            DataReader: DataReader,
            Model: Model,
            Buffer: Buffer,
            BatchBuffer: BatchBuffer
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.binder', [
        'kendo.core',
        'kendo.data'
    ], f);
}(function () {
    var __meta__ = {
        id: 'binder',
        name: 'MVVM',
        category: 'framework',
        description: 'Model View ViewModel (MVVM) is a design pattern which helps developers separate the Model (the data) from the View (the UI).',
        depends: [
            'core',
            'data'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Observable = kendo.Observable, ObservableObject = kendo.data.ObservableObject, ObservableArray = kendo.data.ObservableArray, toString = {}.toString, binders = {}, Class = kendo.Class, proxy = $.proxy, VALUE = 'value', SOURCE = 'source', EVENTS = 'events', CHECKED = 'checked', CSS = 'css', deleteExpando = true, FUNCTION = 'function', CHANGE = 'change';
        (function () {
            var a = document.createElement('a');
            try {
                delete a.test;
            } catch (e) {
                deleteExpando = false;
            }
        }());
        var Binding = Observable.extend({
            init: function (parents, path) {
                var that = this;
                Observable.fn.init.call(that);
                that.source = parents[0];
                that.parents = parents;
                that.path = path;
                that.dependencies = {};
                that.dependencies[path] = true;
                that.observable = that.source instanceof Observable;
                that._access = function (e) {
                    that.dependencies[e.field] = true;
                };
                if (that.observable) {
                    that._change = function (e) {
                        that.change(e);
                    };
                    that.source.bind(CHANGE, that._change);
                }
            },
            _parents: function () {
                var parents = this.parents;
                var value = this.get();
                if (value && typeof value.parent == 'function') {
                    var parent = value.parent();
                    if ($.inArray(parent, parents) < 0) {
                        parents = [parent].concat(parents);
                    }
                }
                return parents;
            },
            change: function (e) {
                var dependency, ch, field = e.field, that = this;
                if (that.path === 'this') {
                    that.trigger(CHANGE, e);
                } else {
                    for (dependency in that.dependencies) {
                        if (dependency.indexOf(field) === 0) {
                            ch = dependency.charAt(field.length);
                            if (!ch || ch === '.' || ch === '[') {
                                that.trigger(CHANGE, e);
                                break;
                            }
                        }
                    }
                }
            },
            start: function (source) {
                source.bind('get', this._access);
            },
            stop: function (source) {
                source.unbind('get', this._access);
            },
            get: function () {
                var that = this, source = that.source, index = 0, path = that.path, result = source;
                if (!that.observable) {
                    return result;
                }
                that.start(that.source);
                result = source.get(path);
                while (result === undefined && source) {
                    source = that.parents[++index];
                    if (source instanceof ObservableObject) {
                        result = source.get(path);
                    }
                }
                if (result === undefined) {
                    source = that.source;
                    while (result === undefined && source) {
                        source = source.parent();
                        if (source instanceof ObservableObject) {
                            result = source.get(path);
                        }
                    }
                }
                if (typeof result === 'function') {
                    index = path.lastIndexOf('.');
                    if (index > 0) {
                        source = source.get(path.substring(0, index));
                    }
                    that.start(source);
                    if (source !== that.source) {
                        result = result.call(source, that.source);
                    } else {
                        result = result.call(source);
                    }
                    that.stop(source);
                }
                if (source && source !== that.source) {
                    that.currentSource = source;
                    source.unbind(CHANGE, that._change).bind(CHANGE, that._change);
                }
                that.stop(that.source);
                return result;
            },
            set: function (value) {
                var source = this.currentSource || this.source;
                var field = kendo.getter(this.path)(source);
                if (typeof field === 'function') {
                    if (source !== this.source) {
                        field.call(source, this.source, value);
                    } else {
                        field.call(source, value);
                    }
                } else {
                    source.set(this.path, value);
                }
            },
            destroy: function () {
                if (this.observable) {
                    this.source.unbind(CHANGE, this._change);
                    if (this.currentSource) {
                        this.currentSource.unbind(CHANGE, this._change);
                    }
                }
                this.unbind();
            }
        });
        var EventBinding = Binding.extend({
            get: function () {
                var source = this.source, path = this.path, index = 0, handler;
                handler = source.get(path);
                while (!handler && source) {
                    source = this.parents[++index];
                    if (source instanceof ObservableObject) {
                        handler = source.get(path);
                    }
                }
                return proxy(handler, source);
            }
        });
        var TemplateBinding = Binding.extend({
            init: function (source, path, template) {
                var that = this;
                Binding.fn.init.call(that, source, path);
                that.template = template;
            },
            render: function (value) {
                var html;
                this.start(this.source);
                html = kendo.render(this.template, value);
                this.stop(this.source);
                return html;
            }
        });
        var Binder = Class.extend({
            init: function (element, bindings, options) {
                this.element = element;
                this.bindings = bindings;
                this.options = options;
            },
            bind: function (binding, attribute) {
                var that = this;
                binding = attribute ? binding[attribute] : binding;
                binding.bind(CHANGE, function (e) {
                    that.refresh(attribute || e);
                });
                that.refresh(attribute);
            },
            destroy: function () {
            }
        });
        var TypedBinder = Binder.extend({
            dataType: function () {
                var dataType = this.element.getAttribute('data-type') || this.element.type || 'text';
                return dataType.toLowerCase();
            },
            parsedValue: function () {
                return this._parseValue(this.element.value, this.dataType());
            },
            _parseValue: function (value, dataType) {
                if (dataType == 'date') {
                    value = kendo.parseDate(value, 'yyyy-MM-dd');
                } else if (dataType == 'datetime-local') {
                    value = kendo.parseDate(value, [
                        'yyyy-MM-ddTHH:mm:ss',
                        'yyyy-MM-ddTHH:mm'
                    ]);
                } else if (dataType == 'number') {
                    value = kendo.parseFloat(value);
                } else if (dataType == 'boolean') {
                    value = value.toLowerCase();
                    if (kendo.parseFloat(value) !== null) {
                        value = Boolean(kendo.parseFloat(value));
                    } else {
                        value = value.toLowerCase() === 'true';
                    }
                }
                return value;
            }
        });
        binders.attr = Binder.extend({
            refresh: function (key) {
                this.element.setAttribute(key, this.bindings.attr[key].get());
            }
        });
        binders.css = Binder.extend({
            init: function (element, bindings, options) {
                Binder.fn.init.call(this, element, bindings, options);
                this.classes = {};
            },
            refresh: function (className) {
                var element = $(this.element), binding = this.bindings.css[className], hasClass = this.classes[className] = binding.get();
                if (hasClass) {
                    element.addClass(className);
                } else {
                    element.removeClass(className);
                }
            }
        });
        binders.style = Binder.extend({
            refresh: function (key) {
                this.element.style[key] = this.bindings.style[key].get() || '';
            }
        });
        binders.enabled = Binder.extend({
            refresh: function () {
                if (this.bindings.enabled.get()) {
                    this.element.removeAttribute('disabled');
                } else {
                    this.element.setAttribute('disabled', 'disabled');
                }
            }
        });
        binders.readonly = Binder.extend({
            refresh: function () {
                if (this.bindings.readonly.get()) {
                    this.element.setAttribute('readonly', 'readonly');
                } else {
                    this.element.removeAttribute('readonly');
                }
            }
        });
        binders.disabled = Binder.extend({
            refresh: function () {
                if (this.bindings.disabled.get()) {
                    this.element.setAttribute('disabled', 'disabled');
                } else {
                    this.element.removeAttribute('disabled');
                }
            }
        });
        binders.events = Binder.extend({
            init: function (element, bindings, options) {
                Binder.fn.init.call(this, element, bindings, options);
                this.handlers = {};
            },
            refresh: function (key) {
                var element = $(this.element), binding = this.bindings.events[key], handler = this.handlers[key];
                if (handler) {
                    element.off(key, handler);
                }
                handler = this.handlers[key] = binding.get();
                element.on(key, binding.source, handler);
            },
            destroy: function () {
                var element = $(this.element), handler;
                for (handler in this.handlers) {
                    element.off(handler, this.handlers[handler]);
                }
            }
        });
        binders.text = Binder.extend({
            refresh: function () {
                var text = this.bindings.text.get();
                var dataFormat = this.element.getAttribute('data-format') || '';
                if (text == null) {
                    text = '';
                }
                $(this.element).text(kendo.toString(text, dataFormat));
            }
        });
        binders.visible = Binder.extend({
            refresh: function () {
                if (this.bindings.visible.get()) {
                    this.element.style.display = '';
                } else {
                    this.element.style.display = 'none';
                }
            }
        });
        binders.invisible = Binder.extend({
            refresh: function () {
                if (!this.bindings.invisible.get()) {
                    this.element.style.display = '';
                } else {
                    this.element.style.display = 'none';
                }
            }
        });
        binders.html = Binder.extend({
            refresh: function () {
                this.element.innerHTML = this.bindings.html.get();
            }
        });
        binders.value = TypedBinder.extend({
            init: function (element, bindings, options) {
                TypedBinder.fn.init.call(this, element, bindings, options);
                this._change = proxy(this.change, this);
                this.eventName = options.valueUpdate || CHANGE;
                $(this.element).on(this.eventName, this._change);
                this._initChange = false;
            },
            change: function () {
                this._initChange = this.eventName != CHANGE;
                this.bindings[VALUE].set(this.parsedValue());
                this._initChange = false;
            },
            refresh: function () {
                if (!this._initChange) {
                    var value = this.bindings[VALUE].get();
                    if (value == null) {
                        value = '';
                    }
                    var type = this.dataType();
                    if (type == 'date') {
                        value = kendo.toString(value, 'yyyy-MM-dd');
                    } else if (type == 'datetime-local') {
                        value = kendo.toString(value, 'yyyy-MM-ddTHH:mm:ss');
                    }
                    this.element.value = value;
                }
                this._initChange = false;
            },
            destroy: function () {
                $(this.element).off(this.eventName, this._change);
            }
        });
        binders.source = Binder.extend({
            init: function (element, bindings, options) {
                Binder.fn.init.call(this, element, bindings, options);
                var source = this.bindings.source.get();
                if (source instanceof kendo.data.DataSource && options.autoBind !== false) {
                    source.fetch();
                }
            },
            refresh: function (e) {
                var that = this, source = that.bindings.source.get();
                if (source instanceof ObservableArray || source instanceof kendo.data.DataSource) {
                    e = e || {};
                    if (e.action == 'add') {
                        that.add(e.index, e.items);
                    } else if (e.action == 'remove') {
                        that.remove(e.index, e.items);
                    } else if (e.action != 'itemchange') {
                        that.render();
                    }
                } else {
                    that.render();
                }
            },
            container: function () {
                var element = this.element;
                if (element.nodeName.toLowerCase() == 'table') {
                    if (!element.tBodies[0]) {
                        element.appendChild(document.createElement('tbody'));
                    }
                    element = element.tBodies[0];
                }
                return element;
            },
            template: function () {
                var options = this.options, template = options.template, nodeName = this.container().nodeName.toLowerCase();
                if (!template) {
                    if (nodeName == 'select') {
                        if (options.valueField || options.textField) {
                            template = kendo.format('<option value="#:{0}#">#:{1}#</option>', options.valueField || options.textField, options.textField || options.valueField);
                        } else {
                            template = '<option>#:data#</option>';
                        }
                    } else if (nodeName == 'tbody') {
                        template = '<tr><td>#:data#</td></tr>';
                    } else if (nodeName == 'ul' || nodeName == 'ol') {
                        template = '<li>#:data#</li>';
                    } else {
                        template = '#:data#';
                    }
                    template = kendo.template(template);
                }
                return template;
            },
            add: function (index, items) {
                var element = this.container(), parents, idx, length, child, clone = element.cloneNode(false), reference = element.children[index];
                $(clone).html(kendo.render(this.template(), items));
                if (clone.children.length) {
                    parents = this.bindings.source._parents();
                    for (idx = 0, length = items.length; idx < length; idx++) {
                        child = clone.children[0];
                        element.insertBefore(child, reference || null);
                        bindElement(child, items[idx], this.options.roles, [items[idx]].concat(parents));
                    }
                }
            },
            remove: function (index, items) {
                var idx, element = this.container();
                for (idx = 0; idx < items.length; idx++) {
                    var child = element.children[index];
                    unbindElementTree(child, true);
                    if (child.parentNode == element) {
                        element.removeChild(child);
                    }
                }
            },
            render: function () {
                var source = this.bindings.source.get(), parents, idx, length, element = this.container(), template = this.template();
                if (source == null) {
                    return;
                }
                if (source instanceof kendo.data.DataSource) {
                    source = source.view();
                }
                if (!(source instanceof ObservableArray) && toString.call(source) !== '[object Array]') {
                    source = [source];
                }
                if (this.bindings.template) {
                    unbindElementChildren(element, true);
                    $(element).html(this.bindings.template.render(source));
                    if (element.children.length) {
                        parents = this.bindings.source._parents();
                        for (idx = 0, length = source.length; idx < length; idx++) {
                            bindElement(element.children[idx], source[idx], this.options.roles, [source[idx]].concat(parents));
                        }
                    }
                } else {
                    $(element).html(kendo.render(template, source));
                }
            }
        });
        binders.input = {
            checked: TypedBinder.extend({
                init: function (element, bindings, options) {
                    TypedBinder.fn.init.call(this, element, bindings, options);
                    this._change = proxy(this.change, this);
                    $(this.element).change(this._change);
                },
                change: function () {
                    var element = this.element;
                    var value = this.value();
                    if (element.type == 'radio') {
                        value = this.parsedValue();
                        this.bindings[CHECKED].set(value);
                    } else if (element.type == 'checkbox') {
                        var source = this.bindings[CHECKED].get();
                        var index;
                        if (source instanceof ObservableArray) {
                            value = this.parsedValue();
                            if (value instanceof Date) {
                                for (var i = 0; i < source.length; i++) {
                                    if (source[i] instanceof Date && +source[i] === +value) {
                                        index = i;
                                        break;
                                    }
                                }
                            } else {
                                index = source.indexOf(value);
                            }
                            if (index > -1) {
                                source.splice(index, 1);
                            } else {
                                source.push(value);
                            }
                        } else {
                            this.bindings[CHECKED].set(value);
                        }
                    }
                },
                refresh: function () {
                    var value = this.bindings[CHECKED].get(), source = value, type = this.dataType(), element = this.element;
                    if (element.type == 'checkbox') {
                        if (source instanceof ObservableArray) {
                            var index = -1;
                            value = this.parsedValue();
                            if (value instanceof Date) {
                                for (var i = 0; i < source.length; i++) {
                                    if (source[i] instanceof Date && +source[i] === +value) {
                                        index = i;
                                        break;
                                    }
                                }
                            } else {
                                index = source.indexOf(value);
                            }
                            element.checked = index >= 0;
                        } else {
                            element.checked = source;
                        }
                    } else if (element.type == 'radio' && value != null) {
                        if (type == 'date') {
                            value = kendo.toString(value, 'yyyy-MM-dd');
                        } else if (type == 'datetime-local') {
                            value = kendo.toString(value, 'yyyy-MM-ddTHH:mm:ss');
                        }
                        if (element.value === value.toString()) {
                            element.checked = true;
                        } else {
                            element.checked = false;
                        }
                    }
                },
                value: function () {
                    var element = this.element, value = element.value;
                    if (element.type == 'checkbox') {
                        value = element.checked;
                    }
                    return value;
                },
                destroy: function () {
                    $(this.element).off(CHANGE, this._change);
                }
            })
        };
        binders.select = {
            source: binders.source.extend({
                refresh: function (e) {
                    var that = this, source = that.bindings.source.get();
                    if (source instanceof ObservableArray || source instanceof kendo.data.DataSource) {
                        e = e || {};
                        if (e.action == 'add') {
                            that.add(e.index, e.items);
                        } else if (e.action == 'remove') {
                            that.remove(e.index, e.items);
                        } else if (e.action == 'itemchange' || e.action === undefined) {
                            that.render();
                            if (that.bindings.value) {
                                if (that.bindings.value) {
                                    var val = retrievePrimitiveValues(that.bindings.value.get(), $(that.element).data('valueField'));
                                    if (val === null) {
                                        that.element.selectedIndex = -1;
                                    } else {
                                        that.element.value = val;
                                    }
                                }
                            }
                        }
                    } else {
                        that.render();
                    }
                }
            }),
            value: TypedBinder.extend({
                init: function (target, bindings, options) {
                    TypedBinder.fn.init.call(this, target, bindings, options);
                    this._change = proxy(this.change, this);
                    $(this.element).change(this._change);
                },
                parsedValue: function () {
                    var dataType = this.dataType();
                    var values = [];
                    var value, option, idx, length;
                    for (idx = 0, length = this.element.options.length; idx < length; idx++) {
                        option = this.element.options[idx];
                        if (option.selected) {
                            value = option.attributes.value;
                            if (value && value.specified) {
                                value = option.value;
                            } else {
                                value = option.text;
                            }
                            values.push(this._parseValue(value, dataType));
                        }
                    }
                    return values;
                },
                change: function () {
                    var values = [], element = this.element, source, field = this.options.valueField || this.options.textField, valuePrimitive = this.options.valuePrimitive, option, valueIndex, value, idx, length;
                    for (idx = 0, length = element.options.length; idx < length; idx++) {
                        option = element.options[idx];
                        if (option.selected) {
                            value = option.attributes.value;
                            if (value && value.specified) {
                                value = option.value;
                            } else {
                                value = option.text;
                            }
                            if (field) {
                                values.push(value);
                            } else {
                                values.push(this._parseValue(value, this.dataType()));
                            }
                        }
                    }
                    if (field) {
                        source = this.bindings.source.get();
                        if (source instanceof kendo.data.DataSource) {
                            source = source.view();
                        }
                        for (valueIndex = 0; valueIndex < values.length; valueIndex++) {
                            for (idx = 0, length = source.length; idx < length; idx++) {
                                var sourceValue = source[idx].get(field);
                                var match = String(sourceValue) === values[valueIndex];
                                if (match) {
                                    values[valueIndex] = source[idx];
                                    break;
                                }
                            }
                        }
                    }
                    value = this.bindings[VALUE].get();
                    if (value instanceof ObservableArray) {
                        value.splice.apply(value, [
                            0,
                            value.length
                        ].concat(values));
                    } else if (!valuePrimitive && (value instanceof ObservableObject || value === null || value === undefined || !field)) {
                        this.bindings[VALUE].set(values[0]);
                    } else {
                        this.bindings[VALUE].set(values[0].get(field));
                    }
                },
                refresh: function () {
                    var optionIndex, element = this.element, options = element.options, value = this.bindings[VALUE].get(), values = value, field = this.options.valueField || this.options.textField, found = false, type = this.dataType(), optionValue;
                    if (!(values instanceof ObservableArray)) {
                        values = new ObservableArray([value]);
                    }
                    element.selectedIndex = -1;
                    for (var valueIndex = 0; valueIndex < values.length; valueIndex++) {
                        value = values[valueIndex];
                        if (field && value instanceof ObservableObject) {
                            value = value.get(field);
                        }
                        if (type == 'date') {
                            value = kendo.toString(values[valueIndex], 'yyyy-MM-dd');
                        } else if (type == 'datetime-local') {
                            value = kendo.toString(values[valueIndex], 'yyyy-MM-ddTHH:mm:ss');
                        }
                        for (optionIndex = 0; optionIndex < options.length; optionIndex++) {
                            optionValue = options[optionIndex].value;
                            if (optionValue === '' && value !== '') {
                                optionValue = options[optionIndex].text;
                            }
                            if (value != null && optionValue == value.toString()) {
                                options[optionIndex].selected = true;
                                found = true;
                            }
                        }
                    }
                },
                destroy: function () {
                    $(this.element).off(CHANGE, this._change);
                }
            })
        };
        function dataSourceBinding(bindingName, fieldName, setter) {
            return Binder.extend({
                init: function (widget, bindings, options) {
                    var that = this;
                    Binder.fn.init.call(that, widget.element[0], bindings, options);
                    that.widget = widget;
                    that._dataBinding = proxy(that.dataBinding, that);
                    that._dataBound = proxy(that.dataBound, that);
                    that._itemChange = proxy(that.itemChange, that);
                },
                itemChange: function (e) {
                    bindElement(e.item[0], e.data, this._ns(e.ns), [e.data].concat(this.bindings[bindingName]._parents()));
                },
                dataBinding: function (e) {
                    var idx, length, widget = this.widget, items = e.removedItems || widget.items();
                    for (idx = 0, length = items.length; idx < length; idx++) {
                        unbindElementTree(items[idx], false);
                    }
                },
                _ns: function (ns) {
                    ns = ns || kendo.ui;
                    var all = [
                        kendo.ui,
                        kendo.dataviz.ui,
                        kendo.mobile.ui
                    ];
                    all.splice($.inArray(ns, all), 1);
                    all.unshift(ns);
                    return kendo.rolesFromNamespaces(all);
                },
                dataBound: function (e) {
                    var idx, length, widget = this.widget, items = e.addedItems || widget.items(), dataSource = widget[fieldName], view, parents, hds = kendo.data.HierarchicalDataSource;
                    if (hds && dataSource instanceof hds) {
                        return;
                    }
                    if (items.length) {
                        view = e.addedDataItems || dataSource.flatView();
                        parents = this.bindings[bindingName]._parents();
                        for (idx = 0, length = view.length; idx < length; idx++) {
                            bindElement(items[idx], view[idx], this._ns(e.ns), [view[idx]].concat(parents));
                        }
                    }
                },
                refresh: function (e) {
                    var that = this, source, widget = that.widget, select, multiselect;
                    e = e || {};
                    if (!e.action) {
                        that.destroy();
                        widget.bind('dataBinding', that._dataBinding);
                        widget.bind('dataBound', that._dataBound);
                        widget.bind('itemChange', that._itemChange);
                        source = that.bindings[bindingName].get();
                        if (widget[fieldName] instanceof kendo.data.DataSource && widget[fieldName] != source) {
                            if (source instanceof kendo.data.DataSource) {
                                widget[setter](source);
                            } else if (source && source._dataSource) {
                                widget[setter](source._dataSource);
                            } else {
                                widget[fieldName].data(source);
                                select = kendo.ui.Select && widget instanceof kendo.ui.Select;
                                multiselect = kendo.ui.MultiSelect && widget instanceof kendo.ui.MultiSelect;
                                if (that.bindings.value && (select || multiselect)) {
                                    widget.value(retrievePrimitiveValues(that.bindings.value.get(), widget.options.dataValueField));
                                }
                            }
                        }
                    }
                },
                destroy: function () {
                    var widget = this.widget;
                    widget.unbind('dataBinding', this._dataBinding);
                    widget.unbind('dataBound', this._dataBound);
                    widget.unbind('itemChange', this._itemChange);
                }
            });
        }
        binders.widget = {
            events: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                    this.handlers = {};
                },
                refresh: function (key) {
                    var binding = this.bindings.events[key], handler = this.handlers[key];
                    if (handler) {
                        this.widget.unbind(key, handler);
                    }
                    handler = binding.get();
                    this.handlers[key] = function (e) {
                        e.data = binding.source;
                        handler(e);
                        if (e.data === binding.source) {
                            delete e.data;
                        }
                    };
                    this.widget.bind(key, this.handlers[key]);
                },
                destroy: function () {
                    var handler;
                    for (handler in this.handlers) {
                        this.widget.unbind(handler, this.handlers[handler]);
                    }
                }
            }),
            checked: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                    this._change = proxy(this.change, this);
                    this.widget.bind(CHANGE, this._change);
                },
                change: function () {
                    this.bindings[CHECKED].set(this.value());
                },
                refresh: function () {
                    this.widget.check(this.bindings[CHECKED].get() === true);
                },
                value: function () {
                    var element = this.element, value = element.value;
                    if (value == 'on' || value == 'off') {
                        value = element.checked;
                    }
                    return value;
                },
                destroy: function () {
                    this.widget.unbind(CHANGE, this._change);
                }
            }),
            visible: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                },
                refresh: function () {
                    var visible = this.bindings.visible.get();
                    this.widget.wrapper[0].style.display = visible ? '' : 'none';
                }
            }),
            invisible: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                },
                refresh: function () {
                    var invisible = this.bindings.invisible.get();
                    this.widget.wrapper[0].style.display = invisible ? 'none' : '';
                }
            }),
            enabled: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                },
                refresh: function () {
                    if (this.widget.enable) {
                        this.widget.enable(this.bindings.enabled.get());
                    }
                }
            }),
            disabled: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                },
                refresh: function () {
                    if (this.widget.enable) {
                        this.widget.enable(!this.bindings.disabled.get());
                    }
                }
            }),
            source: dataSourceBinding('source', 'dataSource', 'setDataSource'),
            value: Binder.extend({
                init: function (widget, bindings, options) {
                    Binder.fn.init.call(this, widget.element[0], bindings, options);
                    this.widget = widget;
                    this._change = $.proxy(this.change, this);
                    this.widget.first(CHANGE, this._change);
                    var value = this.bindings.value.get();
                    this._valueIsObservableObject = !options.valuePrimitive && (value == null || value instanceof ObservableObject);
                    this._valueIsObservableArray = value instanceof ObservableArray;
                    this._initChange = false;
                },
                _source: function () {
                    var source;
                    if (this.widget.dataItem) {
                        source = this.widget.dataItem();
                        if (source && source instanceof ObservableObject) {
                            return [source];
                        }
                    }
                    if (this.bindings.source) {
                        source = this.bindings.source.get();
                    }
                    if (!source || source instanceof kendo.data.DataSource) {
                        source = this.widget.dataSource.flatView();
                    }
                    return source;
                },
                change: function () {
                    var value = this.widget.value(), field = this.options.dataValueField || this.options.dataTextField, isArray = toString.call(value) === '[object Array]', isObservableObject = this._valueIsObservableObject, valueIndex, valueLength, values = [], sourceItem, sourceValue, idx, length, source;
                    this._initChange = true;
                    if (field) {
                        if (value === '' && (isObservableObject || this.options.valuePrimitive)) {
                            value = null;
                        } else {
                            source = this._source();
                            if (isArray) {
                                valueLength = value.length;
                                values = value.slice(0);
                            }
                            for (idx = 0, length = source.length; idx < length; idx++) {
                                sourceItem = source[idx];
                                sourceValue = sourceItem.get(field);
                                if (isArray) {
                                    for (valueIndex = 0; valueIndex < valueLength; valueIndex++) {
                                        if (sourceValue == values[valueIndex]) {
                                            values[valueIndex] = sourceItem;
                                            break;
                                        }
                                    }
                                } else if (sourceValue == value) {
                                    value = isObservableObject ? sourceItem : sourceValue;
                                    break;
                                }
                            }
                            if (values[0]) {
                                if (this._valueIsObservableArray) {
                                    value = values;
                                } else if (isObservableObject || !field) {
                                    value = values[0];
                                } else {
                                    value = values[0].get(field);
                                }
                            }
                        }
                    }
                    this.bindings.value.set(value);
                    this._initChange = false;
                },
                refresh: function () {
                    if (!this._initChange) {
                        var widget = this.widget;
                        var options = widget.options;
                        var textField = options.dataTextField;
                        var valueField = options.dataValueField || textField;
                        var value = this.bindings.value.get();
                        var text = options.text || '';
                        var idx = 0, length;
                        var values = [];
                        if (value === undefined) {
                            value = null;
                        }
                        if (valueField) {
                            if (value instanceof ObservableArray) {
                                for (length = value.length; idx < length; idx++) {
                                    values[idx] = value[idx].get(valueField);
                                }
                                value = values;
                            } else if (value instanceof ObservableObject) {
                                text = value.get(textField);
                                value = value.get(valueField);
                            }
                        }
                        if (options.autoBind === false && !options.cascadeFrom && widget.listView && !widget.listView.bound()) {
                            if (textField === valueField && !text) {
                                text = value;
                            }
                            if (!text && (value || value === 0) && options.valuePrimitive) {
                                widget.value(value);
                            } else {
                                widget._preselect(value, text);
                            }
                        } else {
                            widget.value(value);
                        }
                    }
                    this._initChange = false;
                },
                destroy: function () {
                    this.widget.unbind(CHANGE, this._change);
                }
            }),
            gantt: { dependencies: dataSourceBinding('dependencies', 'dependencies', 'setDependenciesDataSource') },
            multiselect: {
                value: Binder.extend({
                    init: function (widget, bindings, options) {
                        Binder.fn.init.call(this, widget.element[0], bindings, options);
                        this.widget = widget;
                        this._change = $.proxy(this.change, this);
                        this.widget.first(CHANGE, this._change);
                        this._initChange = false;
                    },
                    change: function () {
                        var that = this, oldValues = that.bindings[VALUE].get(), valuePrimitive = that.options.valuePrimitive, newValues = valuePrimitive ? that.widget.value() : that.widget.dataItems();
                        var field = this.options.dataValueField || this.options.dataTextField;
                        newValues = newValues.slice(0);
                        that._initChange = true;
                        if (oldValues instanceof ObservableArray) {
                            var remove = [];
                            var newLength = newValues.length;
                            var i = 0, j = 0;
                            var old = oldValues[i];
                            var same = false;
                            var removeIndex;
                            var newValue;
                            var found;
                            while (old !== undefined) {
                                found = false;
                                for (j = 0; j < newLength; j++) {
                                    if (valuePrimitive) {
                                        same = newValues[j] == old;
                                    } else {
                                        newValue = newValues[j];
                                        newValue = newValue.get ? newValue.get(field) : newValue;
                                        same = newValue == (old.get ? old.get(field) : old);
                                    }
                                    if (same) {
                                        newValues.splice(j, 1);
                                        newLength -= 1;
                                        found = true;
                                        break;
                                    }
                                }
                                if (!found) {
                                    remove.push(old);
                                    arraySplice(oldValues, i, 1);
                                    removeIndex = i;
                                } else {
                                    i += 1;
                                }
                                old = oldValues[i];
                            }
                            arraySplice(oldValues, oldValues.length, 0, newValues);
                            if (remove.length) {
                                oldValues.trigger('change', {
                                    action: 'remove',
                                    items: remove,
                                    index: removeIndex
                                });
                            }
                            if (newValues.length) {
                                oldValues.trigger('change', {
                                    action: 'add',
                                    items: newValues,
                                    index: oldValues.length - 1
                                });
                            }
                        } else {
                            that.bindings[VALUE].set(newValues);
                        }
                        that._initChange = false;
                    },
                    refresh: function () {
                        if (!this._initChange) {
                            var options = this.options, widget = this.widget, field = options.dataValueField || options.dataTextField, value = this.bindings.value.get(), data = value, idx = 0, length, values = [], selectedValue;
                            if (value === undefined) {
                                value = null;
                            }
                            if (field) {
                                if (value instanceof ObservableArray) {
                                    for (length = value.length; idx < length; idx++) {
                                        selectedValue = value[idx];
                                        values[idx] = selectedValue.get ? selectedValue.get(field) : selectedValue;
                                    }
                                    value = values;
                                } else if (value instanceof ObservableObject) {
                                    value = value.get(field);
                                }
                            }
                            if (options.autoBind === false && options.valuePrimitive !== true && !widget._isBound()) {
                                widget._preselect(data, value);
                            } else {
                                widget.value(value);
                            }
                        }
                    },
                    destroy: function () {
                        this.widget.unbind(CHANGE, this._change);
                    }
                })
            },
            scheduler: {
                source: dataSourceBinding('source', 'dataSource', 'setDataSource').extend({
                    dataBound: function (e) {
                        var idx;
                        var length;
                        var widget = this.widget;
                        var elements = e.addedItems || widget.items();
                        var data, parents;
                        if (elements.length) {
                            data = e.addedDataItems || widget.dataItems();
                            parents = this.bindings.source._parents();
                            for (idx = 0, length = data.length; idx < length; idx++) {
                                bindElement(elements[idx], data[idx], this._ns(e.ns), [data[idx]].concat(parents));
                            }
                        }
                    }
                })
            }
        };
        var arraySplice = function (arr, idx, remove, add) {
            add = add || [];
            remove = remove || 0;
            var addLength = add.length;
            var oldLength = arr.length;
            var shifted = [].slice.call(arr, idx + remove);
            var shiftedLength = shifted.length;
            var index;
            if (addLength) {
                addLength = idx + addLength;
                index = 0;
                for (; idx < addLength; idx++) {
                    arr[idx] = add[index];
                    index++;
                }
                arr.length = addLength;
            } else if (remove) {
                arr.length = idx;
                remove += idx;
                while (idx < remove) {
                    delete arr[--remove];
                }
            }
            if (shiftedLength) {
                shiftedLength = idx + shiftedLength;
                index = 0;
                for (; idx < shiftedLength; idx++) {
                    arr[idx] = shifted[index];
                    index++;
                }
                arr.length = shiftedLength;
            }
            idx = arr.length;
            while (idx < oldLength) {
                delete arr[idx];
                idx++;
            }
        };
        var BindingTarget = Class.extend({
            init: function (target, options) {
                this.target = target;
                this.options = options;
                this.toDestroy = [];
            },
            bind: function (bindings) {
                var key, hasValue, hasSource, hasEvents, hasChecked, hasCss, widgetBinding = this instanceof WidgetBindingTarget, specificBinders = this.binders();
                for (key in bindings) {
                    if (key == VALUE) {
                        hasValue = true;
                    } else if (key == SOURCE) {
                        hasSource = true;
                    } else if (key == EVENTS && !widgetBinding) {
                        hasEvents = true;
                    } else if (key == CHECKED) {
                        hasChecked = true;
                    } else if (key == CSS) {
                        hasCss = true;
                    } else {
                        this.applyBinding(key, bindings, specificBinders);
                    }
                }
                if (hasSource) {
                    this.applyBinding(SOURCE, bindings, specificBinders);
                }
                if (hasValue) {
                    this.applyBinding(VALUE, bindings, specificBinders);
                }
                if (hasChecked) {
                    this.applyBinding(CHECKED, bindings, specificBinders);
                }
                if (hasEvents && !widgetBinding) {
                    this.applyBinding(EVENTS, bindings, specificBinders);
                }
                if (hasCss && !widgetBinding) {
                    this.applyBinding(CSS, bindings, specificBinders);
                }
            },
            binders: function () {
                return binders[this.target.nodeName.toLowerCase()] || {};
            },
            applyBinding: function (name, bindings, specificBinders) {
                var binder = specificBinders[name] || binders[name], toDestroy = this.toDestroy, attribute, binding = bindings[name];
                if (binder) {
                    binder = new binder(this.target, bindings, this.options);
                    toDestroy.push(binder);
                    if (binding instanceof Binding) {
                        binder.bind(binding);
                        toDestroy.push(binding);
                    } else {
                        for (attribute in binding) {
                            binder.bind(binding, attribute);
                            toDestroy.push(binding[attribute]);
                        }
                    }
                } else if (name !== 'template') {
                    throw new Error('The ' + name + ' binding is not supported by the ' + this.target.nodeName.toLowerCase() + ' element');
                }
            },
            destroy: function () {
                var idx, length, toDestroy = this.toDestroy;
                for (idx = 0, length = toDestroy.length; idx < length; idx++) {
                    toDestroy[idx].destroy();
                }
            }
        });
        var WidgetBindingTarget = BindingTarget.extend({
            binders: function () {
                return binders.widget[this.target.options.name.toLowerCase()] || {};
            },
            applyBinding: function (name, bindings, specificBinders) {
                var binder = specificBinders[name] || binders.widget[name], toDestroy = this.toDestroy, attribute, binding = bindings[name];
                if (binder) {
                    binder = new binder(this.target, bindings, this.target.options);
                    toDestroy.push(binder);
                    if (binding instanceof Binding) {
                        binder.bind(binding);
                        toDestroy.push(binding);
                    } else {
                        for (attribute in binding) {
                            binder.bind(binding, attribute);
                            toDestroy.push(binding[attribute]);
                        }
                    }
                } else {
                    throw new Error('The ' + name + ' binding is not supported by the ' + this.target.options.name + ' widget');
                }
            }
        });
        function bindingTargetForRole(element, roles) {
            var widget = kendo.initWidget(element, {}, roles);
            if (widget) {
                return new WidgetBindingTarget(widget);
            }
        }
        var keyValueRegExp = /[A-Za-z0-9_\-]+:(\{([^}]*)\}|[^,}]+)/g, whiteSpaceRegExp = /\s/g;
        function parseBindings(bind) {
            var result = {}, idx, length, token, colonIndex, key, value, tokens;
            tokens = bind.match(keyValueRegExp);
            for (idx = 0, length = tokens.length; idx < length; idx++) {
                token = tokens[idx];
                colonIndex = token.indexOf(':');
                key = token.substring(0, colonIndex);
                value = token.substring(colonIndex + 1);
                if (value.charAt(0) == '{') {
                    value = parseBindings(value);
                }
                result[key] = value;
            }
            return result;
        }
        function createBindings(bindings, source, type) {
            var binding, result = {};
            for (binding in bindings) {
                result[binding] = new type(source, bindings[binding]);
            }
            return result;
        }
        function bindElement(element, source, roles, parents) {
            var role = element.getAttribute('data-' + kendo.ns + 'role'), idx, bind = element.getAttribute('data-' + kendo.ns + 'bind'), childrenCopy = [], deep = true, bindings, options = {}, target;
            parents = parents || [source];
            if (role || bind) {
                unbindElement(element, false);
            }
            if (role) {
                target = bindingTargetForRole(element, roles);
            }
            if (bind) {
                bind = parseBindings(bind.replace(whiteSpaceRegExp, ''));
                if (!target) {
                    options = kendo.parseOptions(element, {
                        textField: '',
                        valueField: '',
                        template: '',
                        valueUpdate: CHANGE,
                        valuePrimitive: false,
                        autoBind: true
                    });
                    options.roles = roles;
                    target = new BindingTarget(element, options);
                }
                target.source = source;
                bindings = createBindings(bind, parents, Binding);
                if (options.template) {
                    bindings.template = new TemplateBinding(parents, '', options.template);
                }
                if (bindings.click) {
                    bind.events = bind.events || {};
                    bind.events.click = bind.click;
                    bindings.click.destroy();
                    delete bindings.click;
                }
                if (bindings.source) {
                    deep = false;
                }
                if (bind.attr) {
                    bindings.attr = createBindings(bind.attr, parents, Binding);
                }
                if (bind.style) {
                    bindings.style = createBindings(bind.style, parents, Binding);
                }
                if (bind.events) {
                    bindings.events = createBindings(bind.events, parents, EventBinding);
                }
                if (bind.css) {
                    bindings.css = createBindings(bind.css, parents, Binding);
                }
                target.bind(bindings);
            }
            if (target) {
                element.kendoBindingTarget = target;
            }
            var children = element.children;
            if (deep && children) {
                for (idx = 0; idx < children.length; idx++) {
                    childrenCopy[idx] = children[idx];
                }
                for (idx = 0; idx < childrenCopy.length; idx++) {
                    bindElement(childrenCopy[idx], source, roles, parents);
                }
            }
        }
        function bind(dom, object) {
            var idx, length, node, roles = kendo.rolesFromNamespaces([].slice.call(arguments, 2));
            object = kendo.observable(object);
            dom = $(dom);
            for (idx = 0, length = dom.length; idx < length; idx++) {
                node = dom[idx];
                if (node.nodeType === 1) {
                    bindElement(node, object, roles);
                }
            }
        }
        function unbindElement(element, destroyWidget) {
            var bindingTarget = element.kendoBindingTarget;
            if (bindingTarget) {
                bindingTarget.destroy();
                if (deleteExpando) {
                    delete element.kendoBindingTarget;
                } else if (element.removeAttribute) {
                    element.removeAttribute('kendoBindingTarget');
                } else {
                    element.kendoBindingTarget = null;
                }
            }
            if (destroyWidget) {
                var widget = kendo.widgetInstance($(element));
                if (widget && typeof widget.destroy === FUNCTION) {
                    widget.destroy();
                }
            }
        }
        function unbindElementTree(element, destroyWidgets) {
            unbindElement(element, destroyWidgets);
            unbindElementChildren(element, destroyWidgets);
        }
        function unbindElementChildren(element, destroyWidgets) {
            var children = element.children;
            if (children) {
                for (var idx = 0, length = children.length; idx < length; idx++) {
                    unbindElementTree(children[idx], destroyWidgets);
                }
            }
        }
        function unbind(dom) {
            var idx, length;
            dom = $(dom);
            for (idx = 0, length = dom.length; idx < length; idx++) {
                unbindElementTree(dom[idx], false);
            }
        }
        function notify(widget, namespace) {
            var element = widget.element, bindingTarget = element[0].kendoBindingTarget;
            if (bindingTarget) {
                bind(element, bindingTarget.source, namespace);
            }
        }
        function retrievePrimitiveValues(value, valueField) {
            var values = [];
            var idx = 0;
            var length;
            var item;
            if (!valueField) {
                return value;
            }
            if (value instanceof ObservableArray) {
                for (length = value.length; idx < length; idx++) {
                    item = value[idx];
                    values[idx] = item.get ? item.get(valueField) : item[valueField];
                }
                value = values;
            } else if (value instanceof ObservableObject) {
                value = value.get(valueField);
            }
            return value;
        }
        kendo.unbind = unbind;
        kendo.bind = bind;
        kendo.data.binders = binders;
        kendo.data.Binder = Binder;
        kendo.notify = notify;
        kendo.observable = function (object) {
            if (!(object instanceof ObservableObject)) {
                object = new ObservableObject(object);
            }
            return object;
        };
        kendo.observableHierarchy = function (array) {
            var dataSource = kendo.data.HierarchicalDataSource.create(array);
            function recursiveRead(data) {
                var i, children;
                for (i = 0; i < data.length; i++) {
                    data[i]._initChildren();
                    children = data[i].children;
                    children.fetch();
                    data[i].items = children.data();
                    recursiveRead(data[i].items);
                }
            }
            dataSource.fetch();
            recursiveRead(dataSource.data());
            dataSource._data._dataSource = dataSource;
            return dataSource._data;
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.fx', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'fx',
        name: 'Effects',
        category: 'framework',
        description: 'Required for animation effects in all Kendo UI widgets.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, fx = kendo.effects, each = $.each, extend = $.extend, proxy = $.proxy, support = kendo.support, browser = support.browser, transforms = support.transforms, transitions = support.transitions, scaleProperties = {
                scale: 0,
                scalex: 0,
                scaley: 0,
                scale3d: 0
            }, translateProperties = {
                translate: 0,
                translatex: 0,
                translatey: 0,
                translate3d: 0
            }, hasZoom = typeof document.documentElement.style.zoom !== 'undefined' && !transforms, matrix3dRegExp = /matrix3?d?\s*\(.*,\s*([\d\.\-]+)\w*?,\s*([\d\.\-]+)\w*?,\s*([\d\.\-]+)\w*?,\s*([\d\.\-]+)\w*?/i, cssParamsRegExp = /^(-?[\d\.\-]+)?[\w\s]*,?\s*(-?[\d\.\-]+)?[\w\s]*/i, translateXRegExp = /translatex?$/i, oldEffectsRegExp = /(zoom|fade|expand)(\w+)/, singleEffectRegExp = /(zoom|fade|expand)/, unitRegExp = /[xy]$/i, transformProps = [
                'perspective',
                'rotate',
                'rotatex',
                'rotatey',
                'rotatez',
                'rotate3d',
                'scale',
                'scalex',
                'scaley',
                'scalez',
                'scale3d',
                'skew',
                'skewx',
                'skewy',
                'translate',
                'translatex',
                'translatey',
                'translatez',
                'translate3d',
                'matrix',
                'matrix3d'
            ], transform2d = [
                'rotate',
                'scale',
                'scalex',
                'scaley',
                'skew',
                'skewx',
                'skewy',
                'translate',
                'translatex',
                'translatey',
                'matrix'
            ], transform2units = {
                'rotate': 'deg',
                scale: '',
                skew: 'px',
                translate: 'px'
            }, cssPrefix = transforms.css, round = Math.round, BLANK = '', PX = 'px', NONE = 'none', AUTO = 'auto', WIDTH = 'width', HEIGHT = 'height', HIDDEN = 'hidden', ORIGIN = 'origin', ABORT_ID = 'abortId', OVERFLOW = 'overflow', TRANSLATE = 'translate', POSITION = 'position', COMPLETE_CALLBACK = 'completeCallback', TRANSITION = cssPrefix + 'transition', TRANSFORM = cssPrefix + 'transform', BACKFACE = cssPrefix + 'backface-visibility', PERSPECTIVE = cssPrefix + 'perspective', DEFAULT_PERSPECTIVE = '1500px', TRANSFORM_PERSPECTIVE = 'perspective(' + DEFAULT_PERSPECTIVE + ')', directions = {
                left: {
                    reverse: 'right',
                    property: 'left',
                    transition: 'translatex',
                    vertical: false,
                    modifier: -1
                },
                right: {
                    reverse: 'left',
                    property: 'left',
                    transition: 'translatex',
                    vertical: false,
                    modifier: 1
                },
                down: {
                    reverse: 'up',
                    property: 'top',
                    transition: 'translatey',
                    vertical: true,
                    modifier: 1
                },
                up: {
                    reverse: 'down',
                    property: 'top',
                    transition: 'translatey',
                    vertical: true,
                    modifier: -1
                },
                top: { reverse: 'bottom' },
                bottom: { reverse: 'top' },
                'in': {
                    reverse: 'out',
                    modifier: -1
                },
                out: {
                    reverse: 'in',
                    modifier: 1
                },
                vertical: { reverse: 'vertical' },
                horizontal: { reverse: 'horizontal' }
            };
        kendo.directions = directions;
        extend($.fn, {
            kendoStop: function (clearQueue, gotoEnd) {
                if (transitions) {
                    return fx.stopQueue(this, clearQueue || false, gotoEnd || false);
                } else {
                    return this.stop(clearQueue, gotoEnd);
                }
            }
        });
        if (transforms && !transitions) {
            each(transform2d, function (idx, value) {
                $.fn[value] = function (val) {
                    if (typeof val == 'undefined') {
                        return animationProperty(this, value);
                    } else {
                        var that = $(this)[0], transformValue = value + '(' + val + transform2units[value.replace(unitRegExp, '')] + ')';
                        if (that.style.cssText.indexOf(TRANSFORM) == -1) {
                            $(this).css(TRANSFORM, transformValue);
                        } else {
                            that.style.cssText = that.style.cssText.replace(new RegExp(value + '\\(.*?\\)', 'i'), transformValue);
                        }
                    }
                    return this;
                };
                $.fx.step[value] = function (fx) {
                    $(fx.elem)[value](fx.now);
                };
            });
            var curProxy = $.fx.prototype.cur;
            $.fx.prototype.cur = function () {
                if (transform2d.indexOf(this.prop) != -1) {
                    return parseFloat($(this.elem)[this.prop]());
                }
                return curProxy.apply(this, arguments);
            };
        }
        kendo.toggleClass = function (element, classes, options, add) {
            if (classes) {
                classes = classes.split(' ');
                if (transitions) {
                    options = extend({
                        exclusive: 'all',
                        duration: 400,
                        ease: 'ease-out'
                    }, options);
                    element.css(TRANSITION, options.exclusive + ' ' + options.duration + 'ms ' + options.ease);
                    setTimeout(function () {
                        element.css(TRANSITION, '').css(HEIGHT);
                    }, options.duration);
                }
                each(classes, function (idx, value) {
                    element.toggleClass(value, add);
                });
            }
            return element;
        };
        kendo.parseEffects = function (input, mirror) {
            var effects = {};
            if (typeof input === 'string') {
                each(input.split(' '), function (idx, value) {
                    var redirectedEffect = !singleEffectRegExp.test(value), resolved = value.replace(oldEffectsRegExp, function (match, $1, $2) {
                            return $1 + ':' + $2.toLowerCase();
                        }), effect = resolved.split(':'), direction = effect[1], effectBody = {};
                    if (effect.length > 1) {
                        effectBody.direction = mirror && redirectedEffect ? directions[direction].reverse : direction;
                    }
                    effects[effect[0]] = effectBody;
                });
            } else {
                each(input, function (idx) {
                    var direction = this.direction;
                    if (direction && mirror && !singleEffectRegExp.test(idx)) {
                        this.direction = directions[direction].reverse;
                    }
                    effects[idx] = this;
                });
            }
            return effects;
        };
        function parseInteger(value) {
            return parseInt(value, 10);
        }
        function parseCSS(element, property) {
            return parseInteger(element.css(property));
        }
        function keys(obj) {
            var acc = [];
            for (var propertyName in obj) {
                acc.push(propertyName);
            }
            return acc;
        }
        function strip3DTransforms(properties) {
            for (var key in properties) {
                if (transformProps.indexOf(key) != -1 && transform2d.indexOf(key) == -1) {
                    delete properties[key];
                }
            }
            return properties;
        }
        function normalizeCSS(element, properties) {
            var transformation = [], cssValues = {}, lowerKey, key, value, isTransformed;
            for (key in properties) {
                lowerKey = key.toLowerCase();
                isTransformed = transforms && transformProps.indexOf(lowerKey) != -1;
                if (!support.hasHW3D && isTransformed && transform2d.indexOf(lowerKey) == -1) {
                    delete properties[key];
                } else {
                    value = properties[key];
                    if (isTransformed) {
                        transformation.push(key + '(' + value + ')');
                    } else {
                        cssValues[key] = value;
                    }
                }
            }
            if (transformation.length) {
                cssValues[TRANSFORM] = transformation.join(' ');
            }
            return cssValues;
        }
        if (transitions) {
            extend(fx, {
                transition: function (element, properties, options) {
                    var css, delay = 0, oldKeys = element.data('keys') || [], timeoutID;
                    options = extend({
                        duration: 200,
                        ease: 'ease-out',
                        complete: null,
                        exclusive: 'all'
                    }, options);
                    var stopTransitionCalled = false;
                    var stopTransition = function () {
                        if (!stopTransitionCalled) {
                            stopTransitionCalled = true;
                            if (timeoutID) {
                                clearTimeout(timeoutID);
                                timeoutID = null;
                            }
                            element.removeData(ABORT_ID).dequeue().css(TRANSITION, '').css(TRANSITION);
                            options.complete.call(element);
                        }
                    };
                    options.duration = $.fx ? $.fx.speeds[options.duration] || options.duration : options.duration;
                    css = normalizeCSS(element, properties);
                    $.merge(oldKeys, keys(css));
                    element.data('keys', $.unique(oldKeys)).height();
                    element.css(TRANSITION, options.exclusive + ' ' + options.duration + 'ms ' + options.ease).css(TRANSITION);
                    element.css(css).css(TRANSFORM);
                    if (transitions.event) {
                        element.one(transitions.event, stopTransition);
                        if (options.duration !== 0) {
                            delay = 500;
                        }
                    }
                    timeoutID = setTimeout(stopTransition, options.duration + delay);
                    element.data(ABORT_ID, timeoutID);
                    element.data(COMPLETE_CALLBACK, stopTransition);
                },
                stopQueue: function (element, clearQueue, gotoEnd) {
                    var cssValues, taskKeys = element.data('keys'), retainPosition = !gotoEnd && taskKeys, completeCallback = element.data(COMPLETE_CALLBACK);
                    if (retainPosition) {
                        cssValues = kendo.getComputedStyles(element[0], taskKeys);
                    }
                    if (completeCallback) {
                        completeCallback();
                    }
                    if (retainPosition) {
                        element.css(cssValues);
                    }
                    return element.removeData('keys').stop(clearQueue);
                }
            });
        }
        function animationProperty(element, property) {
            if (transforms) {
                var transform = element.css(TRANSFORM);
                if (transform == NONE) {
                    return property == 'scale' ? 1 : 0;
                }
                var match = transform.match(new RegExp(property + '\\s*\\(([\\d\\w\\.]+)')), computed = 0;
                if (match) {
                    computed = parseInteger(match[1]);
                } else {
                    match = transform.match(matrix3dRegExp) || [
                        0,
                        0,
                        0,
                        0,
                        0
                    ];
                    property = property.toLowerCase();
                    if (translateXRegExp.test(property)) {
                        computed = parseFloat(match[3] / match[2]);
                    } else if (property == 'translatey') {
                        computed = parseFloat(match[4] / match[2]);
                    } else if (property == 'scale') {
                        computed = parseFloat(match[2]);
                    } else if (property == 'rotate') {
                        computed = parseFloat(Math.atan2(match[2], match[1]));
                    }
                }
                return computed;
            } else {
                return parseFloat(element.css(property));
            }
        }
        var EffectSet = kendo.Class.extend({
            init: function (element, options) {
                var that = this;
                that.element = element;
                that.effects = [];
                that.options = options;
                that.restore = [];
            },
            run: function (effects) {
                var that = this, effect, idx, jdx, length = effects.length, element = that.element, options = that.options, deferred = $.Deferred(), start = {}, end = {}, target, children, childrenLength;
                that.effects = effects;
                deferred.then($.proxy(that, 'complete'));
                element.data('animating', true);
                for (idx = 0; idx < length; idx++) {
                    effect = effects[idx];
                    effect.setReverse(options.reverse);
                    effect.setOptions(options);
                    that.addRestoreProperties(effect.restore);
                    effect.prepare(start, end);
                    children = effect.children();
                    for (jdx = 0, childrenLength = children.length; jdx < childrenLength; jdx++) {
                        children[jdx].duration(options.duration).run();
                    }
                }
                for (var effectName in options.effects) {
                    extend(end, options.effects[effectName].properties);
                }
                if (!element.is(':visible')) {
                    extend(start, { display: element.data('olddisplay') || 'block' });
                }
                if (transforms && !options.reset) {
                    target = element.data('targetTransform');
                    if (target) {
                        start = extend(target, start);
                    }
                }
                start = normalizeCSS(element, start);
                if (transforms && !transitions) {
                    start = strip3DTransforms(start);
                }
                element.css(start).css(TRANSFORM);
                for (idx = 0; idx < length; idx++) {
                    effects[idx].setup();
                }
                if (options.init) {
                    options.init();
                }
                element.data('targetTransform', end);
                fx.animate(element, end, extend({}, options, { complete: deferred.resolve }));
                return deferred.promise();
            },
            stop: function () {
                $(this.element).kendoStop(true, true);
            },
            addRestoreProperties: function (restore) {
                var element = this.element, value, i = 0, length = restore.length;
                for (; i < length; i++) {
                    value = restore[i];
                    this.restore.push(value);
                    if (!element.data(value)) {
                        element.data(value, element.css(value));
                    }
                }
            },
            restoreCallback: function () {
                var element = this.element;
                for (var i = 0, length = this.restore.length; i < length; i++) {
                    var value = this.restore[i];
                    element.css(value, element.data(value));
                }
            },
            complete: function () {
                var that = this, idx = 0, element = that.element, options = that.options, effects = that.effects, length = effects.length;
                element.removeData('animating').dequeue();
                if (options.hide) {
                    element.data('olddisplay', element.css('display')).hide();
                }
                this.restoreCallback();
                if (hasZoom && !transforms) {
                    setTimeout($.proxy(this, 'restoreCallback'), 0);
                }
                for (; idx < length; idx++) {
                    effects[idx].teardown();
                }
                if (options.completeCallback) {
                    options.completeCallback(element);
                }
            }
        });
        fx.promise = function (element, options) {
            var effects = [], effectClass, effectSet = new EffectSet(element, options), parsedEffects = kendo.parseEffects(options.effects), effect;
            options.effects = parsedEffects;
            for (var effectName in parsedEffects) {
                effectClass = fx[capitalize(effectName)];
                if (effectClass) {
                    effect = new effectClass(element, parsedEffects[effectName].direction);
                    effects.push(effect);
                }
            }
            if (effects[0]) {
                effectSet.run(effects);
            } else {
                if (!element.is(':visible')) {
                    element.css({ display: element.data('olddisplay') || 'block' }).css('display');
                }
                if (options.init) {
                    options.init();
                }
                element.dequeue();
                effectSet.complete();
            }
        };
        extend(fx, {
            animate: function (elements, properties, options) {
                var useTransition = options.transition !== false;
                delete options.transition;
                if (transitions && 'transition' in fx && useTransition) {
                    fx.transition(elements, properties, options);
                } else {
                    if (transforms) {
                        elements.animate(strip3DTransforms(properties), {
                            queue: false,
                            show: false,
                            hide: false,
                            duration: options.duration,
                            complete: options.complete
                        });
                    } else {
                        elements.each(function () {
                            var element = $(this), multiple = {};
                            each(transformProps, function (idx, value) {
                                var params, currentValue = properties ? properties[value] + ' ' : null;
                                if (currentValue) {
                                    var single = properties;
                                    if (value in scaleProperties && properties[value] !== undefined) {
                                        params = currentValue.match(cssParamsRegExp);
                                        if (transforms) {
                                            extend(single, { scale: +params[0] });
                                        }
                                    } else {
                                        if (value in translateProperties && properties[value] !== undefined) {
                                            var position = element.css(POSITION), isFixed = position == 'absolute' || position == 'fixed';
                                            if (!element.data(TRANSLATE)) {
                                                if (isFixed) {
                                                    element.data(TRANSLATE, {
                                                        top: parseCSS(element, 'top') || 0,
                                                        left: parseCSS(element, 'left') || 0,
                                                        bottom: parseCSS(element, 'bottom'),
                                                        right: parseCSS(element, 'right')
                                                    });
                                                } else {
                                                    element.data(TRANSLATE, {
                                                        top: parseCSS(element, 'marginTop') || 0,
                                                        left: parseCSS(element, 'marginLeft') || 0
                                                    });
                                                }
                                            }
                                            var originalPosition = element.data(TRANSLATE);
                                            params = currentValue.match(cssParamsRegExp);
                                            if (params) {
                                                var dX = value == TRANSLATE + 'y' ? +null : +params[1], dY = value == TRANSLATE + 'y' ? +params[1] : +params[2];
                                                if (isFixed) {
                                                    if (!isNaN(originalPosition.right)) {
                                                        if (!isNaN(dX)) {
                                                            extend(single, { right: originalPosition.right - dX });
                                                        }
                                                    } else {
                                                        if (!isNaN(dX)) {
                                                            extend(single, { left: originalPosition.left + dX });
                                                        }
                                                    }
                                                    if (!isNaN(originalPosition.bottom)) {
                                                        if (!isNaN(dY)) {
                                                            extend(single, { bottom: originalPosition.bottom - dY });
                                                        }
                                                    } else {
                                                        if (!isNaN(dY)) {
                                                            extend(single, { top: originalPosition.top + dY });
                                                        }
                                                    }
                                                } else {
                                                    if (!isNaN(dX)) {
                                                        extend(single, { marginLeft: originalPosition.left + dX });
                                                    }
                                                    if (!isNaN(dY)) {
                                                        extend(single, { marginTop: originalPosition.top + dY });
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    if (!transforms && value != 'scale' && value in single) {
                                        delete single[value];
                                    }
                                    if (single) {
                                        extend(multiple, single);
                                    }
                                }
                            });
                            if (browser.msie) {
                                delete multiple.scale;
                            }
                            element.animate(multiple, {
                                queue: false,
                                show: false,
                                hide: false,
                                duration: options.duration,
                                complete: options.complete
                            });
                        });
                    }
                }
            }
        });
        fx.animatedPromise = fx.promise;
        var Effect = kendo.Class.extend({
            init: function (element, direction) {
                var that = this;
                that.element = element;
                that._direction = direction;
                that.options = {};
                that._additionalEffects = [];
                if (!that.restore) {
                    that.restore = [];
                }
            },
            reverse: function () {
                this._reverse = true;
                return this.run();
            },
            play: function () {
                this._reverse = false;
                return this.run();
            },
            add: function (additional) {
                this._additionalEffects.push(additional);
                return this;
            },
            direction: function (value) {
                this._direction = value;
                return this;
            },
            duration: function (duration) {
                this._duration = duration;
                return this;
            },
            compositeRun: function () {
                var that = this, effectSet = new EffectSet(that.element, {
                        reverse: that._reverse,
                        duration: that._duration
                    }), effects = that._additionalEffects.concat([that]);
                return effectSet.run(effects);
            },
            run: function () {
                if (this._additionalEffects && this._additionalEffects[0]) {
                    return this.compositeRun();
                }
                var that = this, element = that.element, idx = 0, restore = that.restore, length = restore.length, value, deferred = $.Deferred(), start = {}, end = {}, target, children = that.children(), childrenLength = children.length;
                deferred.then($.proxy(that, '_complete'));
                element.data('animating', true);
                for (idx = 0; idx < length; idx++) {
                    value = restore[idx];
                    if (!element.data(value)) {
                        element.data(value, element.css(value));
                    }
                }
                for (idx = 0; idx < childrenLength; idx++) {
                    children[idx].duration(that._duration).run();
                }
                that.prepare(start, end);
                if (!element.is(':visible')) {
                    extend(start, { display: element.data('olddisplay') || 'block' });
                }
                if (transforms) {
                    target = element.data('targetTransform');
                    if (target) {
                        start = extend(target, start);
                    }
                }
                start = normalizeCSS(element, start);
                if (transforms && !transitions) {
                    start = strip3DTransforms(start);
                }
                element.css(start).css(TRANSFORM);
                that.setup();
                element.data('targetTransform', end);
                fx.animate(element, end, {
                    duration: that._duration,
                    complete: deferred.resolve
                });
                return deferred.promise();
            },
            stop: function () {
                var idx = 0, children = this.children(), childrenLength = children.length;
                for (idx = 0; idx < childrenLength; idx++) {
                    children[idx].stop();
                }
                $(this.element).kendoStop(true, true);
                return this;
            },
            restoreCallback: function () {
                var element = this.element;
                for (var i = 0, length = this.restore.length; i < length; i++) {
                    var value = this.restore[i];
                    element.css(value, element.data(value));
                }
            },
            _complete: function () {
                var that = this, element = that.element;
                element.removeData('animating').dequeue();
                that.restoreCallback();
                if (that.shouldHide()) {
                    element.data('olddisplay', element.css('display')).hide();
                }
                if (hasZoom && !transforms) {
                    setTimeout($.proxy(that, 'restoreCallback'), 0);
                }
                that.teardown();
            },
            setOptions: function (options) {
                extend(true, this.options, options);
            },
            children: function () {
                return [];
            },
            shouldHide: $.noop,
            setup: $.noop,
            prepare: $.noop,
            teardown: $.noop,
            directions: [],
            setReverse: function (reverse) {
                this._reverse = reverse;
                return this;
            }
        });
        function capitalize(word) {
            return word.charAt(0).toUpperCase() + word.substring(1);
        }
        function createEffect(name, definition) {
            var effectClass = Effect.extend(definition), directions = effectClass.prototype.directions;
            fx[capitalize(name)] = effectClass;
            fx.Element.prototype[name] = function (direction, opt1, opt2, opt3) {
                return new effectClass(this.element, direction, opt1, opt2, opt3);
            };
            each(directions, function (idx, theDirection) {
                fx.Element.prototype[name + capitalize(theDirection)] = function (opt1, opt2, opt3) {
                    return new effectClass(this.element, theDirection, opt1, opt2, opt3);
                };
            });
        }
        var FOUR_DIRECTIONS = [
                'left',
                'right',
                'up',
                'down'
            ], IN_OUT = [
                'in',
                'out'
            ];
        createEffect('slideIn', {
            directions: FOUR_DIRECTIONS,
            divisor: function (value) {
                this.options.divisor = value;
                return this;
            },
            prepare: function (start, end) {
                var that = this, tmp, element = that.element, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, direction = directions[that._direction], offset = -direction.modifier * (direction.vertical ? outerHeight(element) : outerWidth(element)), startValue = offset / (that.options && that.options.divisor || 1) + PX, endValue = '0px';
                if (that._reverse) {
                    tmp = start;
                    start = end;
                    end = tmp;
                }
                if (transforms) {
                    start[direction.transition] = startValue;
                    end[direction.transition] = endValue;
                } else {
                    start[direction.property] = startValue;
                    end[direction.property] = endValue;
                }
            }
        });
        createEffect('tile', {
            directions: FOUR_DIRECTIONS,
            init: function (element, direction, previous) {
                Effect.prototype.init.call(this, element, direction);
                this.options = { previous: previous };
            },
            previousDivisor: function (value) {
                this.options.previousDivisor = value;
                return this;
            },
            children: function () {
                var that = this, reverse = that._reverse, previous = that.options.previous, divisor = that.options.previousDivisor || 1, dir = that._direction;
                var children = [kendo.fx(that.element).slideIn(dir).setReverse(reverse)];
                if (previous) {
                    children.push(kendo.fx(previous).slideIn(directions[dir].reverse).divisor(divisor).setReverse(!reverse));
                }
                return children;
            }
        });
        function createToggleEffect(name, property, defaultStart, defaultEnd) {
            createEffect(name, {
                directions: IN_OUT,
                startValue: function (value) {
                    this._startValue = value;
                    return this;
                },
                endValue: function (value) {
                    this._endValue = value;
                    return this;
                },
                shouldHide: function () {
                    return this._shouldHide;
                },
                prepare: function (start, end) {
                    var that = this, startValue, endValue, out = this._direction === 'out', startDataValue = that.element.data(property), startDataValueIsSet = !(isNaN(startDataValue) || startDataValue == defaultStart);
                    if (startDataValueIsSet) {
                        startValue = startDataValue;
                    } else if (typeof this._startValue !== 'undefined') {
                        startValue = this._startValue;
                    } else {
                        startValue = out ? defaultStart : defaultEnd;
                    }
                    if (typeof this._endValue !== 'undefined') {
                        endValue = this._endValue;
                    } else {
                        endValue = out ? defaultEnd : defaultStart;
                    }
                    if (this._reverse) {
                        start[property] = endValue;
                        end[property] = startValue;
                    } else {
                        start[property] = startValue;
                        end[property] = endValue;
                    }
                    that._shouldHide = end[property] === defaultEnd;
                }
            });
        }
        createToggleEffect('fade', 'opacity', 1, 0);
        createToggleEffect('zoom', 'scale', 1, 0.01);
        createEffect('slideMargin', {
            prepare: function (start, end) {
                var that = this, element = that.element, options = that.options, origin = element.data(ORIGIN), offset = options.offset, margin, reverse = that._reverse;
                if (!reverse && origin === null) {
                    element.data(ORIGIN, parseFloat(element.css('margin-' + options.axis)));
                }
                margin = element.data(ORIGIN) || 0;
                end['margin-' + options.axis] = !reverse ? margin + offset : margin;
            }
        });
        createEffect('slideTo', {
            prepare: function (start, end) {
                var that = this, element = that.element, options = that.options, offset = options.offset.split(','), reverse = that._reverse;
                if (transforms) {
                    end.translatex = !reverse ? offset[0] : 0;
                    end.translatey = !reverse ? offset[1] : 0;
                } else {
                    end.left = !reverse ? offset[0] : 0;
                    end.top = !reverse ? offset[1] : 0;
                }
                element.css('left');
            }
        });
        createEffect('expand', {
            directions: [
                'horizontal',
                'vertical'
            ],
            restore: [OVERFLOW],
            prepare: function (start, end) {
                var that = this, element = that.element, options = that.options, reverse = that._reverse, property = that._direction === 'vertical' ? HEIGHT : WIDTH, setLength = element[0].style[property], oldLength = element.data(property), length = parseFloat(oldLength || setLength), realLength = round(element.css(property, AUTO)[property]());
                start.overflow = HIDDEN;
                length = options && options.reset ? realLength || length : length || realLength;
                end[property] = (reverse ? 0 : length) + PX;
                start[property] = (reverse ? length : 0) + PX;
                if (oldLength === undefined) {
                    element.data(property, setLength);
                }
            },
            shouldHide: function () {
                return this._reverse;
            },
            teardown: function () {
                var that = this, element = that.element, property = that._direction === 'vertical' ? HEIGHT : WIDTH, length = element.data(property);
                if (length == AUTO || length === BLANK) {
                    setTimeout(function () {
                        element.css(property, AUTO).css(property);
                    }, 0);
                }
            }
        });
        var TRANSFER_START_STATE = {
            position: 'absolute',
            marginLeft: 0,
            marginTop: 0,
            scale: 1
        };
        createEffect('transfer', {
            init: function (element, target) {
                this.element = element;
                this.options = { target: target };
                this.restore = [];
            },
            setup: function () {
                this.element.appendTo(document.body);
            },
            prepare: function (start, end) {
                var that = this, element = that.element, outerBox = fx.box(element), innerBox = fx.box(that.options.target), currentScale = animationProperty(element, 'scale'), scale = fx.fillScale(innerBox, outerBox), transformOrigin = fx.transformOrigin(innerBox, outerBox);
                extend(start, TRANSFER_START_STATE);
                end.scale = 1;
                element.css(TRANSFORM, 'scale(1)').css(TRANSFORM);
                element.css(TRANSFORM, 'scale(' + currentScale + ')');
                start.top = outerBox.top;
                start.left = outerBox.left;
                start.transformOrigin = transformOrigin.x + PX + ' ' + transformOrigin.y + PX;
                if (that._reverse) {
                    start.scale = scale;
                } else {
                    end.scale = scale;
                }
            }
        });
        var CLIPS = {
            top: 'rect(auto auto $size auto)',
            bottom: 'rect($size auto auto auto)',
            left: 'rect(auto $size auto auto)',
            right: 'rect(auto auto auto $size)'
        };
        var ROTATIONS = {
            top: {
                start: 'rotatex(0deg)',
                end: 'rotatex(180deg)'
            },
            bottom: {
                start: 'rotatex(-180deg)',
                end: 'rotatex(0deg)'
            },
            left: {
                start: 'rotatey(0deg)',
                end: 'rotatey(-180deg)'
            },
            right: {
                start: 'rotatey(180deg)',
                end: 'rotatey(0deg)'
            }
        };
        function clipInHalf(container, direction) {
            var vertical = kendo.directions[direction].vertical, size = container[vertical ? HEIGHT : WIDTH]() / 2 + 'px';
            return CLIPS[direction].replace('$size', size);
        }
        createEffect('turningPage', {
            directions: FOUR_DIRECTIONS,
            init: function (element, direction, container) {
                Effect.prototype.init.call(this, element, direction);
                this._container = container;
            },
            prepare: function (start, end) {
                var that = this, reverse = that._reverse, direction = reverse ? directions[that._direction].reverse : that._direction, rotation = ROTATIONS[direction];
                start.zIndex = 1;
                if (that._clipInHalf) {
                    start.clip = clipInHalf(that._container, kendo.directions[direction].reverse);
                }
                start[BACKFACE] = HIDDEN;
                end[TRANSFORM] = TRANSFORM_PERSPECTIVE + (reverse ? rotation.start : rotation.end);
                start[TRANSFORM] = TRANSFORM_PERSPECTIVE + (reverse ? rotation.end : rotation.start);
            },
            setup: function () {
                this._container.append(this.element);
            },
            face: function (value) {
                this._face = value;
                return this;
            },
            shouldHide: function () {
                var that = this, reverse = that._reverse, face = that._face;
                return reverse && !face || !reverse && face;
            },
            clipInHalf: function (value) {
                this._clipInHalf = value;
                return this;
            },
            temporary: function () {
                this.element.addClass('temp-page');
                return this;
            }
        });
        createEffect('staticPage', {
            directions: FOUR_DIRECTIONS,
            init: function (element, direction, container) {
                Effect.prototype.init.call(this, element, direction);
                this._container = container;
            },
            restore: ['clip'],
            prepare: function (start, end) {
                var that = this, direction = that._reverse ? directions[that._direction].reverse : that._direction;
                start.clip = clipInHalf(that._container, direction);
                start.opacity = 0.999;
                end.opacity = 1;
            },
            shouldHide: function () {
                var that = this, reverse = that._reverse, face = that._face;
                return reverse && !face || !reverse && face;
            },
            face: function (value) {
                this._face = value;
                return this;
            }
        });
        createEffect('pageturn', {
            directions: [
                'horizontal',
                'vertical'
            ],
            init: function (element, direction, face, back) {
                Effect.prototype.init.call(this, element, direction);
                this.options = {};
                this.options.face = face;
                this.options.back = back;
            },
            children: function () {
                var that = this, options = that.options, direction = that._direction === 'horizontal' ? 'left' : 'top', reverseDirection = kendo.directions[direction].reverse, reverse = that._reverse, temp, faceClone = options.face.clone(true).removeAttr('id'), backClone = options.back.clone(true).removeAttr('id'), element = that.element;
                if (reverse) {
                    temp = direction;
                    direction = reverseDirection;
                    reverseDirection = temp;
                }
                return [
                    kendo.fx(options.face).staticPage(direction, element).face(true).setReverse(reverse),
                    kendo.fx(options.back).staticPage(reverseDirection, element).setReverse(reverse),
                    kendo.fx(faceClone).turningPage(direction, element).face(true).clipInHalf(true).temporary().setReverse(reverse),
                    kendo.fx(backClone).turningPage(reverseDirection, element).clipInHalf(true).temporary().setReverse(reverse)
                ];
            },
            prepare: function (start, end) {
                start[PERSPECTIVE] = DEFAULT_PERSPECTIVE;
                start.transformStyle = 'preserve-3d';
                start.opacity = 0.999;
                end.opacity = 1;
            },
            teardown: function () {
                this.element.find('.temp-page').remove();
            }
        });
        createEffect('flip', {
            directions: [
                'horizontal',
                'vertical'
            ],
            init: function (element, direction, face, back) {
                Effect.prototype.init.call(this, element, direction);
                this.options = {};
                this.options.face = face;
                this.options.back = back;
            },
            children: function () {
                var that = this, options = that.options, direction = that._direction === 'horizontal' ? 'left' : 'top', reverseDirection = kendo.directions[direction].reverse, reverse = that._reverse, temp, element = that.element;
                if (reverse) {
                    temp = direction;
                    direction = reverseDirection;
                    reverseDirection = temp;
                }
                return [
                    kendo.fx(options.face).turningPage(direction, element).face(true).setReverse(reverse),
                    kendo.fx(options.back).turningPage(reverseDirection, element).setReverse(reverse)
                ];
            },
            prepare: function (start) {
                start[PERSPECTIVE] = DEFAULT_PERSPECTIVE;
                start.transformStyle = 'preserve-3d';
            }
        });
        var RESTORE_OVERFLOW = !support.mobileOS.android;
        var IGNORE_TRANSITION_EVENT_SELECTOR = '.km-touch-scrollbar, .km-actionsheet-wrapper';
        createEffect('replace', {
            _before: $.noop,
            _after: $.noop,
            init: function (element, previous, transitionClass) {
                Effect.prototype.init.call(this, element);
                this._previous = $(previous);
                this._transitionClass = transitionClass;
            },
            duration: function () {
                throw new Error('The replace effect does not support duration setting; the effect duration may be customized through the transition class rule');
            },
            beforeTransition: function (callback) {
                this._before = callback;
                return this;
            },
            afterTransition: function (callback) {
                this._after = callback;
                return this;
            },
            _both: function () {
                return $().add(this._element).add(this._previous);
            },
            _containerClass: function () {
                var direction = this._direction, containerClass = 'k-fx k-fx-start k-fx-' + this._transitionClass;
                if (direction) {
                    containerClass += ' k-fx-' + direction;
                }
                if (this._reverse) {
                    containerClass += ' k-fx-reverse';
                }
                return containerClass;
            },
            complete: function (e) {
                if (!this.deferred || e && $(e.target).is(IGNORE_TRANSITION_EVENT_SELECTOR)) {
                    return;
                }
                var container = this.container;
                container.removeClass('k-fx-end').removeClass(this._containerClass()).off(transitions.event, this.completeProxy);
                this._previous.hide().removeClass('k-fx-current');
                this.element.removeClass('k-fx-next');
                if (RESTORE_OVERFLOW) {
                    container.css(OVERFLOW, '');
                }
                if (!this.isAbsolute) {
                    this._both().css(POSITION, '');
                }
                this.deferred.resolve();
                delete this.deferred;
            },
            run: function () {
                if (this._additionalEffects && this._additionalEffects[0]) {
                    return this.compositeRun();
                }
                var that = this, element = that.element, previous = that._previous, container = element.parents().filter(previous.parents()).first(), both = that._both(), deferred = $.Deferred(), originalPosition = element.css(POSITION), originalOverflow;
                if (!container.length) {
                    container = element.parent();
                }
                this.container = container;
                this.deferred = deferred;
                this.isAbsolute = originalPosition == 'absolute';
                if (!this.isAbsolute) {
                    both.css(POSITION, 'absolute');
                }
                if (RESTORE_OVERFLOW) {
                    originalOverflow = container.css(OVERFLOW);
                    container.css(OVERFLOW, 'hidden');
                }
                if (!transitions) {
                    this.complete();
                } else {
                    element.addClass('k-fx-hidden');
                    container.addClass(this._containerClass());
                    this.completeProxy = $.proxy(this, 'complete');
                    container.on(transitions.event, this.completeProxy);
                    kendo.animationFrame(function () {
                        element.removeClass('k-fx-hidden').addClass('k-fx-next');
                        previous.css('display', '').addClass('k-fx-current');
                        that._before(previous, element);
                        kendo.animationFrame(function () {
                            container.removeClass('k-fx-start').addClass('k-fx-end');
                            that._after(previous, element);
                        });
                    });
                }
                return deferred.promise();
            },
            stop: function () {
                this.complete();
            }
        });
        var Animation = kendo.Class.extend({
            init: function () {
                var that = this;
                that._tickProxy = proxy(that._tick, that);
                that._started = false;
            },
            tick: $.noop,
            done: $.noop,
            onEnd: $.noop,
            onCancel: $.noop,
            start: function () {
                if (!this.enabled()) {
                    return;
                }
                if (!this.done()) {
                    this._started = true;
                    kendo.animationFrame(this._tickProxy);
                } else {
                    this.onEnd();
                }
            },
            enabled: function () {
                return true;
            },
            cancel: function () {
                this._started = false;
                this.onCancel();
            },
            _tick: function () {
                var that = this;
                if (!that._started) {
                    return;
                }
                that.tick();
                if (!that.done()) {
                    kendo.animationFrame(that._tickProxy);
                } else {
                    that._started = false;
                    that.onEnd();
                }
            }
        });
        var Transition = Animation.extend({
            init: function (options) {
                var that = this;
                extend(that, options);
                Animation.fn.init.call(that);
            },
            done: function () {
                return this.timePassed() >= this.duration;
            },
            timePassed: function () {
                return Math.min(this.duration, new Date() - this.startDate);
            },
            moveTo: function (options) {
                var that = this, movable = that.movable;
                that.initial = movable[that.axis];
                that.delta = options.location - that.initial;
                that.duration = typeof options.duration == 'number' ? options.duration : 300;
                that.tick = that._easeProxy(options.ease);
                that.startDate = new Date();
                that.start();
            },
            _easeProxy: function (ease) {
                var that = this;
                return function () {
                    that.movable.moveAxis(that.axis, ease(that.timePassed(), that.initial, that.delta, that.duration));
                };
            }
        });
        extend(Transition, {
            easeOutExpo: function (t, b, c, d) {
                return t == d ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
            },
            easeOutBack: function (t, b, c, d, s) {
                s = 1.70158;
                return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
            }
        });
        fx.Animation = Animation;
        fx.Transition = Transition;
        fx.createEffect = createEffect;
        fx.box = function (element) {
            element = $(element);
            var result = element.offset();
            result.width = kendo._outerWidth(element);
            result.height = kendo._outerHeight(element);
            return result;
        };
        fx.transformOrigin = function (inner, outer) {
            var x = (inner.left - outer.left) * outer.width / (outer.width - inner.width), y = (inner.top - outer.top) * outer.height / (outer.height - inner.height);
            return {
                x: isNaN(x) ? 0 : x,
                y: isNaN(y) ? 0 : y
            };
        };
        fx.fillScale = function (inner, outer) {
            return Math.min(inner.width / outer.width, inner.height / outer.height);
        };
        fx.fitScale = function (inner, outer) {
            return Math.max(inner.width / outer.width, inner.height / outer.height);
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.view', [
        'kendo.core',
        'kendo.binder',
        'kendo.fx'
    ], f);
}(function () {
    var __meta__ = {
        id: 'view',
        name: 'View',
        category: 'framework',
        description: 'The View class instantiates and handles the events of a certain screen from the application.',
        depends: [
            'core',
            'binder',
            'fx'
        ],
        hidden: false
    };
    (function ($, undefined) {
        var kendo = window.kendo, Observable = kendo.Observable, SCRIPT = 'SCRIPT', INIT = 'init', SHOW = 'show', HIDE = 'hide', TRANSITION_START = 'transitionStart', TRANSITION_END = 'transitionEnd', ATTACH = 'attach', DETACH = 'detach', sizzleErrorRegExp = /unrecognized expression/;
        var View = Observable.extend({
            init: function (content, options) {
                var that = this;
                options = options || {};
                Observable.fn.init.call(that);
                that.content = content;
                that.id = kendo.guid();
                that.tagName = options.tagName || 'div';
                that.model = options.model;
                that._wrap = options.wrap !== false;
                this._evalTemplate = options.evalTemplate || false;
                that._fragments = {};
                that.bind([
                    INIT,
                    SHOW,
                    HIDE,
                    TRANSITION_START,
                    TRANSITION_END
                ], options);
            },
            render: function (container) {
                var that = this, notInitialized = !that.element;
                if (notInitialized) {
                    that.element = that._createElement();
                }
                if (container) {
                    $(container).append(that.element);
                }
                if (notInitialized) {
                    kendo.bind(that.element, that.model);
                    that.trigger(INIT);
                }
                if (container) {
                    that._eachFragment(ATTACH);
                    that.trigger(SHOW);
                }
                return that.element;
            },
            clone: function () {
                return new ViewClone(this);
            },
            triggerBeforeShow: function () {
                return true;
            },
            triggerBeforeHide: function () {
                return true;
            },
            showStart: function () {
                this.element.css('display', '');
            },
            showEnd: function () {
            },
            hideEnd: function () {
                this.hide();
            },
            beforeTransition: function (type) {
                this.trigger(TRANSITION_START, { type: type });
            },
            afterTransition: function (type) {
                this.trigger(TRANSITION_END, { type: type });
            },
            hide: function () {
                this._eachFragment(DETACH);
                this.element.detach();
                this.trigger(HIDE);
            },
            destroy: function () {
                var element = this.element;
                if (element) {
                    kendo.unbind(element);
                    kendo.destroy(element);
                    element.remove();
                }
            },
            fragments: function (fragments) {
                $.extend(this._fragments, fragments);
            },
            _eachFragment: function (methodName) {
                for (var placeholder in this._fragments) {
                    this._fragments[placeholder][methodName](this, placeholder);
                }
            },
            _createElement: function () {
                var that = this, wrapper = '<' + that.tagName + ' />', element, content;
                try {
                    content = $(document.getElementById(that.content) || that.content);
                    if (content[0].tagName === SCRIPT) {
                        content = content.html();
                    }
                } catch (e) {
                    if (sizzleErrorRegExp.test(e.message)) {
                        content = that.content;
                    }
                }
                if (typeof content === 'string') {
                    content = content.replace(/^\s+|\s+$/g, '');
                    if (that._evalTemplate) {
                        content = kendo.template(content)(that.model || {});
                    }
                    element = $(wrapper).append(content);
                    if (!that._wrap) {
                        element = element.contents();
                    }
                } else {
                    element = content;
                    if (that._evalTemplate) {
                        var result = $(kendo.template($('<div />').append(element.clone(true)).html())(that.model || {}));
                        if ($.contains(document, element[0])) {
                            element.replaceWith(result);
                        }
                        element = result;
                    }
                    if (that._wrap) {
                        element = element.wrapAll(wrapper).parent();
                    }
                }
                return element;
            }
        });
        var ViewClone = kendo.Class.extend({
            init: function (view) {
                $.extend(this, {
                    element: view.element.clone(true),
                    transition: view.transition,
                    id: view.id
                });
                view.element.parent().append(this.element);
            },
            hideEnd: function () {
                this.element.remove();
            },
            beforeTransition: $.noop,
            afterTransition: $.noop
        });
        var Layout = View.extend({
            init: function (content, options) {
                View.fn.init.call(this, content, options);
                this.containers = {};
            },
            container: function (selector) {
                var container = this.containers[selector];
                if (!container) {
                    container = this._createContainer(selector);
                    this.containers[selector] = container;
                }
                return container;
            },
            showIn: function (selector, view, transition) {
                this.container(selector).show(view, transition);
            },
            _createContainer: function (selector) {
                var root = this.render(), element = root.find(selector), container;
                if (!element.length && root.is(selector)) {
                    if (root.is(selector)) {
                        element = root;
                    } else {
                        throw new Error('can\'t find a container with the specified ' + selector + ' selector');
                    }
                }
                container = new ViewContainer(element);
                container.bind('accepted', function (e) {
                    e.view.render(element);
                });
                return container;
            }
        });
        var Fragment = View.extend({
            attach: function (view, placeholder) {
                view.element.find(placeholder).replaceWith(this.render());
            },
            detach: function () {
            }
        });
        var transitionRegExp = /^(\w+)(:(\w+))?( (\w+))?$/;
        function parseTransition(transition) {
            if (!transition) {
                return {};
            }
            var matches = transition.match(transitionRegExp) || [];
            return {
                type: matches[1],
                direction: matches[3],
                reverse: matches[5] === 'reverse'
            };
        }
        var ViewContainer = Observable.extend({
            init: function (container) {
                Observable.fn.init.call(this);
                this.container = container;
                this.history = [];
                this.view = null;
                this.running = false;
            },
            after: function () {
                this.running = false;
                this.trigger('complete', { view: this.view });
                this.trigger('after');
            },
            end: function () {
                this.view.showEnd();
                this.previous.hideEnd();
                this.after();
            },
            show: function (view, transition, locationID) {
                if (!view.triggerBeforeShow() || this.view && !this.view.triggerBeforeHide()) {
                    this.trigger('after');
                    return false;
                }
                locationID = locationID || view.id;
                var that = this, current = view === that.view ? view.clone() : that.view, history = that.history, previousEntry = history[history.length - 2] || {}, back = previousEntry.id === locationID, theTransition = transition || (back ? history[history.length - 1].transition : view.transition), transitionData = parseTransition(theTransition);
                if (that.running) {
                    that.effect.stop();
                }
                if (theTransition === 'none') {
                    theTransition = null;
                }
                that.trigger('accepted', { view: view });
                that.view = view;
                that.previous = current;
                that.running = true;
                if (!back) {
                    history.push({
                        id: locationID,
                        transition: theTransition
                    });
                } else {
                    history.pop();
                }
                if (!current) {
                    view.showStart();
                    view.showEnd();
                    that.after();
                    return true;
                }
                if (!theTransition || !kendo.effects.enabled) {
                    view.showStart();
                    that.end();
                } else {
                    view.element.addClass('k-fx-hidden');
                    view.showStart();
                    if (back && !transition) {
                        transitionData.reverse = !transitionData.reverse;
                    }
                    that.effect = kendo.fx(view.element).replace(current.element, transitionData.type).beforeTransition(function () {
                        view.beforeTransition('show');
                        current.beforeTransition('hide');
                    }).afterTransition(function () {
                        view.afterTransition('show');
                        current.afterTransition('hide');
                    }).direction(transitionData.direction).setReverse(transitionData.reverse);
                    that.effect.run().then(function () {
                        that.end();
                    });
                }
                return true;
            }
        });
        kendo.ViewContainer = ViewContainer;
        kendo.Fragment = Fragment;
        kendo.Layout = Layout;
        kendo.View = View;
        kendo.ViewClone = ViewClone;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dom', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'dom',
        name: 'Virtual DOM',
        category: 'framework',
        depends: ['core'],
        advanced: true
    };
    (function (kendo) {
        function Node() {
            this.node = null;
        }
        Node.prototype = {
            remove: function () {
                if (this.node.parentNode) {
                    this.node.parentNode.removeChild(this.node);
                }
                this.attr = {};
            },
            attr: {},
            text: function () {
                return '';
            }
        };
        function NullNode() {
        }
        NullNode.prototype = {
            nodeName: '#null',
            attr: { style: {} },
            children: [],
            remove: function () {
            }
        };
        var NULL_NODE = new NullNode();
        function Element(nodeName, attr, children) {
            this.nodeName = nodeName;
            this.attr = attr || {};
            this.children = children || [];
        }
        Element.prototype = new Node();
        Element.prototype.appendTo = function (parent) {
            var node = document.createElement(this.nodeName);
            var children = this.children;
            for (var index = 0; index < children.length; index++) {
                children[index].render(node, NULL_NODE);
            }
            parent.appendChild(node);
            return node;
        };
        Element.prototype.render = function (parent, cached) {
            var node;
            if (cached.nodeName !== this.nodeName) {
                cached.remove();
                node = this.appendTo(parent);
            } else {
                node = cached.node;
                var index;
                var children = this.children;
                var length = children.length;
                var cachedChildren = cached.children;
                var cachedLength = cachedChildren.length;
                if (Math.abs(cachedLength - length) > 2) {
                    this.render({
                        appendChild: function (node) {
                            parent.replaceChild(node, cached.node);
                        }
                    }, NULL_NODE);
                    return;
                }
                for (index = 0; index < length; index++) {
                    children[index].render(node, cachedChildren[index] || NULL_NODE);
                }
                for (index = length; index < cachedLength; index++) {
                    cachedChildren[index].remove();
                }
            }
            this.node = node;
            this.syncAttributes(cached.attr);
            this.removeAttributes(cached.attr);
        };
        Element.prototype.syncAttributes = function (cachedAttr) {
            var attr = this.attr;
            for (var name in attr) {
                var value = attr[name];
                var cachedValue = cachedAttr[name];
                if (name === 'style') {
                    this.setStyle(value, cachedValue);
                } else if (value !== cachedValue) {
                    this.setAttribute(name, value, cachedValue);
                }
            }
        };
        Element.prototype.setStyle = function (style, cachedValue) {
            var node = this.node;
            var key;
            if (cachedValue) {
                for (key in style) {
                    if (style[key] !== cachedValue[key]) {
                        node.style[key] = style[key];
                    }
                }
            } else {
                for (key in style) {
                    node.style[key] = style[key];
                }
            }
        };
        Element.prototype.removeStyle = function (cachedStyle) {
            var style = this.attr.style || {};
            var node = this.node;
            for (var key in cachedStyle) {
                if (style[key] === undefined) {
                    node.style[key] = '';
                }
            }
        };
        Element.prototype.removeAttributes = function (cachedAttr) {
            var attr = this.attr;
            for (var name in cachedAttr) {
                if (name === 'style') {
                    this.removeStyle(cachedAttr.style);
                } else if (attr[name] === undefined) {
                    this.removeAttribute(name);
                }
            }
        };
        Element.prototype.removeAttribute = function (name) {
            var node = this.node;
            if (name === 'style') {
                node.style.cssText = '';
            } else if (name === 'className') {
                node.className = '';
            } else {
                node.removeAttribute(name);
            }
        };
        Element.prototype.setAttribute = function (name, value) {
            var node = this.node;
            if (node[name] !== undefined) {
                node[name] = value;
            } else {
                node.setAttribute(name, value);
            }
        };
        Element.prototype.text = function () {
            var str = '';
            for (var i = 0; i < this.children.length; ++i) {
                str += this.children[i].text();
            }
            return str;
        };
        function TextNode(nodeValue) {
            this.nodeValue = String(nodeValue);
        }
        TextNode.prototype = new Node();
        TextNode.prototype.nodeName = '#text';
        TextNode.prototype.render = function (parent, cached) {
            var node;
            if (cached.nodeName !== this.nodeName) {
                cached.remove();
                node = document.createTextNode(this.nodeValue);
                parent.appendChild(node);
            } else {
                node = cached.node;
                if (this.nodeValue !== cached.nodeValue) {
                    if (node.parentNode) {
                        node.nodeValue = this.nodeValue;
                    }
                }
            }
            this.node = node;
        };
        TextNode.prototype.text = function () {
            return this.nodeValue;
        };
        function HtmlNode(html) {
            this.html = html;
        }
        HtmlNode.prototype = {
            nodeName: '#html',
            attr: {},
            remove: function () {
                for (var index = 0; index < this.nodes.length; index++) {
                    var el = this.nodes[index];
                    if (el.parentNode) {
                        el.parentNode.removeChild(el);
                    }
                }
            },
            render: function (parent, cached) {
                if (cached.nodeName !== this.nodeName || cached.html !== this.html) {
                    cached.remove();
                    var lastChild = parent.lastChild;
                    insertHtml(parent, this.html);
                    this.nodes = [];
                    for (var child = lastChild ? lastChild.nextSibling : parent.firstChild; child; child = child.nextSibling) {
                        this.nodes.push(child);
                    }
                } else {
                    this.nodes = cached.nodes.slice(0);
                }
            }
        };
        var HTML_CONTAINER = document.createElement('div');
        function insertHtml(node, html) {
            HTML_CONTAINER.innerHTML = html;
            while (HTML_CONTAINER.firstChild) {
                node.appendChild(HTML_CONTAINER.firstChild);
            }
        }
        function html(value) {
            return new HtmlNode(value);
        }
        function element(nodeName, attrs, children) {
            return new Element(nodeName, attrs, children);
        }
        function text(value) {
            return new TextNode(value);
        }
        function Tree(root) {
            this.root = root;
            this.children = [];
        }
        Tree.prototype = {
            html: html,
            element: element,
            text: text,
            render: function (children) {
                var cachedChildren = this.children;
                var index;
                var length;
                for (index = 0, length = children.length; index < length; index++) {
                    var cached = cachedChildren[index];
                    if (!cached) {
                        cached = NULL_NODE;
                    } else if (!cached.node || !cached.node.parentNode) {
                        cached.remove();
                        cached = NULL_NODE;
                    }
                    children[index].render(this.root, cached);
                }
                for (index = length; index < cachedChildren.length; index++) {
                    cachedChildren[index].remove();
                }
                this.children = children;
            }
        };
        kendo.dom = {
            html: html,
            text: text,
            element: element,
            Tree: Tree,
            Node: Node
        };
    }(window.kendo));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('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 (defaultCellStyleId != null || (columns && columns.length > 0)) { #' + '<cols>' + '# if (!columns || !columns.length) { #' + '<col min="1" max="16384" style="${defaultCellStyleId}" ' + '# if (defaults.columnWidth) { # width="#= kendo.ooxml.toWidth(defaults.columnWidth) #" # } #' + ' />' + '# } #' + '# 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 #if(defaultCellStyleId!=null){# style="${defaultCellStyleId}" #}#' + 'min="${columnIndex}" max="${columnIndex}" hidden="1" customWidth="1" />' + '# } else if (column.width) { #' + '<col #if(defaultCellStyleId!=null){# style="${defaultCellStyleId}" #}#' + '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 === 0) { # hidden="1" # } ' + '  else 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 (autoFilter) { #' + '<autoFilter ref="${autoFilter.from}:${autoFilter.to}"/>' + '# } else if (filter) { #' + '#= kendo.ooxml.spreadsheetFilters(filter) #' + '# } #' + '# if (mergeCells.length) { #' + '<mergeCells count="${mergeCells.length}">' + '# for (var ci = 0; ci < mergeCells.length; ci++) { #' + '<mergeCell ref="${mergeCells[ci]}"/>' + '# } #' + '</mergeCells>' + '# } #' + '# if (validations.length) { #' + '<dataValidations>' + '# for (var vi = 0; vi < validations.length; vi++) { #' + '# var val = validations[vi]; #' + '<dataValidation sqref="#= val.sqref.join(" ") #"' + ' showErrorMessage="#= val.showErrorMessage #"' + ' type="#= val.type #"' + '# if (val.type != "list") {# operator="#= val.operator #" # } #' + ' allowBlank="#= val.allowBlank #"' + ' showDropDown="#= val.showDropDown #"' + '# if (val.error) {# error="#= val.error #" # } #' + '# if (val.errorTitle) {# errorTitle="#= val.errorTitle #" # } #' + '>' + '# if (val.formula1) { #' + '<formula1>#: val.formula1 #</formula1>' + '# } #' + '# if (val.formula2) { #' + '<formula2>#: val.formula2 #</formula2>' + '# } #' + '</dataValidation>' + '# } #' + '</dataValidations>' + '# } #' + '# if (hyperlinks.length) { #' + '<hyperlinks>' + '# for (var hi = 0; hi < hyperlinks.length; hi++) { #' + '<hyperlink ref="${hyperlinks[hi].ref}" r:id="rId${hi}"/>' + '# } #' + '</hyperlinks>' + '# } #' + '<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;
                this._validations = {};
            },
            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 autoFilter = this.options.filter;
                var filter;
                if (autoFilter && typeof autoFilter.from === 'number' && typeof autoFilter.to === 'number') {
                    autoFilter = {
                        from: ref(filterRowIndex(this.options), autoFilter.from),
                        to: ref(filterRowIndex(this.options), autoFilter.to)
                    };
                } else if (autoFilter && autoFilter.ref && autoFilter.columns) {
                    filter = autoFilter;
                    autoFilter = null;
                }
                var validations = [];
                for (var i in this._validations) {
                    if (Object.prototype.hasOwnProperty.call(this._validations, i)) {
                        validations.push(this._validations[i]);
                    }
                }
                var defaultCellStyleId = null;
                if (this.options.defaultCellStyle) {
                    defaultCellStyleId = this._lookupStyle(this.options.defaultCellStyle);
                }
                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,
                    autoFilter: autoFilter,
                    filter: filter,
                    showGridLines: this.options.showGridLines,
                    hyperlinks: this.options.hyperlinks || [],
                    validations: validations,
                    defaultCellStyleId: defaultCellStyleId
                });
            },
            _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 defStyle = this.options.defaultCellStyle || {};
                var style = { borderId: border };
                (function (add) {
                    add('color');
                    add('background');
                    add('bold');
                    add('italic');
                    add('underline');
                    if (!add('fontFamily')) {
                        add('fontName', 'fontFamily');
                    }
                    add('fontSize');
                    add('format');
                    if (!add('textAlign')) {
                        add('hAlign', 'textAlign');
                    }
                    if (!add('verticalAlign')) {
                        add('vAlign', 'verticalAlign');
                    }
                    add('wrap');
                }(function (prop, target) {
                    var val = data[prop];
                    if (val === undefined) {
                        val = defStyle[prop];
                    }
                    if (val !== undefined) {
                        style[target || prop] = val;
                        return true;
                    }
                }));
                var columns = this.options.columns || [];
                var column = columns[cellIndex];
                var type = typeof value;
                if (column && column.autoWidth) {
                    var displayValue = value;
                    if (type === 'number') {
                        displayValue = 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);
                var cellName = ref(rowIndex, cellIndex);
                if (data.validation) {
                    this._addValidation(data.validation, cellName);
                }
                return {
                    value: value,
                    formula: data.formula,
                    type: type,
                    style: style,
                    ref: cellName
                };
            },
            _addValidation: function (v, ref) {
                var tmp = {
                    showErrorMessage: v.type == 'reject' ? 1 : 0,
                    formula1: v.from,
                    formula2: v.to,
                    type: MAP_EXCEL_TYPE[v.dataType] || v.dataType,
                    operator: MAP_EXCEL_OPERATOR[v.comparerType] || v.comparerType,
                    allowBlank: v.allowNulls ? 1 : 0,
                    showDropDown: v.showButton ? 0 : 1,
                    error: v.messageTemplate,
                    errorTitle: v.titleTemplate
                };
                var json = JSON.stringify(tmp);
                if (!this._validations[json]) {
                    this._validations[json] = tmp;
                    tmp.sqref = [];
                }
                this._validations[json].sqref.push(ref);
            }
        });
        var MAP_EXCEL_OPERATOR = {
            greaterThanOrEqualTo: 'greaterThanOrEqual',
            lessThanOrEqualTo: 'lessThanOrEqual'
        };
        var MAP_EXCEL_TYPE = { number: 'decimal' };
        var defaultFormats = {
            'General': 0,
            '0': 1,
            '0.00': 2,
            '#,##0': 3,
            '#,##0.00': 4,
            '0%': 9,
            '0.00%': 10,
            '0.00E+00': 11,
            '# ?/?': 12,
            '# ??/??': 13,
            'mm-dd-yy': 14,
            'd-mmm-yy': 15,
            'd-mmm': 16,
            'mmm-yy': 17,
            'h:mm AM/PM': 18,
            'h:mm:ss AM/PM': 19,
            'h:mm': 20,
            'h:mm:ss': 21,
            'm/d/yy h:mm': 22,
            '#,##0 ;(#,##0)': 37,
            '#,##0 ;[Red](#,##0)': 38,
            '#,##0.00;(#,##0.00)': 39,
            '#,##0.00;[Red](#,##0.00)': 40,
            'mm:ss': 45,
            '[h]:mm:ss': 46,
            'mmss.0': 47,
            '##0.0E+0': 48,
            '@': 49,
            '[$-404]e/m/d': 27,
            'm/d/yy': 30,
            't0': 59,
            't0.00': 60,
            't#,##0': 61,
            't#,##0.00': 62,
            't0%': 67,
            't0.00%': 68,
            't# ?/?': 69,
            't# ??/??': 70
        };
        function convertColor(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 pushUnique(array, el) {
            if (array.indexOf(el) < 0) {
                array.push(el);
            }
        }
        function getSpan(mergedCells, ref) {
            ref = ref;
            for (var i = 0; i < mergedCells.length; ++i) {
                var range = mergedCells[i];
                var topLeft = range.substr(0, 2);
                if (topLeft == ref) {
                    var bottomRight = range.substr(3);
                    topLeft = parseRef(topLeft);
                    bottomRight = parseRef(bottomRight);
                    return {
                        rowSpan: bottomRight.row - topLeft.row + 1,
                        colSpan: bottomRight.col - topLeft.col + 1
                    };
                }
            }
        }
        function parseRef(ref) {
            function getcol(str) {
                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;
            }
            var m = /^([a-z]+)(\d+)$/i.exec(ref);
            return {
                row: getrow(m[2]),
                col: getcol(m[1])
            };
        }
        function fillCells(data, ctx) {
            var row = data._source;
            var rowIndex = data.index;
            var cells = row.cells;
            var cellData = data.cells;
            if (!cells) {
                return;
            }
            for (var i = 0; i < cells.length; i++) {
                var cell = cells[i] || EMPTY_CELL;
                var rowSpan = cell.rowSpan || 1;
                var colSpan = cell.colSpan || 1;
                var cellIndex = insertCell(cellData, cell);
                var topLeftRef = ref(rowIndex, cellIndex);
                if (rowSpan == 1 && colSpan == 1) {
                    var tmp = getSpan(ctx.mergedCells, topLeftRef);
                    if (tmp) {
                        colSpan = tmp.colSpan;
                        rowSpan = tmp.rowSpan;
                    }
                }
                spanCell(cell, cellData, cellIndex, colSpan);
                if (rowSpan > 1 || colSpan > 1) {
                    pushUnique(ctx.mergedCells, topLeftRef + ':' + ref(rowIndex + rowSpan - 1, cellIndex + colSpan - 1));
                }
                if (rowSpan > 1) {
                    for (var ri = rowIndex + 1; ri < rowIndex + rowSpan; ri++) {
                        var nextRow = ctx.rowsByIndex[ri];
                        if (!nextRow) {
                            nextRow = ctx.rowsByIndex[ri] = {
                                index: ri,
                                cells: []
                            };
                            ctx.rowData.push(nextRow);
                        }
                        spanCell(cell, nextRow.cells, cellIndex - 1, colSpan + 1);
                    }
                }
            }
        }
        function insertCell(data, cell) {
            var index;
            if (typeof cell.index === 'number') {
                index = cell.index;
                insertCellAt(data, cell, cell.index);
            } else {
                index = appendCell(data, cell);
            }
            return index;
        }
        function insertCellAt(data, cell, index) {
            data[index] = cell;
        }
        function appendCell(data, cell) {
            var index = data.length;
            for (var i = 0; i < data.length + 1; i++) {
                if (!data[i]) {
                    data[i] = cell;
                    index = i;
                    break;
                }
            }
            return index;
        }
        function spanCell(cell, row, startIndex, colSpan) {
            for (var i = 1; i < colSpan; i++) {
                var tmp = {
                    borderTop: cell.borderTop,
                    borderRight: cell.borderRight,
                    borderBottom: cell.borderBottom,
                    borderLeft: cell.borderLeft
                };
                insertCellAt(row, tmp, startIndex + i);
            }
        }
        var SPREADSHEET_FILTERS = kendo.template('<autoFilter ref="${ref}">' + '# for (var i = 0; i < columns.length; ++i) { #' + '# var col = columns[i]; #' + '<filterColumn colId="${col.index}">' + '#= generators[col.filter](col) #' + '</filterColumn>' + '# } #' + '</autoFilter>');
        var SPREADSHEET_CUSTOM_FILTER = kendo.template('<customFilters# if (logic == "and") {# and="1"# } #>' + '# for (var i = 0; i < criteria.length; ++i) { #' + '# var f = criteria[i]; #' + '# var op = kendo.ooxml.spreadsheetFilters.customOperator(f); #' + '# var val = kendo.ooxml.spreadsheetFilters.customValue(f); #' + '<customFilter# if (op) {# operator="${op}"#}# val="${val}"/>' + '# } #' + '</customFilters>');
        var SPREADSHEET_DYNAMIC_FILTER = kendo.template('<dynamicFilter type="${kendo.ooxml.spreadsheetFilters.dynamicFilterType(type)}" />');
        var SPREADSHEET_TOP_FILTER = kendo.template('<top10 percent="#= /percent$/i.test(type) ? 1 : 0 #"' + ' top="#= /^top/i.test(type) ? 1 : 0 #" ' + ' val="#: value #" />');
        var SPREADSHEET_VALUE_FILTER = kendo.template('<filters# if (blanks) {# blank="1"#}#>' + '# for (var i = 0; i < values.length; ++i) { #' + '<filter val="${values[i]}" />' + '# } #' + '</filters>');
        function spreadsheetFilters(filter) {
            return SPREADSHEET_FILTERS({
                ref: filter.ref,
                columns: filter.columns,
                generators: {
                    custom: SPREADSHEET_CUSTOM_FILTER,
                    dynamic: SPREADSHEET_DYNAMIC_FILTER,
                    top: SPREADSHEET_TOP_FILTER,
                    value: SPREADSHEET_VALUE_FILTER
                }
            });
        }
        spreadsheetFilters.customOperator = function (f) {
            return {
                eq: 'equal',
                gt: 'greaterThan',
                gte: 'greaterThanOrEqual',
                lt: 'lessThan',
                lte: 'lessThanOrEqual',
                ne: 'notEqual',
                doesnotstartwith: 'notEqual',
                doesnotendwith: 'notEqual',
                doesnotcontain: 'notEqual',
                doesnotmatch: 'notEqual'
            }[f.operator.toLowerCase()];
        };
        spreadsheetFilters.customValue = function (f) {
            function esc(str) {
                return str.replace(/([*?])/g, '~$1');
            }
            switch (f.operator.toLowerCase()) {
            case 'startswith':
            case 'doesnotstartwith':
                return esc(f.value) + '*';
            case 'endswith':
            case 'doesnotendwith':
                return '*' + esc(f.value);
            case 'contains':
            case 'doesnotcontain':
                return '*' + esc(f.value) + '*';
            }
            return f.value;
        };
        spreadsheetFilters.dynamicFilterType = function (type) {
            return {
                quarter1: 'Q1',
                quarter2: 'Q2',
                quarter3: 'Q3',
                quarter4: 'Q4',
                january: 'M1',
                february: 'M2',
                march: 'M3',
                april: 'M4',
                may: 'M5',
                june: 'M6',
                july: 'M7',
                august: 'M8',
                september: 'M9',
                october: 'M10',
                november: 'M11',
                december: 'M12'
            }[type.toLowerCase()] || type;
        };
        kendo.ooxml = {
            Workbook: Workbook,
            Worksheet: Worksheet,
            toWidth: toWidth,
            toHeight: toHeight,
            borderTemplate: borderTemplate,
            spreadsheetFilters: spreadsheetFilters
        };
    }(kendo.jQuery, kendo));
    return kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(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,
                        items: dataItem.items
                    }, 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) {
                        var groupData = {
                            group: {
                                items: dataItem.items,
                                field: dataItem.field,
                                value: dataItem.value
                            }
                        };
                        footer = true;
                        return {
                            background: '#dfdfdf',
                            color: '#333',
                            value: column.groupFooterTemplate($.extend({}, this.dataSource.aggregates(), dataItem.aggregates, dataItem.aggregates[column.field], groupData))
                        };
                    } 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)();
}));
(function (f, define) {
    define('kendo.data.signalr', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'data.signalr',
        name: 'SignalR',
        category: 'framework',
        depends: ['data'],
        hidden: true
    };
    (function ($) {
        var transport = kendo.data.RemoteTransport.extend({
            init: function (options) {
                var signalr = options && options.signalr ? options.signalr : {};
                var promise = signalr.promise;
                if (!promise) {
                    throw new Error('The "promise" option must be set.');
                }
                if (typeof promise.done != 'function' || typeof promise.fail != 'function') {
                    throw new Error('The "promise" option must be a Promise.');
                }
                this.promise = promise;
                var hub = signalr.hub;
                if (!hub) {
                    throw new Error('The "hub" option must be set.');
                }
                if (typeof hub.on != 'function' || typeof hub.invoke != 'function') {
                    throw new Error('The "hub" option is not a valid SignalR hub proxy.');
                }
                this.hub = hub;
                kendo.data.RemoteTransport.fn.init.call(this, options);
            },
            push: function (callbacks) {
                var client = this.options.signalr.client || {};
                if (client.create) {
                    this.hub.on(client.create, callbacks.pushCreate);
                }
                if (client.update) {
                    this.hub.on(client.update, callbacks.pushUpdate);
                }
                if (client.destroy) {
                    this.hub.on(client.destroy, callbacks.pushDestroy);
                }
            },
            _crud: function (options, type) {
                var hub = this.hub;
                var server = this.options.signalr.server;
                if (!server || !server[type]) {
                    throw new Error(kendo.format('The "server.{0}" option must be set.', type));
                }
                var args = [server[type]];
                var data = this.parameterMap(options.data, type);
                if (!$.isEmptyObject(data)) {
                    args.push(data);
                }
                this.promise.done(function () {
                    hub.invoke.apply(hub, args).done(options.success).fail(options.error);
                });
            },
            read: function (options) {
                this._crud(options, 'read');
            },
            create: function (options) {
                this._crud(options, 'create');
            },
            update: function (options) {
                this._crud(options, 'update');
            },
            destroy: function (options) {
                this._crud(options, 'destroy');
            }
        });
        $.extend(true, kendo.data, { transports: { signalr: transport } });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/util', ['kendo.core'], f);
}(function () {
    (function ($) {
        function createPromise() {
            return $.Deferred();
        }
        function promiseAll(promises) {
            return $.when.apply($, promises);
        }
        kendo.drawing.util = kendo.drawing.util || {};
        kendo.deepExtend(kendo.drawing.util, {
            createPromise: createPromise,
            promiseAll: promiseAll
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.color', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'color',
        name: 'Color utils',
        category: 'framework',
        advanced: true,
        description: 'Color utilities used across components',
        depends: ['core']
    };
    window.kendo = window.kendo || {};
    var Class = kendo.Class;
    var support = kendo.support;
    var namedColors = {
        aliceblue: 'f0f8ff',
        antiquewhite: 'faebd7',
        aqua: '00ffff',
        aquamarine: '7fffd4',
        azure: 'f0ffff',
        beige: 'f5f5dc',
        bisque: 'ffe4c4',
        black: '000000',
        blanchedalmond: 'ffebcd',
        blue: '0000ff',
        blueviolet: '8a2be2',
        brown: 'a52a2a',
        burlywood: 'deb887',
        cadetblue: '5f9ea0',
        chartreuse: '7fff00',
        chocolate: 'd2691e',
        coral: 'ff7f50',
        cornflowerblue: '6495ed',
        cornsilk: 'fff8dc',
        crimson: 'dc143c',
        cyan: '00ffff',
        darkblue: '00008b',
        darkcyan: '008b8b',
        darkgoldenrod: 'b8860b',
        darkgray: 'a9a9a9',
        darkgrey: 'a9a9a9',
        darkgreen: '006400',
        darkkhaki: 'bdb76b',
        darkmagenta: '8b008b',
        darkolivegreen: '556b2f',
        darkorange: 'ff8c00',
        darkorchid: '9932cc',
        darkred: '8b0000',
        darksalmon: 'e9967a',
        darkseagreen: '8fbc8f',
        darkslateblue: '483d8b',
        darkslategray: '2f4f4f',
        darkslategrey: '2f4f4f',
        darkturquoise: '00ced1',
        darkviolet: '9400d3',
        deeppink: 'ff1493',
        deepskyblue: '00bfff',
        dimgray: '696969',
        dimgrey: '696969',
        dodgerblue: '1e90ff',
        firebrick: 'b22222',
        floralwhite: 'fffaf0',
        forestgreen: '228b22',
        fuchsia: 'ff00ff',
        gainsboro: 'dcdcdc',
        ghostwhite: 'f8f8ff',
        gold: 'ffd700',
        goldenrod: 'daa520',
        gray: '808080',
        grey: '808080',
        green: '008000',
        greenyellow: 'adff2f',
        honeydew: 'f0fff0',
        hotpink: 'ff69b4',
        indianred: 'cd5c5c',
        indigo: '4b0082',
        ivory: 'fffff0',
        khaki: 'f0e68c',
        lavender: 'e6e6fa',
        lavenderblush: 'fff0f5',
        lawngreen: '7cfc00',
        lemonchiffon: 'fffacd',
        lightblue: 'add8e6',
        lightcoral: 'f08080',
        lightcyan: 'e0ffff',
        lightgoldenrodyellow: 'fafad2',
        lightgray: 'd3d3d3',
        lightgrey: 'd3d3d3',
        lightgreen: '90ee90',
        lightpink: 'ffb6c1',
        lightsalmon: 'ffa07a',
        lightseagreen: '20b2aa',
        lightskyblue: '87cefa',
        lightslategray: '778899',
        lightslategrey: '778899',
        lightsteelblue: 'b0c4de',
        lightyellow: 'ffffe0',
        lime: '00ff00',
        limegreen: '32cd32',
        linen: 'faf0e6',
        magenta: 'ff00ff',
        maroon: '800000',
        mediumaquamarine: '66cdaa',
        mediumblue: '0000cd',
        mediumorchid: 'ba55d3',
        mediumpurple: '9370d8',
        mediumseagreen: '3cb371',
        mediumslateblue: '7b68ee',
        mediumspringgreen: '00fa9a',
        mediumturquoise: '48d1cc',
        mediumvioletred: 'c71585',
        midnightblue: '191970',
        mintcream: 'f5fffa',
        mistyrose: 'ffe4e1',
        moccasin: 'ffe4b5',
        navajowhite: 'ffdead',
        navy: '000080',
        oldlace: 'fdf5e6',
        olive: '808000',
        olivedrab: '6b8e23',
        orange: 'ffa500',
        orangered: 'ff4500',
        orchid: 'da70d6',
        palegoldenrod: 'eee8aa',
        palegreen: '98fb98',
        paleturquoise: 'afeeee',
        palevioletred: 'd87093',
        papayawhip: 'ffefd5',
        peachpuff: 'ffdab9',
        peru: 'cd853f',
        pink: 'ffc0cb',
        plum: 'dda0dd',
        powderblue: 'b0e0e6',
        purple: '800080',
        red: 'ff0000',
        rosybrown: 'bc8f8f',
        royalblue: '4169e1',
        saddlebrown: '8b4513',
        salmon: 'fa8072',
        sandybrown: 'f4a460',
        seagreen: '2e8b57',
        seashell: 'fff5ee',
        sienna: 'a0522d',
        silver: 'c0c0c0',
        skyblue: '87ceeb',
        slateblue: '6a5acd',
        slategray: '708090',
        slategrey: '708090',
        snow: 'fffafa',
        springgreen: '00ff7f',
        steelblue: '4682b4',
        tan: 'd2b48c',
        teal: '008080',
        thistle: 'd8bfd8',
        tomato: 'ff6347',
        turquoise: '40e0d0',
        violet: 'ee82ee',
        wheat: 'f5deb3',
        white: 'ffffff',
        whitesmoke: 'f5f5f5',
        yellow: 'ffff00',
        yellowgreen: '9acd32'
    };
    var browser = support.browser;
    var namedColorRegexp = ['transparent'];
    for (var i in namedColors) {
        if (namedColors.hasOwnProperty(i)) {
            namedColorRegexp.push(i);
        }
    }
    namedColorRegexp = new RegExp('^(' + namedColorRegexp.join('|') + ')(\\W|$)', 'i');
    var BaseColor = Class.extend({
        init: function () {
        },
        toHSV: function () {
            return this;
        },
        toRGB: function () {
            return this;
        },
        toHex: function () {
            return this.toBytes().toHex();
        },
        toBytes: function () {
            return this;
        },
        toCss: function () {
            return '#' + this.toHex();
        },
        toCssRgba: function () {
            var rgb = this.toBytes();
            return 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + parseFloat(Number(this.a).toFixed(3)) + ')';
        },
        toDisplay: function () {
            if (browser.msie && browser.version < 9) {
                return this.toCss();
            }
            return this.toCssRgba();
        },
        equals: function (c) {
            return c === this || c !== null && this.toCssRgba() === parseColor(c).toCssRgba();
        },
        diff: function (other) {
            if (other === null) {
                return NaN;
            }
            var c1 = this.toBytes();
            var c2 = other.toBytes();
            return Math.sqrt(Math.pow((c1.r - c2.r) * 0.3, 2) + Math.pow((c1.g - c2.g) * 0.59, 2) + Math.pow((c1.b - c2.b) * 0.11, 2));
        },
        clone: function () {
            var c = this.toBytes();
            if (c === this) {
                c = new Bytes(c.r, c.g, c.b, c.a);
            }
            return c;
        }
    });
    var RGB = BaseColor.extend({
        init: function (r, g, b, a) {
            BaseColor.fn.init.call(this);
            this.r = r;
            this.g = g;
            this.b = b;
            this.a = a;
        },
        toHSV: function () {
            var ref = this;
            var r = ref.r;
            var g = ref.g;
            var b = ref.b;
            var min = Math.min(r, g, b);
            var max = Math.max(r, g, b);
            var delta = max - min;
            var v = max;
            var h, s;
            if (delta === 0) {
                return new HSV(0, 0, v, this.a);
            }
            if (max !== 0) {
                s = delta / max;
                if (r === max) {
                    h = (g - b) / delta;
                } else if (g === max) {
                    h = 2 + (b - r) / delta;
                } else {
                    h = 4 + (r - g) / delta;
                }
                h *= 60;
                if (h < 0) {
                    h += 360;
                }
            } else {
                s = 0;
                h = -1;
            }
            return new HSV(h, s, v, this.a);
        },
        toHSL: function () {
            var ref = this;
            var r = ref.r;
            var g = ref.g;
            var b = ref.b;
            var max = Math.max(r, g, b);
            var min = Math.min(r, g, b);
            var h, s, l = (max + min) / 2;
            if (max === min) {
                h = s = 0;
            } else {
                var d = max - min;
                s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                switch (max) {
                case r:
                    h = (g - b) / d + (g < b ? 6 : 0);
                    break;
                case g:
                    h = (b - r) / d + 2;
                    break;
                case b:
                    h = (r - g) / d + 4;
                    break;
                default:
                    break;
                }
                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) {
            RGB.fn.init.call(this, Math.round(r), Math.round(g), Math.round(b), a);
        },
        toRGB: function () {
            return new RGB(this.r / 255, this.g / 255, this.b / 255, this.a);
        },
        toHSV: function () {
            return this.toRGB().toHSV();
        },
        toHSL: function () {
            return this.toRGB().toHSL();
        },
        toHex: function () {
            return hex(this.r, 2) + hex(this.g, 2) + hex(this.b, 2);
        },
        toBytes: function () {
            return this;
        }
    });
    function hex(n, width, pad) {
        if (pad === void 0) {
            pad = '0';
        }
        var result = n.toString(16);
        while (width > result.length) {
            result = pad + result;
        }
        return result;
    }
    var HSV = BaseColor.extend({
        init: function (h, s, v, a) {
            BaseColor.fn.init.call(this);
            this.h = h;
            this.s = s;
            this.v = v;
            this.a = a;
        },
        toRGB: function () {
            var ref = this;
            var h = ref.h;
            var s = ref.s;
            var v = ref.v;
            var r, g, b;
            if (s === 0) {
                r = g = b = v;
            } else {
                h /= 60;
                var i = Math.floor(h);
                var f = h - i;
                var p = v * (1 - s);
                var q = v * (1 - s * f);
                var t = v * (1 - s * (1 - f));
                switch (i) {
                case 0:
                    r = v;
                    g = t;
                    b = p;
                    break;
                case 1:
                    r = q;
                    g = v;
                    b = p;
                    break;
                case 2:
                    r = p;
                    g = v;
                    b = t;
                    break;
                case 3:
                    r = p;
                    g = q;
                    b = v;
                    break;
                case 4:
                    r = t;
                    g = p;
                    b = v;
                    break;
                default:
                    r = v;
                    g = p;
                    b = q;
                    break;
                }
            }
            return new RGB(r, g, b, this.a);
        },
        toHSL: function () {
            return this.toRGB().toHSL();
        },
        toBytes: function () {
            return this.toRGB().toBytes();
        }
    });
    var HSL = BaseColor.extend({
        init: function (h, s, l, a) {
            BaseColor.fn.init.call(this);
            this.h = h;
            this.s = s;
            this.l = l;
            this.a = a;
        },
        toRGB: function () {
            var ref = this;
            var h = ref.h;
            var s = ref.s;
            var l = ref.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();
        }
    });
    function hue2rgb(p, q, s) {
        var t = s;
        if (t < 0) {
            t += 1;
        }
        if (t > 1) {
            t -= 1;
        }
        if (t < 1 / 6) {
            return p + (q - p) * 6 * t;
        }
        if (t < 1 / 2) {
            return q;
        }
        if (t < 2 / 3) {
            return p + (q - p) * (2 / 3 - t) * 6;
        }
        return p;
    }
    function parseColor(value, safe) {
        var m, ret;
        if (value == null || value === 'none') {
            return null;
        }
        if (value instanceof BaseColor) {
            return value;
        }
        var color = value.toLowerCase();
        if (m = namedColorRegexp.exec(color)) {
            if (m[1] === 'transparent') {
                color = new RGB(1, 1, 1, 0);
            } else {
                color = parseColor(namedColors[m[1]], safe);
            }
            color.match = [m[1]];
            return color;
        }
        if (m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})\b/i.exec(color)) {
            ret = new Bytes(parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16), 1);
        } else if (m = /^#?([0-9a-f])([0-9a-f])([0-9a-f])\b/i.exec(color)) {
            ret = new Bytes(parseInt(m[1] + m[1], 16), parseInt(m[2] + m[2], 16), parseInt(m[3] + m[3], 16), 1);
        } else if (m = /^rgb\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/.exec(color)) {
            ret = new Bytes(parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10), 1);
        } else if (m = /^rgba\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)/.exec(color)) {
            ret = new Bytes(parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10), parseFloat(m[4]));
        } else if (m = /^rgb\(\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9]*\.?[0-9]+)%\s*\)/.exec(color)) {
            ret = new RGB(parseFloat(m[1]) / 100, parseFloat(m[2]) / 100, parseFloat(m[3]) / 100, 1);
        } else if (m = /^rgba\(\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9]*\.?[0-9]+)%\s*,\s*([0-9.]+)\s*\)/.exec(color)) {
            ret = new RGB(parseFloat(m[1]) / 100, parseFloat(m[2]) / 100, parseFloat(m[3]) / 100, parseFloat(m[4]));
        }
        if (ret) {
            ret.match = m;
        } else if (!safe) {
            throw new Error('Cannot parse color: ' + color);
        }
        return ret;
    }
    var Color = Class.extend({
        init: function (value) {
            var this$1 = this;
            if (arguments.length === 1) {
                var formats = Color.formats;
                var resolvedColor = this.resolveColor(value);
                for (var idx = 0; idx < formats.length; idx++) {
                    var formatRegex = formats[idx].re;
                    var processor = formats[idx].process;
                    var parts = formatRegex.exec(resolvedColor);
                    if (parts) {
                        var channels = processor(parts);
                        this$1.r = channels[0];
                        this$1.g = channels[1];
                        this$1.b = channels[2];
                    }
                }
            } else {
                this.r = arguments[0];
                this.g = arguments[1];
                this.b = arguments[2];
            }
            this.r = this.normalizeByte(this.r);
            this.g = this.normalizeByte(this.g);
            this.b = this.normalizeByte(this.b);
        },
        toHex: function () {
            var pad = this.padDigit;
            var r = this.r.toString(16);
            var g = this.g.toString(16);
            var b = this.b.toString(16);
            return '#' + pad(r) + pad(g) + pad(b);
        },
        resolveColor: function (value) {
            var color = value || 'black';
            if (color.charAt(0) === '#') {
                color = color.substr(1, 6);
            }
            color = color.replace(/ /g, '');
            color = color.toLowerCase();
            color = Color.namedColors[color] || color;
            return color;
        },
        normalizeByte: function (value) {
            if (value < 0 || isNaN(value)) {
                return 0;
            }
            return value > 255 ? 255 : value;
        },
        padDigit: function (value) {
            return value.length === 1 ? '0' + value : value;
        },
        brightness: function (value) {
            var round = Math.round;
            this.r = round(this.normalizeByte(this.r * value));
            this.g = round(this.normalizeByte(this.g * value));
            this.b = round(this.normalizeByte(this.b * value));
            return this;
        },
        percBrightness: function () {
            return Math.sqrt(0.241 * this.r * this.r + 0.691 * this.g * this.g + 0.068 * this.b * this.b);
        }
    });
    Color.fromBytes = function (r, g, b, a) {
        return new Bytes(r, g, b, a != null ? a : 1);
    };
    Color.fromRGB = function (r, g, b, a) {
        return new RGB(r, g, b, a != null ? a : 1);
    };
    Color.fromHSV = function (h, s, v, a) {
        return new HSV(h, s, v, a != null ? a : 1);
    };
    Color.fromHSL = function (h, s, l, a) {
        return new HSL(h, s, l, a != null ? a : 1);
    };
    Color.formats = [
        {
            re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
            process: function (parts) {
                return [
                    parseInt(parts[1], 10),
                    parseInt(parts[2], 10),
                    parseInt(parts[3], 10)
                ];
            }
        },
        {
            re: /^(\w{2})(\w{2})(\w{2})$/,
            process: function (parts) {
                return [
                    parseInt(parts[1], 16),
                    parseInt(parts[2], 16),
                    parseInt(parts[3], 16)
                ];
            }
        },
        {
            re: /^(\w{1})(\w{1})(\w{1})$/,
            process: function (parts) {
                return [
                    parseInt(parts[1] + parts[1], 16),
                    parseInt(parts[2] + parts[2], 16),
                    parseInt(parts[3] + parts[3], 16)
                ];
            }
        }
    ];
    Color.namedColors = namedColors;
    kendo.deepExtend(kendo, {
        parseColor: parseColor,
        Color: Color
    });
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/text-metrics', ['kendo.core'], f);
}(function () {
    (function ($) {
        window.kendo.util = window.kendo.util || {};
        var LRUCache = kendo.Class.extend({
            init: function (size) {
                this._size = size;
                this._length = 0;
                this._map = {};
            },
            put: function (key, value) {
                var map = this._map;
                var entry = {
                    key: key,
                    value: value
                };
                map[key] = entry;
                if (!this._head) {
                    this._head = this._tail = entry;
                } else {
                    this._tail.newer = entry;
                    entry.older = this._tail;
                    this._tail = entry;
                }
                if (this._length >= this._size) {
                    map[this._head.key] = null;
                    this._head = this._head.newer;
                    this._head.older = null;
                } else {
                    this._length++;
                }
            },
            get: function (key) {
                var entry = this._map[key];
                if (entry) {
                    if (entry === this._head && entry !== this._tail) {
                        this._head = entry.newer;
                        this._head.older = null;
                    }
                    if (entry !== this._tail) {
                        if (entry.older) {
                            entry.older.newer = entry.newer;
                            entry.newer.older = entry.older;
                        }
                        entry.older = this._tail;
                        entry.newer = null;
                        this._tail.newer = entry;
                        this._tail = entry;
                    }
                    return entry.value;
                }
            }
        });
        function objectKey(object) {
            var parts = [];
            for (var key in object) {
                parts.push(key + object[key]);
            }
            return parts.sort().join('');
        }
        function hashKey(str) {
            var hash = 2166136261;
            for (var i = 0; i < str.length; ++i) {
                hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
                hash ^= str.charCodeAt(i);
            }
            return hash >>> 0;
        }
        function zeroSize() {
            return {
                width: 0,
                height: 0,
                baseline: 0
            };
        }
        var DEFAULT_OPTIONS = { baselineMarkerSize: 1 };
        var defaultMeasureBox;
        if (typeof document !== 'undefined') {
            defaultMeasureBox = document.createElement('div');
            defaultMeasureBox.style.cssText = 'position: absolute !important; top: -4000px !important; width: auto !important; height: auto !important;' + 'padding: 0 !important; margin: 0 !important; border: 0 !important;' + 'line-height: normal !important; visibility: hidden !important; white-space: nowrap!important;';
        }
        var TextMetrics = kendo.Class.extend({
            init: function (options) {
                this._cache = new LRUCache(1000);
                this.options = $.extend({}, DEFAULT_OPTIONS, options);
            },
            measure: function (text, style, box) {
                if (!text) {
                    return zeroSize();
                }
                var styleKey = objectKey(style);
                var cacheKey = hashKey(text + styleKey);
                var cachedResult = this._cache.get(cacheKey);
                if (cachedResult) {
                    return cachedResult;
                }
                var size = zeroSize();
                var measureBox = box || defaultMeasureBox;
                var baselineMarker = this._baselineMarker().cloneNode(false);
                for (var key in style) {
                    var value = style[key];
                    if (typeof value !== 'undefined') {
                        measureBox.style[key] = value;
                    }
                }
                measureBox.textContent = text;
                measureBox.appendChild(baselineMarker);
                document.body.appendChild(measureBox);
                if (String(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 () {
                var marker = document.createElement('div');
                marker.style.cssText = 'display: inline-block; vertical-align: baseline;width: ' + this.options.baselineMarkerSize + 'px; height: ' + this.options.baselineMarkerSize + 'px;overflow: hidden;';
                return marker;
            }
        });
        TextMetrics.current = new TextMetrics();
        function measureText(text, style, measureBox) {
            return TextMetrics.current.measure(text, style, measureBox);
        }
        kendo.deepExtend(kendo.util, {
            LRUCache: LRUCache,
            TextMetrics: TextMetrics,
            measureText: measureText,
            objectKey: objectKey,
            hashKey: hashKey
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/kendo-drawing', [
        'drawing/util',
        'kendo.color',
        'util/text-metrics'
    ], f);
}(function () {
    (function ($) {
        window.kendo = window.kendo || {};
        var kendoDrawing = kendo.drawing;
        var kendoDrawingUtil = kendoDrawing.util;
        var Class = kendo.Class;
        var kendoUtil = kendo.util;
        var support = kendo.support;
        var createPromise = kendoDrawingUtil.createPromise;
        var promiseAll = kendoDrawingUtil.promiseAll;
        var ObserversMixin = {
            extend: function (proto) {
                var this$1 = this;
                for (var method in this) {
                    if (method !== 'extend') {
                        proto[method] = this$1[method];
                    }
                }
            },
            observers: function () {
                this._observers = this._observers || [];
                return this._observers;
            },
            addObserver: function (element) {
                if (!this._observers) {
                    this._observers = [element];
                } else {
                    this._observers.push(element);
                }
                return this;
            },
            removeObserver: function (element) {
                var observers = this.observers();
                var index = observers.indexOf(element);
                if (index !== -1) {
                    observers.splice(index, 1);
                }
                return this;
            },
            trigger: function (methodName, event) {
                var observers = this._observers;
                if (observers && !this._suspended) {
                    for (var idx = 0; idx < observers.length; idx++) {
                        var observer = observers[idx];
                        if (observer[methodName]) {
                            observer[methodName](event);
                        }
                    }
                }
                return this;
            },
            optionsChange: function (e) {
                if (e === void 0) {
                    e = {};
                }
                e.element = this;
                this.trigger('optionsChange', e);
            },
            geometryChange: function () {
                this.trigger('geometryChange', { element: this });
            },
            suspend: function () {
                this._suspended = (this._suspended || 0) + 1;
                return this;
            },
            resume: function () {
                this._suspended = Math.max((this._suspended || 0) - 1, 0);
                return this;
            },
            _observerField: function (field, value) {
                if (this[field]) {
                    this[field].removeObserver(this);
                }
                this[field] = value;
                value.addObserver(this);
            }
        };
        function append(first, second) {
            first.push.apply(first, second);
            return first;
        }
        var literals = {
            1: 'i',
            10: 'x',
            100: 'c',
            2: 'ii',
            20: 'xx',
            200: 'cc',
            3: 'iii',
            30: 'xxx',
            300: 'ccc',
            4: 'iv',
            40: 'xl',
            400: 'cd',
            5: 'v',
            50: 'l',
            500: 'd',
            6: 'vi',
            60: 'lx',
            600: 'dc',
            7: 'vii',
            70: 'lxx',
            700: 'dcc',
            8: 'viii',
            80: 'lxxx',
            800: 'dccc',
            9: 'ix',
            90: 'xc',
            900: 'cm',
            1000: 'm'
        };
        function arabicToRoman(n) {
            var values = [
                1000,
                900,
                800,
                700,
                600,
                500,
                400,
                300,
                200,
                100,
                90,
                80,
                70,
                60,
                50,
                40,
                30,
                20,
                10,
                9,
                8,
                7,
                6,
                5,
                4,
                3,
                2,
                1
            ];
            var roman = '';
            while (n > 0) {
                if (n < values[0]) {
                    values.shift();
                } else {
                    roman += literals[values[0]];
                    n -= values[0];
                }
            }
            return roman;
        }
        var UNDEFINED = 'undefined';
        function defined(value) {
            return typeof value !== UNDEFINED;
        }
        var defId = 1;
        function definitionId() {
            return 'kdef' + defId++;
        }
        var DEG_TO_RAD = Math.PI / 180;
        var MAX_NUM = Number.MAX_VALUE;
        var MIN_NUM = -Number.MAX_VALUE;
        function deg(radians) {
            return radians / DEG_TO_RAD;
        }
        var KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        var fromCharCode = String.fromCharCode;
        function encodeUTF8(input) {
            var output = '';
            for (var i = 0; i < input.length; i++) {
                var c = input.charCodeAt(i);
                if (c < 128) {
                    output += fromCharCode(c);
                } else if (c < 2048) {
                    output += fromCharCode(192 | c >>> 6);
                    output += fromCharCode(128 | c & 63);
                } else if (c < 65536) {
                    output += fromCharCode(224 | c >>> 12);
                    output += fromCharCode(128 | c >>> 6 & 63);
                    output += fromCharCode(128 | c & 63);
                }
            }
            return output;
        }
        function encodeBase64(input) {
            var output = '';
            var i = 0;
            var utfInput = encodeUTF8(input);
            while (i < utfInput.length) {
                var chr1 = utfInput.charCodeAt(i++);
                var chr2 = utfInput.charCodeAt(i++);
                var chr3 = utfInput.charCodeAt(i++);
                var enc1 = chr1 >> 2;
                var enc2 = (chr1 & 3) << 4 | chr2 >> 4;
                var enc3 = (chr2 & 15) << 2 | chr3 >> 6;
                var enc4 = chr3 & 63;
                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output = output + KEY_STR.charAt(enc1) + KEY_STR.charAt(enc2) + KEY_STR.charAt(enc3) + KEY_STR.charAt(enc4);
            }
            return output;
        }
        function eventCoordinates(e) {
            if (defined((e.x || {}).location)) {
                return {
                    x: e.x.location,
                    y: e.y.location
                };
            }
            return {
                x: e.pageX || e.clientX || 0,
                y: e.pageY || e.clientY || 0
            };
        }
        function eventElement(e) {
            if (e === void 0) {
                e = {};
            }
            return e.touch ? e.touch.initialTouch : e.target;
        }
        function isTransparent(color) {
            return color === '' || color === null || color === 'none' || color === 'transparent' || !defined(color);
        }
        function last(array) {
            if (array) {
                return array[array.length - 1];
            }
        }
        function limitValue(value, min, max) {
            return Math.max(Math.min(value, max), min);
        }
        function mergeSort(a, cmp) {
            if (a.length < 2) {
                return a.slice();
            }
            function merge(a, b) {
                var r = [], ai = 0, bi = 0, i = 0;
                while (ai < a.length && bi < b.length) {
                    if (cmp(a[ai], b[bi]) <= 0) {
                        r[i++] = a[ai++];
                    } else {
                        r[i++] = b[bi++];
                    }
                }
                if (ai < a.length) {
                    r.push.apply(r, a.slice(ai));
                }
                if (bi < b.length) {
                    r.push.apply(r, b.slice(bi));
                }
                return r;
            }
            return function sort(a) {
                if (a.length <= 1) {
                    return a;
                }
                var m = Math.floor(a.length / 2);
                var left = a.slice(0, m);
                var right = a.slice(m);
                left = sort(left);
                right = sort(right);
                return merge(left, right);
            }(a);
        }
        function rad(degrees) {
            return degrees * DEG_TO_RAD;
        }
        function pow(p) {
            if (p) {
                return Math.pow(10, p);
            }
            return 1;
        }
        function round(value, precision) {
            var power = pow(precision);
            return Math.round(value * power) / power;
        }
        function valueOrDefault(value, defaultValue) {
            return defined(value) ? value : defaultValue;
        }
        function bindEvents(element, events) {
            for (var eventName in events) {
                var eventNames = eventName.trim().split(' ');
                for (var idx = 0; idx < eventNames.length; idx++) {
                    element.addEventListener(eventNames[idx], events[eventName], false);
                }
            }
        }
        function elementOffset(element) {
            var box = element.getBoundingClientRect();
            var documentElement = document.documentElement;
            return {
                top: box.top + (window.pageYOffset || documentElement.scrollTop) - (documentElement.clientTop || 0),
                left: box.left + (window.pageXOffset || documentElement.scrollLeft) - (documentElement.clientLeft || 0)
            };
        }
        function elementStyles(element, styles) {
            var result = {};
            var style = window.getComputedStyle(element);
            var stylesArray = Array.isArray(styles) ? styles : [styles];
            for (var idx = 0; idx < stylesArray.length; idx++) {
                var field = stylesArray[idx];
                result[field] = style[field];
            }
            return result;
        }
        function getPixels(value) {
            if (isNaN(value)) {
                return value;
            }
            return value + 'px';
        }
        function elementSize(element, size) {
            if (size) {
                var width = size.width;
                var height = size.height;
                if (defined(width)) {
                    element.style.width = getPixels(width);
                }
                if (defined(height)) {
                    element.style.height = getPixels(height);
                }
            } else {
                var size$1 = elementStyles(element, [
                    'width',
                    'height'
                ]);
                return {
                    width: parseInt(size$1.width, 10),
                    height: parseInt(size$1.height, 10)
                };
            }
        }
        function unbindEvents(element, events) {
            if (events === void 0) {
                events = {};
            }
            for (var name in events) {
                var eventNames = name.trim().split(' ');
                for (var idx = 0; idx < eventNames.length; idx++) {
                    element.removeEventListener(eventNames[idx], events[name], false);
                }
            }
        }
        var util = {
            append: append,
            arabicToRoman: arabicToRoman,
            createPromise: createPromise,
            defined: defined,
            definitionId: definitionId,
            deg: deg,
            encodeBase64: encodeBase64,
            eventCoordinates: eventCoordinates,
            eventElement: eventElement,
            isTransparent: isTransparent,
            last: last,
            limitValue: limitValue,
            mergeSort: mergeSort,
            promiseAll: promiseAll,
            rad: rad,
            round: round,
            valueOrDefault: valueOrDefault,
            bindEvents: bindEvents,
            elementOffset: elementOffset,
            elementSize: elementSize,
            elementStyles: elementStyles,
            unbindEvents: unbindEvents,
            DEG_TO_RAD: DEG_TO_RAD,
            MAX_NUM: MAX_NUM,
            MIN_NUM: MIN_NUM
        };
        var toString = {}.toString;
        var OptionsStore = Class.extend({
            init: function (options, prefix) {
                var this$1 = this;
                if (prefix === void 0) {
                    prefix = '';
                }
                this.prefix = prefix;
                for (var field in options) {
                    var member = options[field];
                    member = this$1._wrap(member, field);
                    this$1[field] = member;
                }
            },
            get: function (field) {
                var parts = field.split('.');
                var result = this;
                while (parts.length && result) {
                    var part = parts.shift();
                    result = result[part];
                }
                return result;
            },
            set: function (field, value) {
                var current = this.get(field);
                if (current !== value) {
                    this._set(field, this._wrap(value, field));
                    this.optionsChange({
                        field: this.prefix + field,
                        value: value
                    });
                }
            },
            _set: function (field, value) {
                var this$1 = this;
                var composite = field.indexOf('.') >= 0;
                var parentObj = this;
                var fieldName = field;
                if (composite) {
                    var parts = fieldName.split('.');
                    var prefix = this.prefix;
                    while (parts.length > 1) {
                        fieldName = parts.shift();
                        prefix += fieldName + '.';
                        var obj = parentObj[fieldName];
                        if (!obj) {
                            obj = new OptionsStore({}, prefix);
                            obj.addObserver(this$1);
                            parentObj[fieldName] = obj;
                        }
                        parentObj = obj;
                    }
                    fieldName = parts[0];
                }
                parentObj._clear(fieldName);
                parentObj[fieldName] = value;
            },
            _clear: function (field) {
                var current = this[field];
                if (current && current.removeObserver) {
                    current.removeObserver(this);
                }
            },
            _wrap: function (object, field) {
                var type = toString.call(object);
                var wrapped = object;
                if (wrapped !== null && defined(wrapped) && type === '[object Object]') {
                    if (!(object instanceof OptionsStore) && !(object instanceof Class)) {
                        wrapped = new OptionsStore(wrapped, this.prefix + field + '.');
                    }
                    wrapped.addObserver(this);
                }
                return wrapped;
            }
        });
        ObserversMixin.extend(OptionsStore.prototype);
        function setAccessor(field) {
            return function (value) {
                if (this[field] !== value) {
                    this[field] = value;
                    this.geometryChange();
                }
                return this;
            };
        }
        function getAccessor(field) {
            return function () {
                return this[field];
            };
        }
        function defineAccessors(fn, fields) {
            for (var i = 0; i < fields.length; i++) {
                var name = fields[i];
                var capitalized = name.charAt(0).toUpperCase() + name.substring(1, name.length);
                fn['set' + capitalized] = setAccessor(name);
                fn['get' + capitalized] = getAccessor(name);
            }
        }
        var Matrix = Class.extend({
            init: function (a, b, c, d, e, f) {
                if (a === void 0) {
                    a = 0;
                }
                if (b === void 0) {
                    b = 0;
                }
                if (c === void 0) {
                    c = 0;
                }
                if (d === void 0) {
                    d = 0;
                }
                if (e === void 0) {
                    e = 0;
                }
                if (f === void 0) {
                    f = 0;
                }
                this.a = a;
                this.b = b;
                this.c = c;
                this.d = d;
                this.e = e;
                this.f = f;
            },
            multiplyCopy: function (matrix) {
                return new Matrix(this.a * matrix.a + this.c * matrix.b, this.b * matrix.a + this.d * matrix.b, this.a * matrix.c + this.c * matrix.d, this.b * matrix.c + this.d * matrix.d, this.a * matrix.e + this.c * matrix.f + this.e, this.b * matrix.e + this.d * matrix.f + this.f);
            },
            invert: function () {
                var ref = this;
                var a = ref.a;
                var b = ref.b;
                var d = ref.c;
                var e = ref.d;
                var g = ref.e;
                var h = ref.f;
                var det = a * e - b * d;
                if (det === 0) {
                    return null;
                }
                return new Matrix(e / det, -b / det, -d / det, a / det, (d * h - e * g) / det, (b * g - a * h) / det);
            },
            clone: function () {
                return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
            },
            equals: function (other) {
                if (!other) {
                    return false;
                }
                return this.a === other.a && this.b === other.b && this.c === other.c && this.d === other.d && this.e === other.e && this.f === other.f;
            },
            round: function (precision) {
                this.a = round(this.a, precision);
                this.b = round(this.b, precision);
                this.c = round(this.c, precision);
                this.d = round(this.d, precision);
                this.e = round(this.e, precision);
                this.f = round(this.f, precision);
                return this;
            },
            toArray: function (precision) {
                var result = [
                    this.a,
                    this.b,
                    this.c,
                    this.d,
                    this.e,
                    this.f
                ];
                if (defined(precision)) {
                    for (var i = 0; i < result.length; i++) {
                        result[i] = round(result[i], precision);
                    }
                }
                return result;
            },
            toString: function (precision, separator) {
                if (separator === void 0) {
                    separator = ',';
                }
                return this.toArray(precision).join(separator);
            }
        });
        Matrix.translate = function (x, y) {
            return new Matrix(1, 0, 0, 1, x, y);
        };
        Matrix.unit = function () {
            return new Matrix(1, 0, 0, 1, 0, 0);
        };
        Matrix.rotate = function (angle, x, y) {
            var matrix = new Matrix();
            matrix.a = Math.cos(rad(angle));
            matrix.b = Math.sin(rad(angle));
            matrix.c = -matrix.b;
            matrix.d = matrix.a;
            matrix.e = x - x * matrix.a + y * matrix.b || 0;
            matrix.f = y - y * matrix.a - x * matrix.b || 0;
            return matrix;
        };
        Matrix.scale = function (scaleX, scaleY) {
            return new Matrix(scaleX, 0, 0, scaleY, 0, 0);
        };
        Matrix.IDENTITY = Matrix.unit();
        function toMatrix(transformation) {
            if (transformation && typeof transformation.matrix === 'function') {
                return transformation.matrix();
            }
            return transformation;
        }
        var Point = Class.extend({
            init: function (x, y) {
                this.x = x || 0;
                this.y = y || 0;
            },
            equals: function (other) {
                return other && other.x === this.x && other.y === this.y;
            },
            clone: function () {
                return new Point(this.x, this.y);
            },
            rotate: function (angle, origin) {
                var originPoint = Point.create(origin) || Point.ZERO;
                return this.transform(Matrix.rotate(angle, originPoint.x, originPoint.y));
            },
            translate: function (x, y) {
                this.x += x;
                this.y += y;
                this.geometryChange();
                return this;
            },
            translateWith: function (point) {
                return this.translate(point.x, point.y);
            },
            move: function (x, y) {
                this.x = this.y = 0;
                return this.translate(x, y);
            },
            scale: function (scaleX, scaleY) {
                if (scaleY === void 0) {
                    scaleY = scaleX;
                }
                this.x *= scaleX;
                this.y *= scaleY;
                this.geometryChange();
                return this;
            },
            scaleCopy: function (scaleX, scaleY) {
                return this.clone().scale(scaleX, scaleY);
            },
            transform: function (transformation) {
                var matrix = toMatrix(transformation);
                var ref = this;
                var x = ref.x;
                var y = ref.y;
                this.x = matrix.a * x + matrix.c * y + matrix.e;
                this.y = matrix.b * x + matrix.d * y + matrix.f;
                this.geometryChange();
                return this;
            },
            transformCopy: function (transformation) {
                var point = this.clone();
                if (transformation) {
                    point.transform(transformation);
                }
                return point;
            },
            distanceTo: function (point) {
                var dx = this.x - point.x;
                var dy = this.y - point.y;
                return Math.sqrt(dx * dx + dy * dy);
            },
            round: function (digits) {
                this.x = round(this.x, digits);
                this.y = round(this.y, digits);
                this.geometryChange();
                return this;
            },
            toArray: function (digits) {
                var doRound = defined(digits);
                var x = doRound ? round(this.x, digits) : this.x;
                var y = doRound ? round(this.y, digits) : this.y;
                return [
                    x,
                    y
                ];
            },
            toString: function (digits, separator) {
                if (separator === void 0) {
                    separator = ' ';
                }
                var ref = this;
                var x = ref.x;
                var y = ref.y;
                if (defined(digits)) {
                    x = round(x, digits);
                    y = round(y, digits);
                }
                return x + separator + y;
            }
        });
        Point.create = function (arg0, arg1) {
            if (defined(arg0)) {
                if (arg0 instanceof Point) {
                    return arg0;
                } else if (arguments.length === 1 && arg0.length === 2) {
                    return new Point(arg0[0], arg0[1]);
                }
                return new Point(arg0, arg1);
            }
        };
        Point.min = function () {
            var arguments$1 = arguments;
            var minX = MAX_NUM;
            var minY = MAX_NUM;
            for (var i = 0; i < arguments.length; i++) {
                var point = arguments$1[i];
                minX = Math.min(point.x, minX);
                minY = Math.min(point.y, minY);
            }
            return new Point(minX, minY);
        };
        Point.max = function () {
            var arguments$1 = arguments;
            var maxX = MIN_NUM;
            var maxY = MIN_NUM;
            for (var i = 0; i < arguments.length; i++) {
                var point = arguments$1[i];
                maxX = Math.max(point.x, maxX);
                maxY = Math.max(point.y, maxY);
            }
            return new Point(maxX, maxY);
        };
        Point.minPoint = function () {
            return new Point(MIN_NUM, MIN_NUM);
        };
        Point.maxPoint = function () {
            return new Point(MAX_NUM, MAX_NUM);
        };
        if (Object.defineProperties) {
            Object.defineProperties(Point, {
                ZERO: {
                    get: function () {
                        return new Point(0, 0);
                    }
                }
            });
        }
        defineAccessors(Point.prototype, [
            'x',
            'y'
        ]);
        ObserversMixin.extend(Point.prototype);
        var Size = Class.extend({
            init: function (width, height) {
                this.width = width || 0;
                this.height = height || 0;
            },
            equals: function (other) {
                return other && other.width === this.width && other.height === this.height;
            },
            clone: function () {
                return new Size(this.width, this.height);
            },
            toArray: function (digits) {
                var doRound = defined(digits);
                var width = doRound ? round(this.width, digits) : this.width;
                var height = doRound ? round(this.height, digits) : this.height;
                return [
                    width,
                    height
                ];
            }
        });
        Size.create = function (arg0, arg1) {
            if (defined(arg0)) {
                if (arg0 instanceof Size) {
                    return arg0;
                } else if (arguments.length === 1 && arg0.length === 2) {
                    return new Size(arg0[0], arg0[1]);
                }
                return new Size(arg0, arg1);
            }
        };
        if (Object.defineProperties) {
            Object.defineProperties(Size, {
                ZERO: {
                    get: function () {
                        return new Size(0, 0);
                    }
                }
            });
        }
        defineAccessors(Size.prototype, [
            'width',
            'height'
        ]);
        ObserversMixin.extend(Size.prototype);
        var Rect = Class.extend({
            init: function (origin, size) {
                if (origin === void 0) {
                    origin = new Point();
                }
                if (size === void 0) {
                    size = new Size();
                }
                this.setOrigin(origin);
                this.setSize(size);
            },
            clone: function () {
                return new Rect(this.origin.clone(), this.size.clone());
            },
            equals: function (other) {
                return other && other.origin.equals(this.origin) && other.size.equals(this.size);
            },
            setOrigin: function (value) {
                this._observerField('origin', Point.create(value));
                this.geometryChange();
                return this;
            },
            getOrigin: function () {
                return this.origin;
            },
            setSize: function (value) {
                this._observerField('size', Size.create(value));
                this.geometryChange();
                return this;
            },
            getSize: function () {
                return this.size;
            },
            width: function () {
                return this.size.width;
            },
            height: function () {
                return this.size.height;
            },
            topLeft: function () {
                return this.origin.clone();
            },
            bottomRight: function () {
                return this.origin.clone().translate(this.width(), this.height());
            },
            topRight: function () {
                return this.origin.clone().translate(this.width(), 0);
            },
            bottomLeft: function () {
                return this.origin.clone().translate(0, this.height());
            },
            center: function () {
                return this.origin.clone().translate(this.width() / 2, this.height() / 2);
            },
            bbox: function (matrix) {
                var tl = this.topLeft().transformCopy(matrix);
                var tr = this.topRight().transformCopy(matrix);
                var br = this.bottomRight().transformCopy(matrix);
                var bl = this.bottomLeft().transformCopy(matrix);
                return Rect.fromPoints(tl, tr, br, bl);
            },
            transformCopy: function (m) {
                return Rect.fromPoints(this.topLeft().transform(m), this.bottomRight().transform(m));
            },
            expand: function (x, y) {
                if (y === void 0) {
                    y = x;
                }
                this.size.width += 2 * x;
                this.size.height += 2 * y;
                this.origin.translate(-x, -y);
                return this;
            },
            expandCopy: function (x, y) {
                return this.clone().expand(x, y);
            },
            containsPoint: function (point) {
                var origin = this.origin;
                var bottomRight = this.bottomRight();
                return !(point.x < origin.x || point.y < origin.y || bottomRight.x < point.x || bottomRight.y < point.y);
            },
            _isOnPath: function (point, width) {
                var rectOuter = this.expandCopy(width, width);
                var rectInner = this.expandCopy(-width, -width);
                return rectOuter.containsPoint(point) && !rectInner.containsPoint(point);
            }
        });
        Rect.fromPoints = function () {
            var topLeft = Point.min.apply(null, arguments);
            var bottomRight = Point.max.apply(null, arguments);
            var size = new Size(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
            return new Rect(topLeft, size);
        };
        Rect.union = function (a, b) {
            return Rect.fromPoints(Point.min(a.topLeft(), b.topLeft()), Point.max(a.bottomRight(), b.bottomRight()));
        };
        Rect.intersect = function (a, b) {
            var rect1 = {
                left: a.topLeft().x,
                top: a.topLeft().y,
                right: a.bottomRight().x,
                bottom: a.bottomRight().y
            };
            var rect2 = {
                left: b.topLeft().x,
                top: b.topLeft().y,
                right: b.bottomRight().x,
                bottom: b.bottomRight().y
            };
            if (rect1.left <= rect2.right && rect2.left <= rect1.right && rect1.top <= rect2.bottom && rect2.top <= rect1.bottom) {
                return Rect.fromPoints(new Point(Math.max(rect1.left, rect2.left), Math.max(rect1.top, rect2.top)), new Point(Math.min(rect1.right, rect2.right), Math.min(rect1.bottom, rect2.bottom)));
            }
        };
        ObserversMixin.extend(Rect.prototype);
        var Transformation = Class.extend({
            init: function (matrix) {
                if (matrix === void 0) {
                    matrix = Matrix.unit();
                }
                this._matrix = matrix;
            },
            clone: function () {
                return new Transformation(this._matrix.clone());
            },
            equals: function (other) {
                return other && other._matrix.equals(this._matrix);
            },
            translate: function (x, y) {
                this._matrix = this._matrix.multiplyCopy(Matrix.translate(x, y));
                this._optionsChange();
                return this;
            },
            scale: function (scaleX, scaleY, origin) {
                if (scaleY === void 0) {
                    scaleY = scaleX;
                }
                if (origin === void 0) {
                    origin = null;
                }
                var originPoint = origin;
                if (originPoint) {
                    originPoint = Point.create(originPoint);
                    this._matrix = this._matrix.multiplyCopy(Matrix.translate(originPoint.x, originPoint.y));
                }
                this._matrix = this._matrix.multiplyCopy(Matrix.scale(scaleX, scaleY));
                if (originPoint) {
                    this._matrix = this._matrix.multiplyCopy(Matrix.translate(-originPoint.x, -originPoint.y));
                }
                this._optionsChange();
                return this;
            },
            rotate: function (angle, origin) {
                var originPoint = Point.create(origin) || Point.ZERO;
                this._matrix = this._matrix.multiplyCopy(Matrix.rotate(angle, originPoint.x, originPoint.y));
                this._optionsChange();
                return this;
            },
            multiply: function (transformation) {
                var matrix = toMatrix(transformation);
                this._matrix = this._matrix.multiplyCopy(matrix);
                this._optionsChange();
                return this;
            },
            matrix: function (value) {
                if (value) {
                    this._matrix = value;
                    this._optionsChange();
                    return this;
                }
                return this._matrix;
            },
            _optionsChange: function () {
                this.optionsChange({
                    field: 'transform',
                    value: this
                });
            }
        });
        ObserversMixin.extend(Transformation.prototype);
        function transform(matrix) {
            if (matrix === null) {
                return null;
            }
            if (matrix instanceof Transformation) {
                return matrix;
            }
            return new Transformation(matrix);
        }
        var Element$1 = Class.extend({
            init: function (options) {
                this._initOptions(options);
            },
            _initOptions: function (options) {
                if (options === void 0) {
                    options = {};
                }
                var clip = options.clip;
                var transform$$1 = options.transform;
                if (transform$$1) {
                    options.transform = transform(transform$$1);
                }
                if (clip && !clip.id) {
                    clip.id = definitionId();
                }
                this.options = new OptionsStore(options);
                this.options.addObserver(this);
            },
            transform: function (value) {
                if (defined(value)) {
                    this.options.set('transform', transform(value));
                } else {
                    return this.options.get('transform');
                }
            },
            parentTransform: function () {
                var element = this;
                var parentMatrix;
                while (element.parent) {
                    element = element.parent;
                    var transformation = element.transform();
                    if (transformation) {
                        parentMatrix = transformation.matrix().multiplyCopy(parentMatrix || Matrix.unit());
                    }
                }
                if (parentMatrix) {
                    return transform(parentMatrix);
                }
            },
            currentTransform: function (parentTransform) {
                if (parentTransform === void 0) {
                    parentTransform = this.parentTransform();
                }
                var elementTransform = this.transform();
                var elementMatrix = toMatrix(elementTransform);
                var parentMatrix = toMatrix(parentTransform);
                var combinedMatrix;
                if (elementMatrix && parentMatrix) {
                    combinedMatrix = parentMatrix.multiplyCopy(elementMatrix);
                } else {
                    combinedMatrix = elementMatrix || parentMatrix;
                }
                if (combinedMatrix) {
                    return transform(combinedMatrix);
                }
            },
            visible: function (value) {
                if (defined(value)) {
                    this.options.set('visible', value);
                    return this;
                }
                return this.options.get('visible') !== false;
            },
            clip: function (value) {
                var options = this.options;
                if (defined(value)) {
                    if (value && !value.id) {
                        value.id = definitionId();
                    }
                    options.set('clip', value);
                    return this;
                }
                return options.get('clip');
            },
            opacity: function (value) {
                if (defined(value)) {
                    this.options.set('opacity', value);
                    return this;
                }
                return valueOrDefault(this.options.get('opacity'), 1);
            },
            clippedBBox: function (transformation) {
                var bbox = this._clippedBBox(transformation);
                if (bbox) {
                    var clip = this.clip();
                    return clip ? Rect.intersect(bbox, clip.bbox(transformation)) : bbox;
                }
            },
            containsPoint: function (point, parentTransform) {
                if (this.visible()) {
                    var transform$$1 = this.currentTransform(parentTransform);
                    var transformedPoint = point;
                    if (transform$$1) {
                        transformedPoint = point.transformCopy(transform$$1.matrix().invert());
                    }
                    return this._hasFill() && this._containsPoint(transformedPoint) || this._isOnPath && this._hasStroke() && this._isOnPath(transformedPoint);
                }
                return false;
            },
            _hasFill: function () {
                var fill = this.options.fill;
                return fill && !isTransparent(fill.color);
            },
            _hasStroke: function () {
                var stroke = this.options.stroke;
                return stroke && stroke.width > 0 && !isTransparent(stroke.color);
            },
            _clippedBBox: function (transformation) {
                return this.bbox(transformation);
            }
        });
        Element$1.prototype.nodeType = 'Element';
        ObserversMixin.extend(Element$1.prototype);
        function ellipseExtremeAngles(center, rx, ry, matrix) {
            var extremeX = 0;
            var extremeY = 0;
            if (matrix) {
                extremeX = Math.atan2(matrix.c * ry, matrix.a * rx);
                if (matrix.b !== 0) {
                    extremeY = Math.atan2(matrix.d * ry, matrix.b * rx);
                }
            }
            return {
                x: extremeX,
                y: extremeY
            };
        }
        var PI_DIV_2 = Math.PI / 2;
        var Circle$2 = Class.extend({
            init: function (center, radius) {
                if (center === void 0) {
                    center = new Point();
                }
                if (radius === void 0) {
                    radius = 0;
                }
                this.setCenter(center);
                this.setRadius(radius);
            },
            setCenter: function (value) {
                this._observerField('center', Point.create(value));
                this.geometryChange();
                return this;
            },
            getCenter: function () {
                return this.center;
            },
            equals: function (other) {
                return other && other.center.equals(this.center) && other.radius === this.radius;
            },
            clone: function () {
                return new Circle$2(this.center.clone(), this.radius);
            },
            pointAt: function (angle) {
                return this._pointAt(rad(angle));
            },
            bbox: function (matrix) {
                var this$1 = this;
                var extremeAngles = ellipseExtremeAngles(this.center, this.radius, this.radius, matrix);
                var minPoint = Point.maxPoint();
                var maxPoint = Point.minPoint();
                for (var i = 0; i < 4; i++) {
                    var currentPointX = this$1._pointAt(extremeAngles.x + i * PI_DIV_2).transformCopy(matrix);
                    var currentPointY = this$1._pointAt(extremeAngles.y + i * PI_DIV_2).transformCopy(matrix);
                    var currentPoint = new Point(currentPointX.x, currentPointY.y);
                    minPoint = Point.min(minPoint, currentPoint);
                    maxPoint = Point.max(maxPoint, currentPoint);
                }
                return Rect.fromPoints(minPoint, maxPoint);
            },
            _pointAt: function (angle) {
                var ref = this;
                var center = ref.center;
                var radius = ref.radius;
                return new Point(center.x + radius * Math.cos(angle), center.y + radius * Math.sin(angle));
            },
            containsPoint: function (point) {
                var ref = this;
                var center = ref.center;
                var radius = ref.radius;
                var inCircle = Math.pow(point.x - center.x, 2) + Math.pow(point.y - center.y, 2) <= Math.pow(radius, 2);
                return inCircle;
            },
            _isOnPath: function (point, width) {
                var ref = this;
                var center = ref.center;
                var radius = ref.radius;
                var pointDistance = center.distanceTo(point);
                return radius - width <= pointDistance && pointDistance <= radius + width;
            }
        });
        defineAccessors(Circle$2.prototype, ['radius']);
        ObserversMixin.extend(Circle$2.prototype);
        var GRADIENT = 'Gradient';
        var Paintable = {
            extend: function (proto) {
                proto.fill = this.fill;
                proto.stroke = this.stroke;
            },
            fill: function (color, opacity) {
                var options = this.options;
                if (defined(color)) {
                    if (color && color.nodeType !== GRADIENT) {
                        var newFill = { color: color };
                        if (defined(opacity)) {
                            newFill.opacity = opacity;
                        }
                        options.set('fill', newFill);
                    } else {
                        options.set('fill', color);
                    }
                    return this;
                }
                return options.get('fill');
            },
            stroke: function (color, width, opacity) {
                if (defined(color)) {
                    this.options.set('stroke.color', color);
                    if (defined(width)) {
                        this.options.set('stroke.width', width);
                    }
                    if (defined(opacity)) {
                        this.options.set('stroke.opacity', opacity);
                    }
                    return this;
                }
                return this.options.get('stroke');
            }
        };
        var IDENTITY_MATRIX_HASH = Matrix.IDENTITY.toString();
        var Measurable = {
            extend: function (proto) {
                proto.bbox = this.bbox;
                proto.geometryChange = this.geometryChange;
            },
            bbox: function (transformation) {
                var combinedMatrix = toMatrix(this.currentTransform(transformation));
                var matrixHash = combinedMatrix ? combinedMatrix.toString() : IDENTITY_MATRIX_HASH;
                var bbox;
                if (this._bboxCache && this._matrixHash === matrixHash) {
                    bbox = this._bboxCache.clone();
                } else {
                    bbox = this._bbox(combinedMatrix);
                    this._bboxCache = bbox ? bbox.clone() : null;
                    this._matrixHash = matrixHash;
                }
                var strokeWidth = this.options.get('stroke.width');
                if (strokeWidth && bbox) {
                    bbox.expand(strokeWidth / 2);
                }
                return bbox;
            },
            geometryChange: function () {
                delete this._bboxCache;
                this.trigger('geometryChange', { element: this });
            }
        };
        function geometryAccessor(name) {
            var fieldName = '_' + name;
            return function (value) {
                if (defined(value)) {
                    this._observerField(fieldName, value);
                    this.geometryChange();
                    return this;
                }
                return this[fieldName];
            };
        }
        function defineGeometryAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = geometryAccessor(names[i]);
            }
        }
        var DEFAULT_STROKE = '#000';
        var Circle = Element$1.extend({
            init: function (geometry, options) {
                if (geometry === void 0) {
                    geometry = new Circle$2();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.geometry(geometry);
                if (!defined(this.options.stroke)) {
                    this.stroke(DEFAULT_STROKE);
                }
            },
            rawBBox: function () {
                return this._geometry.bbox();
            },
            _bbox: function (matrix) {
                return this._geometry.bbox(matrix);
            },
            _containsPoint: function (point) {
                return this.geometry().containsPoint(point);
            },
            _isOnPath: function (point) {
                return this.geometry()._isOnPath(point, this.options.stroke.width / 2);
            }
        });
        Circle.prototype.nodeType = 'Circle';
        Paintable.extend(Circle.prototype);
        Measurable.extend(Circle.prototype);
        defineGeometryAccessors(Circle.prototype, ['geometry']);
        var PRECISION = 10;
        function close(a, b, tolerance) {
            if (tolerance === void 0) {
                tolerance = PRECISION;
            }
            return round(Math.abs(a - b), tolerance) === 0;
        }
        function closeOrLess(a, b, tolerance) {
            return a < b || close(a, b, tolerance);
        }
        function lineIntersection(p0, p1, p2, p3) {
            var s1x = p1.x - p0.x;
            var s2x = p3.x - p2.x;
            var s1y = p1.y - p0.y;
            var s2y = p3.y - p2.y;
            var nx = p0.x - p2.x;
            var ny = p0.y - p2.y;
            var d = s1x * s2y - s2x * s1y;
            var s = (s1x * ny - s1y * nx) / d;
            var t = (s2x * ny - s2y * nx) / d;
            if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
                return new Point(p0.x + t * s1x, p0.y + t * s1y);
            }
        }
        var MAX_INTERVAL = 45;
        var pow$1 = Math.pow;
        var Arc$2 = Class.extend({
            init: function (center, options) {
                if (center === void 0) {
                    center = new Point();
                }
                if (options === void 0) {
                    options = {};
                }
                this.setCenter(center);
                this.radiusX = options.radiusX;
                this.radiusY = options.radiusY || options.radiusX;
                this.startAngle = options.startAngle;
                this.endAngle = options.endAngle;
                this.anticlockwise = options.anticlockwise || false;
            },
            clone: function () {
                return new Arc$2(this.center, {
                    radiusX: this.radiusX,
                    radiusY: this.radiusY,
                    startAngle: this.startAngle,
                    endAngle: this.endAngle,
                    anticlockwise: this.anticlockwise
                });
            },
            setCenter: function (value) {
                this._observerField('center', Point.create(value));
                this.geometryChange();
                return this;
            },
            getCenter: function () {
                return this.center;
            },
            pointAt: function (angle) {
                var center = this.center;
                var radian = rad(angle);
                return new Point(center.x + this.radiusX * Math.cos(radian), center.y + this.radiusY * Math.sin(radian));
            },
            curvePoints: function () {
                var this$1 = this;
                var startAngle = this.startAngle;
                var dir = this.anticlockwise ? -1 : 1;
                var curvePoints = [this.pointAt(startAngle)];
                var interval = this._arcInterval();
                var intervalAngle = interval.endAngle - interval.startAngle;
                var subIntervalsCount = Math.ceil(intervalAngle / MAX_INTERVAL);
                var subIntervalAngle = intervalAngle / subIntervalsCount;
                var currentAngle = startAngle;
                for (var i = 1; i <= subIntervalsCount; i++) {
                    var nextAngle = currentAngle + dir * subIntervalAngle;
                    var points = this$1._intervalCurvePoints(currentAngle, nextAngle);
                    curvePoints.push(points.cp1, points.cp2, points.p2);
                    currentAngle = nextAngle;
                }
                return curvePoints;
            },
            bbox: function (matrix) {
                var this$1 = this;
                var interval = this._arcInterval();
                var startAngle = interval.startAngle;
                var endAngle = interval.endAngle;
                var extremeAngles = ellipseExtremeAngles(this.center, this.radiusX, this.radiusY, matrix);
                var extremeX = deg(extremeAngles.x);
                var extremeY = deg(extremeAngles.y);
                var endPoint = this.pointAt(endAngle).transformCopy(matrix);
                var currentAngleX = bboxStartAngle(extremeX, startAngle);
                var currentAngleY = bboxStartAngle(extremeY, startAngle);
                var currentPoint = this.pointAt(startAngle).transformCopy(matrix);
                var minPoint = Point.min(currentPoint, endPoint);
                var maxPoint = Point.max(currentPoint, endPoint);
                while (currentAngleX < endAngle || currentAngleY < endAngle) {
                    var currentPointX = void 0;
                    if (currentAngleX < endAngle) {
                        currentPointX = this$1.pointAt(currentAngleX).transformCopy(matrix);
                        currentAngleX += 90;
                    }
                    var currentPointY = void 0;
                    if (currentAngleY < endAngle) {
                        currentPointY = this$1.pointAt(currentAngleY).transformCopy(matrix);
                        currentAngleY += 90;
                    }
                    currentPoint = new Point(currentPointX.x, currentPointY.y);
                    minPoint = Point.min(minPoint, currentPoint);
                    maxPoint = Point.max(maxPoint, currentPoint);
                }
                return Rect.fromPoints(minPoint, maxPoint);
            },
            _arcInterval: function () {
                var ref = this;
                var startAngle = ref.startAngle;
                var endAngle = ref.endAngle;
                var anticlockwise = ref.anticlockwise;
                if (anticlockwise) {
                    var oldStart = startAngle;
                    startAngle = endAngle;
                    endAngle = oldStart;
                }
                if (startAngle > endAngle || anticlockwise && startAngle === endAngle) {
                    endAngle += 360;
                }
                return {
                    startAngle: startAngle,
                    endAngle: endAngle
                };
            },
            _intervalCurvePoints: function (startAngle, endAngle) {
                var p1 = this.pointAt(startAngle);
                var p2 = this.pointAt(endAngle);
                var p1Derivative = this._derivativeAt(startAngle);
                var p2Derivative = this._derivativeAt(endAngle);
                var t = (rad(endAngle) - rad(startAngle)) / 3;
                var cp1 = new Point(p1.x + t * p1Derivative.x, p1.y + t * p1Derivative.y);
                var cp2 = new Point(p2.x - t * p2Derivative.x, p2.y - t * p2Derivative.y);
                return {
                    p1: p1,
                    cp1: cp1,
                    cp2: cp2,
                    p2: p2
                };
            },
            _derivativeAt: function (angle) {
                var radian = rad(angle);
                return new Point(-this.radiusX * Math.sin(radian), this.radiusY * Math.cos(radian));
            },
            containsPoint: function (point) {
                var interval = this._arcInterval();
                var intervalAngle = interval.endAngle - interval.startAngle;
                var ref = this;
                var center = ref.center;
                var radiusX = ref.radiusX;
                var radiusY = ref.radiusY;
                var distance = center.distanceTo(point);
                var angleRad = Math.atan2(point.y - center.y, point.x - center.x);
                var pointRadius = radiusX * radiusY / Math.sqrt(pow$1(radiusX, 2) * pow$1(Math.sin(angleRad), 2) + pow$1(radiusY, 2) * pow$1(Math.cos(angleRad), 2));
                var startPoint = this.pointAt(this.startAngle).round(PRECISION);
                var endPoint = this.pointAt(this.endAngle).round(PRECISION);
                var intersection = lineIntersection(center, point.round(PRECISION), startPoint, endPoint);
                var containsPoint;
                if (intervalAngle < 180) {
                    containsPoint = intersection && closeOrLess(center.distanceTo(intersection), distance) && closeOrLess(distance, pointRadius);
                } else {
                    var angle = calculateAngle(center.x, center.y, radiusX, radiusY, point.x, point.y);
                    if (angle !== 360) {
                        angle = (360 + angle) % 360;
                    }
                    var inAngleRange = interval.startAngle <= angle && angle <= interval.endAngle;
                    containsPoint = inAngleRange && closeOrLess(distance, pointRadius) || !inAngleRange && (!intersection || intersection.equals(point));
                }
                return containsPoint;
            },
            _isOnPath: function (point, width) {
                var interval = this._arcInterval();
                var center = this.center;
                var angle = calculateAngle(center.x, center.y, this.radiusX, this.radiusY, point.x, point.y);
                if (angle !== 360) {
                    angle = (360 + angle) % 360;
                }
                var inAngleRange = interval.startAngle <= angle && angle <= interval.endAngle;
                return inAngleRange && this.pointAt(angle).distanceTo(point) <= width;
            }
        });
        Arc$2.fromPoints = function (start, end, rx, ry, largeArc, swipe) {
            var arcParameters = normalizeArcParameters({
                x1: start.x,
                y1: start.y,
                x2: end.x,
                y2: end.y,
                rx: rx,
                ry: ry,
                largeArc: largeArc,
                swipe: swipe
            });
            return new Arc$2(arcParameters.center, {
                startAngle: arcParameters.startAngle,
                endAngle: arcParameters.endAngle,
                radiusX: rx,
                radiusY: ry,
                anticlockwise: swipe === 0
            });
        };
        defineAccessors(Arc$2.prototype, [
            'radiusX',
            'radiusY',
            'startAngle',
            'endAngle',
            'anticlockwise'
        ]);
        ObserversMixin.extend(Arc$2.prototype);
        function elipseAngle(start, end, swipe) {
            var endAngle = end;
            if (start > endAngle) {
                endAngle += 360;
            }
            var alpha = Math.abs(endAngle - 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(parameters) {
            var x1 = parameters.x1;
            var y1 = parameters.y1;
            var x2 = parameters.x2;
            var y2 = parameters.y2;
            var rx = parameters.rx;
            var ry = parameters.ry;
            var largeArc = parameters.largeArc;
            var swipe = parameters.swipe;
            var cx, cy;
            var cx1, cy1;
            var a, b, c, sqrt;
            if (y1 !== y2) {
                var x21 = x2 - x1;
                var y21 = y2 - y1;
                var rx2 = pow$1(rx, 2), ry2 = pow$1(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$1(l, 2) / ry2;
                b = 2 * (l * yk2 / ry2 - x2 / rx2);
                c = pow$1(x2, 2) / rx2 + pow$1(yk2, 2) / ry2 - 1;
                sqrt = Math.sqrt(pow$1(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$1((x2 - x1) * ry / (2 * rx), 2) + pow$1(y2, 2) - pow$1(ry, 2);
                sqrt = Math.sqrt(pow$1(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
            };
        }
        function bboxStartAngle(angle, start) {
            var startAngle = angle;
            while (startAngle < start) {
                startAngle += 90;
            }
            return startAngle;
        }
        var push = [].push;
        var pop = [].pop;
        var splice = [].splice;
        var shift = [].shift;
        var slice = [].slice;
        var unshift = [].unshift;
        var ElementsArray = Class.extend({
            init: function (array) {
                if (array === void 0) {
                    array = [];
                }
                this.length = 0;
                this._splice(0, array.length, array);
            },
            elements: function (value) {
                if (value) {
                    this._splice(0, this.length, value);
                    this._change();
                    return this;
                }
                return this.slice(0);
            },
            push: function () {
                var elements = arguments;
                var result = push.apply(this, elements);
                this._add(elements);
                return result;
            },
            slice: function () {
                return slice.call(this);
            },
            pop: function () {
                var length = this.length;
                var result = pop.apply(this);
                if (length) {
                    this._remove([result]);
                }
                return result;
            },
            splice: function (index, howMany) {
                var elements = slice.call(arguments, 2);
                var result = this._splice(index, howMany, elements);
                this._change();
                return result;
            },
            shift: function () {
                var length = this.length;
                var result = shift.apply(this);
                if (length) {
                    this._remove([result]);
                }
                return result;
            },
            unshift: function () {
                var elements = arguments;
                var result = unshift.apply(this, elements);
                this._add(elements);
                return result;
            },
            indexOf: function (element) {
                var this$1 = this;
                var length = this.length;
                for (var idx = 0; idx < length; idx++) {
                    if (this$1[idx] === element) {
                        return idx;
                    }
                }
                return -1;
            },
            _splice: function (index, howMany, elements) {
                var result = splice.apply(this, [
                    index,
                    howMany
                ].concat(elements));
                this._clearObserver(result);
                this._setObserver(elements);
                return result;
            },
            _add: function (elements) {
                this._setObserver(elements);
                this._change();
            },
            _remove: function (elements) {
                this._clearObserver(elements);
                this._change();
            },
            _setObserver: function (elements) {
                var this$1 = this;
                for (var idx = 0; idx < elements.length; idx++) {
                    elements[idx].addObserver(this$1);
                }
            },
            _clearObserver: function (elements) {
                var this$1 = this;
                for (var idx = 0; idx < elements.length; idx++) {
                    elements[idx].removeObserver(this$1);
                }
            },
            _change: function () {
            }
        });
        ObserversMixin.extend(ElementsArray.prototype);
        var GeometryElementsArray = ElementsArray.extend({
            _change: function () {
                this.geometryChange();
            }
        });
        function pointAccessor(name) {
            var fieldName = '_' + name;
            return function (value) {
                if (defined(value)) {
                    this._observerField(fieldName, Point.create(value));
                    this.geometryChange();
                    return this;
                }
                return this[fieldName];
            };
        }
        function definePointAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = pointAccessor(names[i]);
            }
        }
        function isOutOfEndPoint(endPoint, controlPoint, point) {
            var angle = deg(Math.atan2(controlPoint.y - endPoint.y, controlPoint.x - endPoint.x));
            var rotatedPoint = point.transformCopy(transform().rotate(-angle, endPoint));
            return rotatedPoint.x < endPoint.x;
        }
        function calculateCurveAt(t, field, points) {
            var t1 = 1 - t;
            return Math.pow(t1, 3) * points[0][field] + 3 * Math.pow(t1, 2) * t * points[1][field] + 3 * Math.pow(t, 2) * t1 * points[2][field] + Math.pow(t, 3) * points[3][field];
        }
        function toCubicPolynomial(points, field) {
            return [
                -points[0][field] + 3 * points[1][field] - 3 * points[2][field] + points[3][field],
                3 * (points[0][field] - 2 * points[1][field] + points[2][field]),
                3 * (-points[0][field] + points[1][field]),
                points[0][field]
            ];
        }
        var ComplexNumber = Class.extend({
            init: function (real, img) {
                if (real === void 0) {
                    real = 0;
                }
                if (img === void 0) {
                    img = 0;
                }
                this.real = real;
                this.img = img;
            },
            add: function (cNumber) {
                return new ComplexNumber(round(this.real + cNumber.real, PRECISION), round(this.img + cNumber.img, PRECISION));
            },
            addConstant: function (value) {
                return new ComplexNumber(this.real + value, this.img);
            },
            negate: function () {
                return new ComplexNumber(-this.real, -this.img);
            },
            multiply: function (cNumber) {
                return new ComplexNumber(this.real * cNumber.real - this.img * cNumber.img, this.real * cNumber.img + this.img * cNumber.real);
            },
            multiplyConstant: function (value) {
                return new ComplexNumber(this.real * value, this.img * value);
            },
            nthRoot: function (n) {
                var rad$$1 = Math.atan2(this.img, this.real);
                var r = Math.sqrt(Math.pow(this.img, 2) + Math.pow(this.real, 2));
                var nthR = Math.pow(r, 1 / n);
                return new ComplexNumber(nthR * Math.cos(rad$$1 / n), nthR * Math.sin(rad$$1 / n));
            },
            equals: function (cNumber) {
                return this.real === cNumber.real && this.img === cNumber.img;
            },
            isReal: function () {
                return this.img === 0;
            }
        });
        function numberSign(x) {
            return x < 0 ? -1 : 1;
        }
        function solveQuadraticEquation(a, b, c) {
            var squareRoot = Math.sqrt(Math.pow(b, 2) - 4 * a * c);
            return [
                (-b + squareRoot) / (2 * a),
                (-b - squareRoot) / (2 * a)
            ];
        }
        function solveCubicEquation(a, b, c, d) {
            if (a === 0) {
                return solveQuadraticEquation(b, c, d);
            }
            var p = (3 * a * c - Math.pow(b, 2)) / (3 * Math.pow(a, 2));
            var q = (2 * Math.pow(b, 3) - 9 * a * b * c + 27 * Math.pow(a, 2) * d) / (27 * Math.pow(a, 3));
            var Q = Math.pow(p / 3, 3) + Math.pow(q / 2, 2);
            var i = new ComplexNumber(0, 1);
            var b3a = -b / (3 * a);
            var x1, x2, y1, y2, y3, z1, z2;
            if (Q < 0) {
                x1 = new ComplexNumber(-q / 2, Math.sqrt(-Q)).nthRoot(3);
                x2 = new ComplexNumber(-q / 2, -Math.sqrt(-Q)).nthRoot(3);
            } else {
                x1 = -q / 2 + Math.sqrt(Q);
                x1 = new ComplexNumber(numberSign(x1) * Math.pow(Math.abs(x1), 1 / 3));
                x2 = -q / 2 - Math.sqrt(Q);
                x2 = new ComplexNumber(numberSign(x2) * Math.pow(Math.abs(x2), 1 / 3));
            }
            y1 = x1.add(x2);
            z1 = x1.add(x2).multiplyConstant(-1 / 2);
            z2 = x1.add(x2.negate()).multiplyConstant(Math.sqrt(3) / 2);
            y2 = z1.add(i.multiply(z2));
            y3 = z1.add(i.negate().multiply(z2));
            var result = [];
            if (y1.isReal()) {
                result.push(round(y1.real + b3a, PRECISION));
            }
            if (y2.isReal()) {
                result.push(round(y2.real + b3a, PRECISION));
            }
            if (y3.isReal()) {
                result.push(round(y3.real + b3a, PRECISION));
            }
            return result;
        }
        function hasRootsInRange(points, point, field, rootField, range) {
            var polynomial = toCubicPolynomial(points, rootField);
            var roots = solveCubicEquation(polynomial[0], polynomial[1], polynomial[2], polynomial[3] - point[rootField]);
            var intersection;
            for (var idx = 0; idx < roots.length; idx++) {
                if (0 <= roots[idx] && roots[idx] <= 1) {
                    intersection = calculateCurveAt(roots[idx], field, points);
                    if (Math.abs(intersection - point[field]) <= range) {
                        return true;
                    }
                }
            }
        }
        function curveIntersectionsCount(points, point, bbox) {
            var polynomial = toCubicPolynomial(points, 'x');
            var roots = solveCubicEquation(polynomial[0], polynomial[1], polynomial[2], polynomial[3] - point.x);
            var rayIntersection, intersectsRay;
            var count = 0;
            for (var i = 0; i < roots.length; i++) {
                rayIntersection = calculateCurveAt(roots[i], 'y', points);
                intersectsRay = close(rayIntersection, point.y) || rayIntersection > point.y;
                if (intersectsRay && ((roots[i] === 0 || roots[i] === 1) && bbox.bottomRight().x > point.x || 0 < roots[i] && roots[i] < 1)) {
                    count++;
                }
            }
            return count;
        }
        function lineIntersectionsCount(a, b, point) {
            var intersects;
            if (a.x !== b.x) {
                var minX = Math.min(a.x, b.x);
                var maxX = Math.max(a.x, b.x);
                var minY = Math.min(a.y, b.y);
                var maxY = Math.max(a.y, b.y);
                var inRange = minX <= point.x && point.x < maxX;
                if (minY === maxY) {
                    intersects = point.y <= minY && inRange;
                } else {
                    intersects = inRange && (maxY - minY) * ((a.x - b.x) * (a.y - b.y) > 0 ? point.x - minX : maxX - point.x) / (maxX - minX) + minY - point.y >= 0;
                }
            }
            return intersects ? 1 : 0;
        }
        var Segment = Class.extend({
            init: function (anchor, controlIn, controlOut) {
                this.anchor(anchor || new Point());
                this.controlIn(controlIn);
                this.controlOut(controlOut);
            },
            bboxTo: function (toSegment, matrix) {
                var segmentAnchor = this.anchor().transformCopy(matrix);
                var toSegmentAnchor = toSegment.anchor().transformCopy(matrix);
                var rect;
                if (this.controlOut() && toSegment.controlIn()) {
                    rect = this._curveBoundingBox(segmentAnchor, this.controlOut().transformCopy(matrix), toSegment.controlIn().transformCopy(matrix), toSegmentAnchor);
                } else {
                    rect = this._lineBoundingBox(segmentAnchor, toSegmentAnchor);
                }
                return rect;
            },
            _lineBoundingBox: function (p1, p2) {
                return Rect.fromPoints(p1, p2);
            },
            _curveBoundingBox: function (p1, cp1, cp2, p2) {
                var points = [
                    p1,
                    cp1,
                    cp2,
                    p2
                ];
                var extremesX = this._curveExtremesFor(points, 'x');
                var extremesY = this._curveExtremesFor(points, 'y');
                var xLimits = arrayLimits([
                    extremesX.min,
                    extremesX.max,
                    p1.x,
                    p2.x
                ]);
                var yLimits = arrayLimits([
                    extremesY.min,
                    extremesY.max,
                    p1.y,
                    p2.y
                ]);
                return Rect.fromPoints(new Point(xLimits.min, yLimits.min), new Point(xLimits.max, yLimits.max));
            },
            _curveExtremesFor: function (points, field) {
                var extremes = this._curveExtremes(points[0][field], points[1][field], points[2][field], points[3][field]);
                return {
                    min: calculateCurveAt(extremes.min, field, points),
                    max: calculateCurveAt(extremes.max, field, points)
                };
            },
            _curveExtremes: function (x1, x2, x3, x4) {
                var a = x1 - 3 * x2 + 3 * x3 - x4;
                var b = -2 * (x1 - 2 * x2 + x3);
                var c = x1 - x2;
                var sqrt = Math.sqrt(b * b - 4 * a * c);
                var t1 = 0;
                var t2 = 1;
                if (a === 0) {
                    if (b !== 0) {
                        t1 = t2 = -c / b;
                    }
                } else if (!isNaN(sqrt)) {
                    t1 = (-b + sqrt) / (2 * a);
                    t2 = (-b - sqrt) / (2 * a);
                }
                var min = Math.max(Math.min(t1, t2), 0);
                if (min < 0 || min > 1) {
                    min = 0;
                }
                var max = Math.min(Math.max(t1, t2), 1);
                if (max > 1 || max < 0) {
                    max = 1;
                }
                return {
                    min: min,
                    max: max
                };
            },
            _intersectionsTo: function (segment, point) {
                var intersectionsCount;
                if (this.controlOut() && segment.controlIn()) {
                    intersectionsCount = curveIntersectionsCount([
                        this.anchor(),
                        this.controlOut(),
                        segment.controlIn(),
                        segment.anchor()
                    ], point, this.bboxTo(segment));
                } else {
                    intersectionsCount = lineIntersectionsCount(this.anchor(), segment.anchor(), point);
                }
                return intersectionsCount;
            },
            _isOnCurveTo: function (segment, point, width, endSegment) {
                var bbox = this.bboxTo(segment).expand(width, width);
                if (bbox.containsPoint(point)) {
                    var p1 = this.anchor();
                    var p2 = this.controlOut();
                    var p3 = segment.controlIn();
                    var p4 = segment.anchor();
                    if (endSegment === 'start' && p1.distanceTo(point) <= width) {
                        return !isOutOfEndPoint(p1, p2, point);
                    } else if (endSegment === 'end' && p4.distanceTo(point) <= width) {
                        return !isOutOfEndPoint(p4, p3, point);
                    }
                    var points = [
                        p1,
                        p2,
                        p3,
                        p4
                    ];
                    if (hasRootsInRange(points, point, 'x', 'y', width) || hasRootsInRange(points, point, 'y', 'x', width)) {
                        return true;
                    }
                    var rotation = transform().rotate(45, point);
                    var rotatedPoints = [
                        p1.transformCopy(rotation),
                        p2.transformCopy(rotation),
                        p3.transformCopy(rotation),
                        p4.transformCopy(rotation)
                    ];
                    return hasRootsInRange(rotatedPoints, point, 'x', 'y', width) || hasRootsInRange(rotatedPoints, point, 'y', 'x', width);
                }
            },
            _isOnLineTo: function (segment, point, width) {
                var p1 = this.anchor();
                var p2 = segment.anchor();
                var angle = deg(Math.atan2(p2.y - p1.y, p2.x - p1.x));
                var rect = new Rect([
                    p1.x,
                    p1.y - width / 2
                ], [
                    p1.distanceTo(p2),
                    width
                ]);
                return rect.containsPoint(point.transformCopy(transform().rotate(-angle, p1)));
            },
            _isOnPathTo: function (segment, point, width, endSegment) {
                var isOnPath;
                if (this.controlOut() && segment.controlIn()) {
                    isOnPath = this._isOnCurveTo(segment, point, width / 2, endSegment);
                } else {
                    isOnPath = this._isOnLineTo(segment, point, width);
                }
                return isOnPath;
            }
        });
        definePointAccessors(Segment.prototype, [
            'anchor',
            'controlIn',
            'controlOut'
        ]);
        ObserversMixin.extend(Segment.prototype);
        function arrayLimits(arr) {
            var length = arr.length;
            var min = MAX_NUM;
            var max = MIN_NUM;
            for (var i = 0; i < length; i++) {
                max = Math.max(max, arr[i]);
                min = Math.min(min, arr[i]);
            }
            return {
                min: min,
                max: max
            };
        }
        var Path = Element$1.extend({
            init: function (options) {
                Element$1.fn.init.call(this, options);
                this.segments = new GeometryElementsArray();
                this.segments.addObserver(this);
                if (!defined(this.options.stroke)) {
                    this.stroke('#000');
                    if (!defined(this.options.stroke.lineJoin)) {
                        this.options.set('stroke.lineJoin', 'miter');
                    }
                }
            },
            moveTo: function (x, y) {
                this.suspend();
                this.segments.elements([]);
                this.resume();
                this.lineTo(x, y);
                return this;
            },
            lineTo: function (x, y) {
                var point = defined(y) ? new Point(x, y) : x;
                var segment = new Segment(point);
                this.segments.push(segment);
                return this;
            },
            curveTo: function (controlOut, controlIn, point) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var segment = new Segment(point, controlIn);
                    this.suspend();
                    lastSegment.controlOut(controlOut);
                    this.resume();
                    this.segments.push(segment);
                }
                return this;
            },
            arc: function (startAngle, endAngle, radiusX, radiusY, anticlockwise) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var anchor = lastSegment.anchor();
                    var start = rad(startAngle);
                    var center = new Point(anchor.x - radiusX * Math.cos(start), anchor.y - radiusY * Math.sin(start));
                    var arc = new Arc$2(center, {
                        startAngle: startAngle,
                        endAngle: endAngle,
                        radiusX: radiusX,
                        radiusY: radiusY,
                        anticlockwise: anticlockwise
                    });
                    this._addArcSegments(arc);
                }
                return this;
            },
            arcTo: function (end, rx, ry, largeArc, swipe) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var anchor = lastSegment.anchor();
                    var arc = Arc$2.fromPoints(anchor, end, rx, ry, largeArc, swipe);
                    this._addArcSegments(arc);
                }
                return this;
            },
            _addArcSegments: function (arc) {
                var this$1 = this;
                this.suspend();
                var curvePoints = arc.curvePoints();
                for (var i = 1; i < curvePoints.length; i += 3) {
                    this$1.curveTo(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]);
                }
                this.resume();
                this.geometryChange();
            },
            close: function () {
                this.options.closed = true;
                this.geometryChange();
                return this;
            },
            rawBBox: function () {
                return this._bbox();
            },
            _containsPoint: function (point) {
                var segments = this.segments;
                var length = segments.length;
                var intersectionsCount = 0;
                var previous, current;
                for (var idx = 1; idx < length; idx++) {
                    previous = segments[idx - 1];
                    current = segments[idx];
                    intersectionsCount += previous._intersectionsTo(current, point);
                }
                if (this.options.closed || !segments[0].anchor().equals(segments[length - 1].anchor())) {
                    intersectionsCount += lineIntersectionsCount(segments[0].anchor(), segments[length - 1].anchor(), point);
                }
                return intersectionsCount % 2 !== 0;
            },
            _isOnPath: function (point, width) {
                var segments = this.segments;
                var length = segments.length;
                var pathWidth = width || this.options.stroke.width;
                if (length > 1) {
                    if (segments[0]._isOnPathTo(segments[1], point, pathWidth, 'start')) {
                        return true;
                    }
                    for (var idx = 2; idx <= length - 2; idx++) {
                        if (segments[idx - 1]._isOnPathTo(segments[idx], point, pathWidth)) {
                            return true;
                        }
                    }
                    if (segments[length - 2]._isOnPathTo(segments[length - 1], point, pathWidth, 'end')) {
                        return true;
                    }
                }
                return false;
            },
            _bbox: function (matrix) {
                var segments = this.segments;
                var length = segments.length;
                var boundingBox;
                if (length === 1) {
                    var anchor = segments[0].anchor().transformCopy(matrix);
                    boundingBox = new Rect(anchor, Size.ZERO);
                } else if (length > 0) {
                    for (var i = 1; i < length; i++) {
                        var segmentBox = segments[i - 1].bboxTo(segments[i], matrix);
                        if (boundingBox) {
                            boundingBox = Rect.union(boundingBox, segmentBox);
                        } else {
                            boundingBox = segmentBox;
                        }
                    }
                }
                return boundingBox;
            }
        });
        Path.fromRect = function (rect, options) {
            return new Path(options).moveTo(rect.topLeft()).lineTo(rect.topRight()).lineTo(rect.bottomRight()).lineTo(rect.bottomLeft()).close();
        };
        Path.fromPoints = function (points, options) {
            if (points) {
                var path = new Path(options);
                for (var i = 0; i < points.length; i++) {
                    var point = Point.create(points[i]);
                    if (point) {
                        if (i === 0) {
                            path.moveTo(point);
                        } else {
                            path.lineTo(point);
                        }
                    }
                }
                return path;
            }
        };
        Path.fromArc = function (arc, options) {
            var path = new Path(options);
            var startAngle = arc.startAngle;
            var start = arc.pointAt(startAngle);
            path.moveTo(start.x, start.y);
            path.arc(startAngle, arc.endAngle, arc.radiusX, arc.radiusY, arc.anticlockwise);
            return path;
        };
        Path.prototype.nodeType = 'Path';
        Paintable.extend(Path.prototype);
        Measurable.extend(Path.prototype);
        var DEFAULT_STROKE$1 = '#000';
        var Arc = Element$1.extend({
            init: function (geometry, options) {
                if (geometry === void 0) {
                    geometry = new Arc$2();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.geometry(geometry);
                if (!defined(this.options.stroke)) {
                    this.stroke(DEFAULT_STROKE$1);
                }
            },
            _bbox: function (matrix) {
                return this._geometry.bbox(matrix);
            },
            rawBBox: function () {
                return this.geometry().bbox();
            },
            toPath: function () {
                var path = new Path();
                var curvePoints = this.geometry().curvePoints();
                if (curvePoints.length > 0) {
                    path.moveTo(curvePoints[0].x, curvePoints[0].y);
                    for (var i = 1; i < curvePoints.length; i += 3) {
                        path.curveTo(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]);
                    }
                }
                return path;
            },
            _containsPoint: function (point) {
                return this.geometry().containsPoint(point);
            },
            _isOnPath: function (point) {
                return this.geometry()._isOnPath(point, this.options.stroke.width / 2);
            }
        });
        Arc.prototype.nodeType = 'Arc';
        Paintable.extend(Arc.prototype);
        Measurable.extend(Arc.prototype);
        defineGeometryAccessors(Arc.prototype, ['geometry']);
        function elementsBoundingBox(elements, applyTransform, transformation) {
            var boundingBox;
            for (var i = 0; i < elements.length; i++) {
                var element = elements[i];
                if (element.visible()) {
                    var elementBoundingBox = applyTransform ? element.bbox(transformation) : element.rawBBox();
                    if (elementBoundingBox) {
                        if (boundingBox) {
                            boundingBox = Rect.union(boundingBox, elementBoundingBox);
                        } else {
                            boundingBox = elementBoundingBox;
                        }
                    }
                }
            }
            return boundingBox;
        }
        function elementsClippedBoundingBox(elements, transformation) {
            var boundingBox;
            for (var i = 0; i < elements.length; i++) {
                var element = elements[i];
                if (element.visible()) {
                    var elementBoundingBox = element.clippedBBox(transformation);
                    if (elementBoundingBox) {
                        if (boundingBox) {
                            boundingBox = Rect.union(boundingBox, elementBoundingBox);
                        } else {
                            boundingBox = elementBoundingBox;
                        }
                    }
                }
            }
            return boundingBox;
        }
        var MultiPath = Element$1.extend({
            init: function (options) {
                Element$1.fn.init.call(this, options);
                this.paths = new GeometryElementsArray();
                this.paths.addObserver(this);
                if (!defined(this.options.stroke)) {
                    this.stroke('#000');
                }
            },
            moveTo: function (x, y) {
                var path = new Path();
                path.moveTo(x, y);
                this.paths.push(path);
                return this;
            },
            lineTo: function (x, y) {
                if (this.paths.length > 0) {
                    last(this.paths).lineTo(x, y);
                }
                return this;
            },
            curveTo: function (controlOut, controlIn, point) {
                if (this.paths.length > 0) {
                    last(this.paths).curveTo(controlOut, controlIn, point);
                }
                return this;
            },
            arc: function (startAngle, endAngle, radiusX, radiusY, anticlockwise) {
                if (this.paths.length > 0) {
                    last(this.paths).arc(startAngle, endAngle, radiusX, radiusY, anticlockwise);
                }
                return this;
            },
            arcTo: function (end, rx, ry, largeArc, swipe) {
                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));
            }
        });
        MultiPath.prototype.nodeType = 'MultiPath';
        Paintable.extend(MultiPath.prototype);
        Measurable.extend(MultiPath.prototype);
        var DEFAULT_FONT = '12px sans-serif';
        var DEFAULT_FILL = '#000';
        var Text = Element$1.extend({
            init: function (content, position, options) {
                if (position === void 0) {
                    position = new Point();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.content(content);
                this.position(position);
                if (!this.options.font) {
                    this.options.font = DEFAULT_FONT;
                }
                if (!defined(this.options.fill)) {
                    this.fill(DEFAULT_FILL);
                }
            },
            content: function (value) {
                if (defined(value)) {
                    this.options.set('content', value);
                    return this;
                }
                return this.options.get('content');
            },
            measure: function () {
                var metrics = kendoUtil.measureText(this.content(), { font: this.options.get('font') });
                return metrics;
            },
            rect: function () {
                var size = this.measure();
                var pos = this.position().clone();
                return new Rect(pos, [
                    size.width,
                    size.height
                ]);
            },
            bbox: function (transformation) {
                var combinedMatrix = toMatrix(this.currentTransform(transformation));
                return this.rect().bbox(combinedMatrix);
            },
            rawBBox: function () {
                return this.rect().bbox();
            },
            _containsPoint: function (point) {
                return this.rect().containsPoint(point);
            }
        });
        Text.prototype.nodeType = 'Text';
        Paintable.extend(Text.prototype);
        definePointAccessors(Text.prototype, ['position']);
        var Image$1 = Element$1.extend({
            init: function (src, rect, options) {
                if (rect === void 0) {
                    rect = new Rect();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.src(src);
                this.rect(rect);
            },
            src: function (value) {
                if (defined(value)) {
                    this.options.set('src', value);
                    return this;
                }
                return this.options.get('src');
            },
            bbox: function (transformation) {
                var combinedMatrix = toMatrix(this.currentTransform(transformation));
                return this._rect.bbox(combinedMatrix);
            },
            rawBBox: function () {
                return this._rect.bbox();
            },
            _containsPoint: function (point) {
                return this._rect.containsPoint(point);
            },
            _hasFill: function () {
                return this.src();
            }
        });
        Image$1.prototype.nodeType = 'Image';
        defineGeometryAccessors(Image$1.prototype, ['rect']);
        var Traversable = {
            extend: function (proto, childrenField) {
                proto.traverse = function (callback) {
                    var children = this[childrenField];
                    for (var i = 0; i < children.length; i++) {
                        var child = children[i];
                        if (child.traverse) {
                            child.traverse(callback);
                        } else {
                            callback(child);
                        }
                    }
                    return this;
                };
            }
        };
        var Group = Element$1.extend({
            init: function (options) {
                Element$1.fn.init.call(this, options);
                this.children = [];
            },
            childrenChange: function (action, items, index) {
                this.trigger('childrenChange', {
                    action: action,
                    items: items,
                    index: index
                });
            },
            append: function () {
                append(this.children, arguments);
                this._reparent(arguments, this);
                this.childrenChange('add', arguments);
                return this;
            },
            insert: function (index, element) {
                this.children.splice(index, 0, element);
                element.parent = this;
                this.childrenChange('add', [element], index);
                return this;
            },
            insertAt: function (element, index) {
                return this.insert(index, element);
            },
            remove: function (element) {
                var index = this.children.indexOf(element);
                if (index >= 0) {
                    this.children.splice(index, 1);
                    element.parent = null;
                    this.childrenChange('remove', [element], index);
                }
                return this;
            },
            removeAt: function (index) {
                if (0 <= index && index < this.children.length) {
                    var element = this.children[index];
                    this.children.splice(index, 1);
                    element.parent = null;
                    this.childrenChange('remove', [element], index);
                }
                return this;
            },
            clear: function () {
                var items = this.children;
                this.children = [];
                this._reparent(items, null);
                this.childrenChange('remove', items, 0);
                return this;
            },
            bbox: function (transformation) {
                return elementsBoundingBox(this.children, true, this.currentTransform(transformation));
            },
            rawBBox: function () {
                return elementsBoundingBox(this.children, false);
            },
            _clippedBBox: function (transformation) {
                return elementsClippedBoundingBox(this.children, this.currentTransform(transformation));
            },
            currentTransform: function (transformation) {
                return Element$1.prototype.currentTransform.call(this, transformation) || null;
            },
            containsPoint: function (point, parentTransform) {
                if (this.visible()) {
                    var children = this.children;
                    var transform = this.currentTransform(parentTransform);
                    for (var idx = 0; idx < children.length; idx++) {
                        if (children[idx].containsPoint(point, transform)) {
                            return true;
                        }
                    }
                }
                return false;
            },
            _reparent: function (elements, newParent) {
                var this$1 = this;
                for (var i = 0; i < elements.length; i++) {
                    var child = elements[i];
                    var parent = child.parent;
                    if (parent && parent !== this$1 && parent.remove) {
                        parent.remove(child);
                    }
                    child.parent = newParent;
                }
            }
        });
        Group.prototype.nodeType = 'Group';
        Traversable.extend(Group.prototype, 'children');
        function translateToPoint(point, bbox, element) {
            var transofrm = element.transform() || transform();
            var matrix = transofrm.matrix();
            matrix.e += point.x - bbox.origin.x;
            matrix.f += point.y - bbox.origin.y;
            transofrm.matrix(matrix);
            element.transform(transofrm);
        }
        function alignStart(size, rect, align, axis, sizeField) {
            var start;
            if (align === 'start') {
                start = rect.origin[axis];
            } else if (align === 'end') {
                start = rect.origin[axis] + rect.size[sizeField] - size;
            } else {
                start = rect.origin[axis] + (rect.size[sizeField] - size) / 2;
            }
            return start;
        }
        var DEFAULT_OPTIONS = {
            alignContent: 'start',
            justifyContent: 'start',
            alignItems: 'start',
            spacing: 0,
            orientation: 'horizontal',
            lineSpacing: 0,
            wrap: true
        };
        var Layout = Group.extend({
            init: function (rect, options) {
                Group.fn.init.call(this, $.extend({}, DEFAULT_OPTIONS, options));
                this._rect = rect;
                this._fieldMap = {};
            },
            rect: function (value) {
                if (value) {
                    this._rect = value;
                    return this;
                }
                return this._rect;
            },
            _initMap: function () {
                var options = this.options;
                var fieldMap = this._fieldMap;
                if (options.orientation === 'horizontal') {
                    fieldMap.sizeField = 'width';
                    fieldMap.groupsSizeField = 'height';
                    fieldMap.groupAxis = 'x';
                    fieldMap.groupsAxis = 'y';
                } else {
                    fieldMap.sizeField = 'height';
                    fieldMap.groupsSizeField = 'width';
                    fieldMap.groupAxis = 'y';
                    fieldMap.groupsAxis = 'x';
                }
            },
            reflow: function () {
                if (!this._rect || this.children.length === 0) {
                    return;
                }
                this._initMap();
                if (this.options.transform) {
                    this.transform(null);
                }
                var options = this.options;
                var rect = this._rect;
                var ref = this._initGroups();
                var groups = ref.groups;
                var groupsSize = ref.groupsSize;
                var ref$1 = this._fieldMap;
                var sizeField = ref$1.sizeField;
                var groupsSizeField = ref$1.groupsSizeField;
                var groupAxis = ref$1.groupAxis;
                var groupsAxis = ref$1.groupsAxis;
                var groupOrigin = new Point();
                var elementOrigin = new Point();
                var size = new Size();
                var groupStart = alignStart(groupsSize, rect, options.alignContent, groupsAxis, groupsSizeField);
                var elementStart, 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 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$$1 = transform();
                    if (groupAxis === 'x') {
                        transform$$1.translate(rect.origin.x - scaledStart.x, newStart - scaledStart.y);
                    } else {
                        transform$$1.translate(newStart - scaledStart.x, rect.origin.y - scaledStart.y);
                    }
                    transform$$1.scale(scale, scale);
                    this.transform(transform$$1);
                }
            },
            _initGroups: function () {
                var this$1 = this;
                var ref = this;
                var options = ref.options;
                var children = ref.children;
                var lineSpacing = options.lineSpacing;
                var wrap = options.wrap;
                var spacing = options.spacing;
                var sizeField = this._fieldMap.sizeField;
                var group = this._newGroup();
                var groups = [];
                var addGroup = function () {
                    groups.push(group);
                    groupsSize += group.lineSize + lineSpacing;
                };
                var groupsSize = -lineSpacing;
                for (var idx = 0; idx < children.length; idx++) {
                    var element = children[idx];
                    var bbox = children[idx].clippedBBox();
                    if (element.visible() && bbox) {
                        if (wrap && group.size + bbox.size[sizeField] + spacing > this$1._rect.size[sizeField]) {
                            if (group.bboxes.length === 0) {
                                this$1._addToGroup(group, bbox, element);
                                addGroup();
                                group = this$1._newGroup();
                            } else {
                                addGroup();
                                group = this$1._newGroup();
                                this$1._addToGroup(group, bbox, element);
                            }
                        } else {
                            this$1._addToGroup(group, bbox, element);
                        }
                    }
                }
                if (group.bboxes.length) {
                    addGroup();
                }
                return {
                    groups: groups,
                    groupsSize: groupsSize
                };
            },
            _addToGroup: function (group, bbox, element) {
                group.size += bbox.size[this._fieldMap.sizeField] + this.options.spacing;
                group.lineSize = Math.max(bbox.size[this._fieldMap.groupsSizeField], group.lineSize);
                group.bboxes.push(bbox);
                group.elements.push(element);
            },
            _newGroup: function () {
                return {
                    lineSize: 0,
                    size: -this.options.spacing,
                    bboxes: [],
                    elements: []
                };
            }
        });
        var Rect$2 = Element$1.extend({
            init: function (geometry, options) {
                if (geometry === void 0) {
                    geometry = new Rect();
                }
                if (options === void 0) {
                    options = {};
                }
                Element$1.fn.init.call(this, options);
                this.geometry(geometry);
                if (!defined(this.options.stroke)) {
                    this.stroke('#000');
                }
            },
            _bbox: function (matrix) {
                return this._geometry.bbox(matrix);
            },
            rawBBox: function () {
                return this._geometry.bbox();
            },
            _containsPoint: function (point) {
                return this._geometry.containsPoint(point);
            },
            _isOnPath: function (point) {
                return this.geometry()._isOnPath(point, this.options.stroke.width / 2);
            }
        });
        Rect$2.prototype.nodeType = 'Rect';
        Paintable.extend(Rect$2.prototype);
        Measurable.extend(Rect$2.prototype);
        defineGeometryAccessors(Rect$2.prototype, ['geometry']);
        function alignElements(elements, rect, alignment, axis, sizeField) {
            for (var idx = 0; idx < elements.length; idx++) {
                var bbox = elements[idx].clippedBBox();
                if (bbox) {
                    var point = bbox.origin.clone();
                    point[axis] = alignStart(bbox.size[sizeField], rect, alignment || 'start', axis, sizeField);
                    translateToPoint(point, bbox, elements[idx]);
                }
            }
        }
        function align(elements, rect, alignment) {
            alignElements(elements, rect, alignment, 'x', 'width');
        }
        function vAlign(elements, rect, alignment) {
            alignElements(elements, rect, alignment, 'y', 'height');
        }
        function stackElements(elements, stackAxis, otherAxis, sizeField) {
            if (elements.length > 1) {
                var origin = new Point();
                var previousBBox = elements[0].bbox;
                for (var idx = 1; idx < elements.length; idx++) {
                    var element = elements[idx].element;
                    var bbox = elements[idx].bbox;
                    origin[stackAxis] = previousBBox.origin[stackAxis] + previousBBox.size[sizeField];
                    origin[otherAxis] = bbox.origin[otherAxis];
                    translateToPoint(origin, bbox, element);
                    bbox.origin[stackAxis] = origin[stackAxis];
                    previousBBox = bbox;
                }
            }
        }
        function createStackElements(elements) {
            var stackElements = [];
            for (var idx = 0; idx < elements.length; idx++) {
                var element = elements[idx];
                var bbox = element.clippedBBox();
                if (bbox) {
                    stackElements.push({
                        element: element,
                        bbox: bbox
                    });
                }
            }
            return stackElements;
        }
        function stack(elements) {
            stackElements(createStackElements(elements), 'x', 'y', 'width');
        }
        function vStack(elements) {
            stackElements(createStackElements(elements), 'y', 'x', 'height');
        }
        function getStacks(elements, rect, sizeField) {
            var maxSize = rect.size[sizeField];
            var stacks = [];
            var stack = [];
            var stackSize = 0;
            var element, bbox;
            var addElementToStack = function () {
                stack.push({
                    element: element,
                    bbox: bbox
                });
            };
            for (var idx = 0; idx < elements.length; idx++) {
                element = elements[idx];
                bbox = element.clippedBBox();
                if (bbox) {
                    var size = bbox.size[sizeField];
                    if (stackSize + size > maxSize) {
                        if (stack.length) {
                            stacks.push(stack);
                            stack = [];
                            addElementToStack();
                            stackSize = size;
                        } else {
                            addElementToStack();
                            stacks.push(stack);
                            stack = [];
                            stackSize = 0;
                        }
                    } else {
                        addElementToStack();
                        stackSize += size;
                    }
                }
            }
            if (stack.length) {
                stacks.push(stack);
            }
            return stacks;
        }
        function wrapElements(elements, rect, axis, otherAxis, sizeField) {
            var stacks = getStacks(elements, rect, sizeField);
            var origin = rect.origin.clone();
            var result = [];
            for (var idx = 0; idx < stacks.length; idx++) {
                var stack = stacks[idx];
                var startElement = stack[0];
                origin[otherAxis] = startElement.bbox.origin[otherAxis];
                translateToPoint(origin, startElement.bbox, startElement.element);
                startElement.bbox.origin[axis] = origin[axis];
                stackElements(stack, axis, otherAxis, sizeField);
                result.push([]);
                for (var elementIdx = 0; elementIdx < stack.length; elementIdx++) {
                    result[idx].push(stack[elementIdx].element);
                }
            }
            return result;
        }
        function wrap(elements, rect) {
            return wrapElements(elements, rect, 'x', 'y', 'width');
        }
        function vWrap(elements, rect) {
            return wrapElements(elements, rect, 'y', 'x', 'height');
        }
        function fit(element, rect) {
            var bbox = element.clippedBBox();
            if (bbox) {
                var elementSize = bbox.size;
                var rectSize = rect.size;
                if (rectSize.width < elementSize.width || rectSize.height < elementSize.height) {
                    var scale = Math.min(rectSize.width / elementSize.width, rectSize.height / elementSize.height);
                    var transform$$1 = element.transform() || transform();
                    transform$$1.scale(scale, scale);
                    element.transform(transform$$1);
                }
            }
        }
        var StopsArray = ElementsArray.extend({
            _change: function () {
                this.optionsChange({ field: 'stops' });
            }
        });
        function optionsAccessor(name) {
            return function (value) {
                if (defined(value)) {
                    this.options.set(name, value);
                    return this;
                }
                return this.options.get(name);
            };
        }
        function defineOptionsAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = optionsAccessor(names[i]);
            }
        }
        var GradientStop = Class.extend({
            init: function (offset, color, opacity) {
                this.options = new OptionsStore({
                    offset: offset,
                    color: color,
                    opacity: defined(opacity) ? opacity : 1
                });
                this.options.addObserver(this);
            }
        });
        GradientStop.create = function (arg) {
            if (defined(arg)) {
                var stop;
                if (arg instanceof GradientStop) {
                    stop = arg;
                } else if (arg.length > 1) {
                    stop = new GradientStop(arg[0], arg[1], arg[2]);
                } else {
                    stop = new GradientStop(arg.offset, arg.color, arg.opacity);
                }
                return stop;
            }
        };
        defineOptionsAccessors(GradientStop.prototype, [
            'offset',
            'color',
            'opacity'
        ]);
        ObserversMixin.extend(GradientStop.prototype);
        var Gradient = Class.extend({
            init: function (options) {
                if (options === void 0) {
                    options = {};
                }
                this.stops = new StopsArray(this._createStops(options.stops));
                this.stops.addObserver(this);
                this._userSpace = options.userSpace;
                this.id = definitionId();
            },
            userSpace: function (value) {
                if (defined(value)) {
                    this._userSpace = value;
                    this.optionsChange();
                    return this;
                }
                return this._userSpace;
            },
            _createStops: function (stops) {
                if (stops === void 0) {
                    stops = [];
                }
                var result = [];
                for (var idx = 0; idx < stops.length; idx++) {
                    result.push(GradientStop.create(stops[idx]));
                }
                return result;
            },
            addStop: function (offset, color, opacity) {
                this.stops.push(new GradientStop(offset, color, opacity));
            },
            removeStop: function (stop) {
                var index = this.stops.indexOf(stop);
                if (index >= 0) {
                    this.stops.splice(index, 1);
                }
            }
        });
        Gradient.prototype.nodeType = 'Gradient';
        ObserversMixin.extend(Gradient.prototype);
        $.extend(Gradient.prototype, {
            optionsChange: function (e) {
                this.trigger('optionsChange', {
                    field: 'gradient' + (e ? '.' + e.field : ''),
                    value: this
                });
            },
            geometryChange: function () {
                this.optionsChange();
            }
        });
        var LinearGradient = Gradient.extend({
            init: function (options) {
                if (options === void 0) {
                    options = {};
                }
                Gradient.fn.init.call(this, options);
                this.start(options.start || new Point());
                this.end(options.end || new Point(1, 0));
            }
        });
        definePointAccessors(LinearGradient.prototype, [
            'start',
            'end'
        ]);
        var RadialGradient = Gradient.extend({
            init: function (options) {
                if (options === void 0) {
                    options = {};
                }
                Gradient.fn.init.call(this, options);
                this.center(options.center || new Point());
                this._radius = defined(options.radius) ? options.radius : 1;
                this._fallbackFill = options.fallbackFill;
            },
            radius: function (value) {
                if (defined(value)) {
                    this._radius = value;
                    this.geometryChange();
                    return this;
                }
                return this._radius;
            },
            fallbackFill: function (value) {
                if (defined(value)) {
                    this._fallbackFill = value;
                    this.optionsChange();
                    return this;
                }
                return this._fallbackFill;
            }
        });
        definePointAccessors(RadialGradient.prototype, ['center']);
        function swing(position) {
            return 0.5 - Math.cos(position * Math.PI) / 2;
        }
        function linear(position) {
            return position;
        }
        function easeOutElastic(position, time, start, diff) {
            var s = 1.70158, p = 0, a = diff;
            if (position === 0) {
                return start;
            }
            if (position === 1) {
                return start + diff;
            }
            if (!p) {
                p = 0.5;
            }
            if (a < Math.abs(diff)) {
                a = diff;
                s = p / 4;
            } else {
                s = p / (2 * Math.PI) * Math.asin(diff / a);
            }
            return a * Math.pow(2, -10 * position) * Math.sin((Number(position) - s) * (1.1 * Math.PI) / p) + diff + start;
        }
        var easingFunctions = {
            swing: swing,
            linear: linear,
            easeOutElastic: easeOutElastic
        };
        var now = Date.now || function () {
            return new Date().getTime();
        };
        var Animation = Class.extend({
            init: function (element, options) {
                this.options = $.extend({}, this.options, options);
                this.element = element;
            },
            setup: function () {
            },
            step: function () {
            },
            play: function () {
                var this$1 = this;
                var options = this.options;
                var duration = options.duration;
                var delay = options.delay;
                if (delay === void 0) {
                    delay = 0;
                }
                var easing = easingFunctions[options.easing];
                var start = now() + delay;
                var finish = start + duration;
                if (duration === 0) {
                    this.step(1);
                    this.abort();
                } else {
                    setTimeout(function () {
                        var loop = function () {
                            if (this$1._stopped) {
                                return;
                            }
                            var wallTime = now();
                            var time = limitValue(wallTime - start, 0, duration);
                            var position = time / duration;
                            var easingPosition = easing(position, time, 0, 1, duration);
                            this$1.step(easingPosition);
                            if (wallTime < finish) {
                                kendo.animationFrame(loop);
                            } else {
                                this$1.abort();
                            }
                        };
                        loop();
                    }, delay);
                }
            },
            abort: function () {
                this._stopped = true;
            },
            destroy: function () {
                this.abort();
            }
        });
        Animation.prototype.options = {
            duration: 500,
            easing: 'swing'
        };
        var AnimationFactory = Class.extend({
            init: function () {
                this._items = [];
            },
            register: function (name, type) {
                this._items.push({
                    name: name,
                    type: type
                });
            },
            create: function (element, options) {
                var items = this._items;
                var match;
                if (options && options.type) {
                    var type = options.type.toLowerCase();
                    for (var i = 0; i < items.length; i++) {
                        if (items[i].name.toLowerCase() === type) {
                            match = items[i];
                            break;
                        }
                    }
                }
                if (match) {
                    return new match.type(element, options);
                }
            }
        });
        AnimationFactory.current = new AnimationFactory();
        Animation.create = function (type, element, options) {
            return AnimationFactory.current.create(type, element, options);
        };
        var ShapeMap = {
            l: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                for (var i = 0; i < parameters.length; i += 2) {
                    var point = new Point(parameters[i], parameters[i + 1]);
                    if (options.isRelative) {
                        point.translateWith(position);
                    }
                    path.lineTo(point.x, point.y);
                    position.x = point.x;
                    position.y = point.y;
                }
            },
            c: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                for (var i = 0; i < parameters.length; i += 6) {
                    var controlOut = new Point(parameters[i], parameters[i + 1]);
                    var controlIn = new Point(parameters[i + 2], parameters[i + 3]);
                    var point = new Point(parameters[i + 4], parameters[i + 5]);
                    if (options.isRelative) {
                        controlIn.translateWith(position);
                        controlOut.translateWith(position);
                        point.translateWith(position);
                    }
                    path.curveTo(controlOut, controlIn, point);
                    position.x = point.x;
                    position.y = point.y;
                }
            },
            v: function (path, options) {
                var value = options.isRelative ? 0 : options.position.x;
                toLineParamaters(options.parameters, true, value);
                this.l(path, options);
            },
            h: function (path, options) {
                var value = options.isRelative ? 0 : options.position.y;
                toLineParamaters(options.parameters, false, value);
                this.l(path, options);
            },
            a: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                for (var i = 0; i < parameters.length; i += 7) {
                    var radiusX = parameters[i];
                    var radiusY = parameters[i + 1];
                    var 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 lastControlIn;
                if (previousCommand === 's' || previousCommand === 'c') {
                    lastControlIn = last(last(path.paths).segments).controlIn();
                }
                for (var i = 0; i < parameters.length; i += 4) {
                    var controlIn = new Point(parameters[i], parameters[i + 1]);
                    var endPoint = new Point(parameters[i + 2], parameters[i + 3]);
                    var controlOut = void 0;
                    if (options.isRelative) {
                        controlIn.translateWith(position);
                        endPoint.translateWith(position);
                    }
                    if (lastControlIn) {
                        controlOut = reflectionPoint(lastControlIn, position);
                    } else {
                        controlOut = position.clone();
                    }
                    lastControlIn = controlIn;
                    path.curveTo(controlOut, controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            },
            q: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                for (var i = 0; i < parameters.length; i += 4) {
                    var controlPoint = new Point(parameters[i], parameters[i + 1]);
                    var endPoint = new Point(parameters[i + 2], parameters[i + 3]);
                    if (options.isRelative) {
                        controlPoint.translateWith(position);
                        endPoint.translateWith(position);
                    }
                    var cubicControlPoints = quadraticToCubicControlPoints(position, controlPoint, endPoint);
                    path.curveTo(cubicControlPoints.controlOut, cubicControlPoints.controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            },
            t: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                var previousCommand = options.previousCommand;
                var controlPoint;
                if (previousCommand === 'q' || previousCommand === 't') {
                    var lastSegment = last(last(path.paths).segments);
                    controlPoint = lastSegment.controlIn().clone().translateWith(position.scaleCopy(-1 / 3)).scale(3 / 2);
                }
                for (var i = 0; i < parameters.length; i += 2) {
                    var endPoint = new Point(parameters[i], parameters[i + 1]);
                    if (options.isRelative) {
                        endPoint.translateWith(position);
                    }
                    if (controlPoint) {
                        controlPoint = reflectionPoint(controlPoint, position);
                    } else {
                        controlPoint = position.clone();
                    }
                    var cubicControlPoints = quadraticToCubicControlPoints(position, controlPoint, endPoint);
                    path.curveTo(cubicControlPoints.controlOut, cubicControlPoints.controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            }
        };
        function toLineParamaters(parameters, isVertical, value) {
            var insertPosition = isVertical ? 0 : 1;
            for (var i = 0; i < parameters.length; i += 2) {
                parameters.splice(i + insertPosition, 0, value);
            }
        }
        function reflectionPoint(point, center) {
            if (point && center) {
                return center.scaleCopy(2).translate(-point.x, -point.y);
            }
        }
        var third = 1 / 3;
        function quadraticToCubicControlPoints(position, controlPoint, endPoint) {
            var scaledPoint = controlPoint.clone().scale(2 / 3);
            return {
                controlOut: scaledPoint.clone().translateWith(position.scaleCopy(third)),
                controlIn: scaledPoint.translateWith(endPoint.scaleCopy(third))
            };
        }
        var SEGMENT_REGEX = /([a-df-z]{1})([^a-df-z]*)(z)?/gi;
        var SPLIT_REGEX = /[,\s]?([+\-]?(?:\d*\.\d+|\d+)(?:[eE][+\-]?\d+)?)/g;
        var MOVE = 'm';
        var CLOSE = 'z';
        function parseParameters(str) {
            var parameters = [];
            str.replace(SPLIT_REGEX, function (match, number) {
                parameters.push(parseFloat(number));
            });
            return parameters;
        }
        var PathParser = Class.extend({
            parse: function (str, options) {
                var multiPath = new MultiPath(options);
                var position = new Point();
                var previousCommand;
                str.replace(SEGMENT_REGEX, function (match, element, params, closePath) {
                    var command = element.toLowerCase();
                    var isRelative = command === element;
                    var parameters = parseParameters(params.trim());
                    if (command === MOVE) {
                        if (isRelative) {
                            position.x += parameters[0];
                            position.y += parameters[1];
                        } else {
                            position.x = parameters[0];
                            position.y = parameters[1];
                        }
                        multiPath.moveTo(position.x, position.y);
                        if (parameters.length > 2) {
                            command = 'l';
                            parameters.splice(0, 2);
                        }
                    }
                    if (ShapeMap[command]) {
                        ShapeMap[command](multiPath, {
                            parameters: parameters,
                            position: position,
                            isRelative: isRelative,
                            previousCommand: previousCommand
                        });
                        if (closePath && closePath.toLowerCase() === CLOSE) {
                            multiPath.close();
                        }
                    } else if (command !== MOVE) {
                        throw new Error('Error while parsing SVG path. Unsupported command: ' + command);
                    }
                    previousCommand = command;
                });
                return multiPath;
            }
        });
        PathParser.current = new PathParser();
        Path.parse = function (str, options) {
            return PathParser.current.parse(str, options);
        };
        var SurfaceFactory = Class.extend({
            init: function () {
                this._items = [];
            },
            register: function (name, type, order) {
                var items = this._items;
                var first = items[0];
                var entry = {
                    name: name,
                    type: type,
                    order: order
                };
                if (!first || order < first.order) {
                    items.unshift(entry);
                } else {
                    items.push(entry);
                }
            },
            create: function (element, options) {
                var items = this._items;
                var match = items[0];
                if (options && options.type) {
                    var preferred = options.type.toLowerCase();
                    for (var i = 0; i < items.length; i++) {
                        if (items[i].name === preferred) {
                            match = items[i];
                            break;
                        }
                    }
                }
                if (match) {
                    return new match.type(element, options);
                }
                kendo.logToConsole('Warning: Unable to create Kendo UI Drawing Surface. Possible causes:\n' + '- The browser does not support SVG and Canvas. User agent: ' + navigator.userAgent);
            }
        });
        SurfaceFactory.current = new SurfaceFactory();
        var events = [
            'click',
            'mouseenter',
            'mouseleave',
            'mousemove',
            'resize',
            'tooltipOpen',
            'tooltipClose'
        ];
        var Surface = kendo.Observable.extend({
            init: function (element, options) {
                kendo.Observable.fn.init.call(this);
                this.options = $.extend({}, options);
                this.element = element;
                this._click = this._handler('click');
                this._mouseenter = this._handler('mouseenter');
                this._mouseleave = this._handler('mouseleave');
                this._mousemove = this._handler('mousemove');
                this._visual = new Group();
                elementSize(element, this.options);
                this.bind(events, this.options);
                this._enableTracking();
            },
            draw: function (element) {
                this._visual.children.push(element);
            },
            clear: function () {
                this._visual.children = [];
            },
            destroy: function () {
                this._visual = null;
                this.unbind();
            },
            eventTarget: function (e) {
                var this$1 = this;
                var domNode = eventElement(e);
                var node;
                while (!node && domNode) {
                    node = domNode._kendoNode;
                    if (domNode === this$1.element) {
                        break;
                    }
                    domNode = domNode.parentElement;
                }
                if (node) {
                    return node.srcElement;
                }
            },
            exportVisual: function () {
                return this._visual;
            },
            getSize: function () {
                return elementSize(this.element);
            },
            currentSize: function (size) {
                if (size) {
                    this._size = size;
                } else {
                    return this._size;
                }
            },
            setSize: function (size) {
                elementSize(this.element, size);
                this.currentSize(size);
                this._resize();
            },
            resize: function (force) {
                var size = this.getSize();
                var currentSize = this.currentSize();
                if (force || (size.width > 0 || size.height > 0) && (!currentSize || size.width !== currentSize.width || size.height !== currentSize.height)) {
                    this.currentSize(size);
                    this._resize(size, force);
                    this.trigger('resize', size);
                }
            },
            size: function (value) {
                if (!value) {
                    return this.getSize();
                }
                this.setSize(value);
            },
            suspendTracking: function () {
                this._suspendedTracking = true;
            },
            resumeTracking: function () {
                this._suspendedTracking = false;
            },
            _enableTracking: function () {
            },
            _resize: function () {
            },
            _handler: function (eventName) {
                var this$1 = this;
                return function (e) {
                    var node = this$1.eventTarget(e);
                    if (node && !this$1._suspendedTracking) {
                        this$1.trigger(eventName, {
                            element: node,
                            originalEvent: e,
                            type: eventName
                        });
                    }
                };
            },
            _elementOffset: function () {
                var element = this.element;
                var ref = elementStyles(element, [
                    'paddingLeft',
                    'paddingTop'
                ]);
                var paddingLeft = ref.paddingLeft;
                var paddingTop = ref.paddingTop;
                var ref$1 = elementOffset(element);
                var left = ref$1.left;
                var top = ref$1.top;
                return {
                    left: left + parseInt(paddingLeft, 10),
                    top: top + parseInt(paddingTop, 10)
                };
            },
            _surfacePoint: function (e) {
                var offset = this._elementOffset();
                var coord = eventCoordinates(e);
                var x = coord.x - offset.left;
                var y = coord.y - offset.top;
                return new Point(x, y);
            }
        });
        Surface.create = function (element, options) {
            return SurfaceFactory.current.create(element, options);
        };
        Surface.support = {};
        var BaseNode = Class.extend({
            init: function (srcElement) {
                this.childNodes = [];
                this.parent = null;
                if (srcElement) {
                    this.srcElement = srcElement;
                    this.observe();
                }
            },
            destroy: function () {
                var this$1 = this;
                if (this.srcElement) {
                    this.srcElement.removeObserver(this);
                }
                var children = this.childNodes;
                for (var i = 0; i < children.length; i++) {
                    this$1.childNodes[i].destroy();
                }
                this.parent = null;
            },
            load: function () {
            },
            observe: function () {
                if (this.srcElement) {
                    this.srcElement.addObserver(this);
                }
            },
            append: function (node) {
                this.childNodes.push(node);
                node.parent = this;
            },
            insertAt: function (node, pos) {
                this.childNodes.splice(pos, 0, node);
                node.parent = this;
            },
            remove: function (index, count) {
                var this$1 = this;
                var end = index + count;
                for (var i = index; i < end; i++) {
                    this$1.childNodes[i].removeSelf();
                }
                this.childNodes.splice(index, count);
            },
            removeSelf: function () {
                this.clear();
                this.destroy();
            },
            clear: function () {
                this.remove(0, this.childNodes.length);
            },
            invalidate: function () {
                if (this.parent) {
                    this.parent.invalidate();
                }
            },
            geometryChange: function () {
                this.invalidate();
            },
            optionsChange: function () {
                this.invalidate();
            },
            childrenChange: function (e) {
                if (e.action === 'add') {
                    this.load(e.items, e.index);
                } else if (e.action === 'remove') {
                    this.remove(e.index, e.items.length);
                }
                this.invalidate();
            }
        });
        function renderAttr(name, value) {
            return defined(value) && value !== null ? ' ' + name + '=\'' + value + '\' ' : '';
        }
        function renderAllAttr(attrs) {
            var output = '';
            for (var i = 0; i < attrs.length; i++) {
                output += renderAttr(attrs[i][0], attrs[i][1]);
            }
            return output;
        }
        function renderStyle(attrs) {
            var output = '';
            for (var i = 0; i < attrs.length; i++) {
                var value = attrs[i][1];
                if (defined(value)) {
                    output += attrs[i][0] + ':' + value + ';';
                }
            }
            if (output !== '') {
                return output;
            }
        }
        var NODE_MAP = {};
        var SVG_NS = 'http://www.w3.org/2000/svg';
        var NONE = 'none';
        var renderSVG = function (container, svg) {
            container.innerHTML = svg;
        };
        if (typeof document !== 'undefined') {
            var testFragment = '<svg xmlns=\'' + SVG_NS + '\'></svg>';
            var testContainer = document.createElement('div');
            var hasParser = typeof DOMParser !== 'undefined';
            testContainer.innerHTML = testFragment;
            if (hasParser && testContainer.firstChild.namespaceURI !== SVG_NS) {
                renderSVG = function (container, svg) {
                    var parser = new DOMParser();
                    var chartDoc = parser.parseFromString(svg, 'text/xml');
                    var importedDoc = document.adoptNode(chartDoc.documentElement);
                    container.innerHTML = '';
                    container.appendChild(importedDoc);
                };
            }
        }
        var renderSVG$1 = renderSVG;
        var TRANSFORM = 'transform';
        var DefinitionMap = {
            clip: 'clip-path',
            fill: 'fill'
        };
        function isDefinition(type, value) {
            return type === 'clip' || type === 'fill' && (!value || value.nodeType === 'Gradient');
        }
        function baseUrl() {
            var base = document.getElementsByTagName('base')[0];
            var href = document.location.href;
            var hashIndex = href.indexOf('#');
            var url = '';
            if (base && !support.browser.msie) {
                if (hashIndex !== -1) {
                    href = href.substring(0, hashIndex);
                }
                url = href;
            }
            return url;
        }
        function refUrl(id) {
            return 'url(' + baseUrl() + '#' + id + ')';
        }
        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 this$1 = this;
                for (var i = 0; i < elements.length; i++) {
                    var srcElement = elements[i];
                    var children = srcElement.children;
                    var childNode = new NODE_MAP[srcElement.nodeType](srcElement);
                    if (defined(pos)) {
                        this$1.insertAt(childNode, pos);
                    } else {
                        this$1.append(childNode);
                    }
                    childNode.createDefinitions();
                    if (children && children.length > 0) {
                        childNode.load(children);
                    }
                    var element = this$1.element;
                    if (element) {
                        childNode.attachTo(element, pos);
                    }
                }
            },
            root: function () {
                var root = this;
                while (root.parent) {
                    root = root.parent;
                }
                return root;
            },
            attachTo: function (domElement, pos) {
                var container = document.createElement('div');
                renderSVG$1(container, '<svg xmlns=\'' + SVG_NS + '\' version=\'1.1\'>' + this.render() + '</svg>');
                var element = container.firstChild.firstChild;
                if (element) {
                    if (defined(pos)) {
                        domElement.insertBefore(element, domElement.childNodes[pos] || null);
                    } else {
                        domElement.appendChild(element);
                    }
                    this.setElement(element);
                }
            },
            setElement: function (element) {
                if (this.element) {
                    this.element._kendoNode = null;
                }
                this.element = element;
                this.element._kendoNode = this;
                var nodes = this.childNodes;
                for (var i = 0; i < nodes.length; i++) {
                    var childElement = element.childNodes[i];
                    nodes[i].setElement(childElement);
                }
            },
            clear: function () {
                this.clearDefinitions();
                if (this.element) {
                    this.element.innerHTML = '';
                }
                var children = this.childNodes;
                for (var i = 0; i < children.length; i++) {
                    children[i].destroy();
                }
                this.childNodes = [];
            },
            removeSelf: function () {
                if (this.element) {
                    var parentNode = this.element.parentNode;
                    if (parentNode) {
                        parentNode.removeChild(this.element);
                    }
                    this.element = null;
                }
                BaseNode.fn.removeSelf.call(this);
            },
            template: function () {
                return this.renderChildren();
            },
            render: function () {
                return this.template();
            },
            renderChildren: function () {
                var nodes = this.childNodes;
                var output = '';
                for (var i = 0; i < nodes.length; i++) {
                    output += nodes[i].render();
                }
                return output;
            },
            optionsChange: function (e) {
                var field = e.field;
                var value = e.value;
                if (field === 'visible') {
                    this.css('display', value ? '' : NONE);
                } else if (DefinitionMap[field] && isDefinition(field, value)) {
                    this.updateDefinition(field, value);
                } else if (field === 'opacity') {
                    this.attr('opacity', value);
                } else if (field === 'cursor') {
                    this.css('cursor', value);
                }
                BaseNode.fn.optionsChange.call(this, e);
            },
            attr: function (name, value) {
                if (this.element) {
                    this.element.setAttribute(name, value);
                }
            },
            allAttr: function (attrs) {
                var this$1 = this;
                for (var i = 0; i < attrs.length; i++) {
                    this$1.attr(attrs[i][0], attrs[i][1]);
                }
            },
            css: function (name, value) {
                if (this.element) {
                    this.element.style[name] = value;
                }
            },
            allCss: function (styles) {
                var this$1 = this;
                for (var i = 0; i < styles.length; i++) {
                    this$1.css(styles[i][0], styles[i][1]);
                }
            },
            removeAttr: function (name) {
                if (this.element) {
                    this.element.removeAttribute(name);
                }
            },
            mapTransform: function (transform) {
                var attrs = [];
                if (transform) {
                    attrs.push([
                        TRANSFORM,
                        'matrix(' + transform.matrix().toString(6) + ')'
                    ]);
                }
                return attrs;
            },
            renderTransform: function () {
                return renderAllAttr(this.mapTransform(this.srcElement.transform()));
            },
            transformChange: function (value) {
                if (value) {
                    this.allAttr(this.mapTransform(value));
                } else {
                    this.removeAttr(TRANSFORM);
                }
            },
            mapStyle: function () {
                var options = this.srcElement.options;
                var style = [[
                        'cursor',
                        options.cursor
                    ]];
                if (options.visible === false) {
                    style.push([
                        'display',
                        NONE
                    ]);
                }
                return style;
            },
            renderStyle: function () {
                return renderAttr('style', renderStyle(this.mapStyle(true)));
            },
            renderOpacity: function () {
                return renderAttr('opacity', this.srcElement.options.opacity);
            },
            createDefinitions: function () {
                var srcElement = this.srcElement;
                var definitions = this.definitions;
                if (srcElement) {
                    var options = srcElement.options;
                    var hasDefinitions;
                    for (var field in DefinitionMap) {
                        var definition = options.get(field);
                        if (definition && isDefinition(field, definition)) {
                            definitions[field] = definition;
                            hasDefinitions = true;
                        }
                    }
                    if (hasDefinitions) {
                        this.definitionChange({
                            action: 'add',
                            definitions: definitions
                        });
                    }
                }
            },
            definitionChange: function (e) {
                if (this.parent) {
                    this.parent.definitionChange(e);
                }
            },
            updateDefinition: function (type, value) {
                var definitions = this.definitions;
                var current = definitions[type];
                var attr = DefinitionMap[type];
                var definition = {};
                if (current) {
                    definition[type] = current;
                    this.definitionChange({
                        action: 'remove',
                        definitions: definition
                    });
                    delete definitions[type];
                }
                if (!value) {
                    if (current) {
                        this.removeAttr(attr);
                    }
                } else {
                    definition[type] = value;
                    this.definitionChange({
                        action: 'add',
                        definitions: definition
                    });
                    definitions[type] = value;
                    this.attr(attr, refUrl(value.id));
                }
            },
            clearDefinitions: function () {
                var definitions = this.definitions;
                this.definitionChange({
                    action: 'remove',
                    definitions: definitions
                });
                this.definitions = {};
            },
            renderDefinitions: function () {
                return renderAllAttr(this.mapDefinitions());
            },
            mapDefinitions: function () {
                var definitions = this.definitions;
                var attrs = [];
                for (var field in definitions) {
                    attrs.push([
                        DefinitionMap[field],
                        refUrl(definitions[field].id)
                    ]);
                }
                return attrs;
            }
        });
        var GradientStopNode = Node.extend({
            template: function () {
                return '<stop ' + this.renderOffset() + ' ' + this.renderStyle() + ' />';
            },
            renderOffset: function () {
                return renderAttr('offset', this.srcElement.offset());
            },
            mapStyle: function () {
                var srcElement = this.srcElement;
                return [
                    [
                        'stop-color',
                        srcElement.color()
                    ],
                    [
                        'stop-opacity',
                        srcElement.opacity()
                    ]
                ];
            },
            optionsChange: function (e) {
                if (e.field === 'offset') {
                    this.attr(e.field, e.value);
                } else if (e.field === 'color' || e.field === 'opacity') {
                    this.css('stop-' + e.field, e.value);
                }
            }
        });
        var GradientNode = Node.extend({
            init: function (srcElement) {
                Node.fn.init.call(this, srcElement);
                this.id = srcElement.id;
                this.loadStops();
            },
            loadStops: function () {
                var this$1 = this;
                var stops = this.srcElement.stops;
                var element = this.element;
                for (var idx = 0; idx < stops.length; idx++) {
                    var stopNode = new GradientStopNode(stops[idx]);
                    this$1.append(stopNode);
                    if (element) {
                        stopNode.attachTo(element);
                    }
                }
            },
            optionsChange: function (e) {
                if (e.field === 'gradient.stops') {
                    BaseNode.prototype.clear.call(this);
                    this.loadStops();
                } else if (e.field === 'gradient') {
                    this.allAttr(this.mapCoordinates());
                }
            },
            renderCoordinates: function () {
                return renderAllAttr(this.mapCoordinates());
            },
            mapSpace: function () {
                return [
                    'gradientUnits',
                    this.srcElement.userSpace() ? 'userSpaceOnUse' : 'objectBoundingBox'
                ];
            }
        });
        var LinearGradientNode = GradientNode.extend({
            template: function () {
                return '<linearGradient id=\'' + this.id + '\' ' + this.renderCoordinates() + '>' + this.renderChildren() + '</linearGradient>';
            },
            mapCoordinates: function () {
                var srcElement = this.srcElement;
                var start = srcElement.start();
                var end = srcElement.end();
                var attrs = [
                    [
                        'x1',
                        start.x
                    ],
                    [
                        'y1',
                        start.y
                    ],
                    [
                        'x2',
                        end.x
                    ],
                    [
                        'y2',
                        end.y
                    ],
                    this.mapSpace()
                ];
                return attrs;
            }
        });
        var RadialGradientNode = GradientNode.extend({
            template: function () {
                return '<radialGradient id=\'' + this.id + '\' ' + this.renderCoordinates() + '>' + this.renderChildren() + '</radialGradient>';
            },
            mapCoordinates: function () {
                var srcElement = this.srcElement;
                var center = srcElement.center();
                var radius = srcElement.radius();
                var attrs = [
                    [
                        'cx',
                        center.x
                    ],
                    [
                        'cy',
                        center.y
                    ],
                    [
                        'r',
                        radius
                    ],
                    this.mapSpace()
                ];
                return attrs;
            }
        });
        var ClipNode = Node.extend({
            init: function (srcElement) {
                Node.fn.init.call(this);
                this.srcElement = srcElement;
                this.id = srcElement.id;
                this.load([srcElement]);
            },
            template: function () {
                return '<clipPath id=\'' + this.id + '\'>' + this.renderChildren() + '</clipPath>';
            }
        });
        var DefinitionNode = Node.extend({
            init: function () {
                Node.fn.init.call(this);
                this.definitionMap = {};
            },
            attachTo: function (domElement) {
                this.element = domElement;
            },
            template: function () {
                return '<defs>' + this.renderChildren() + '</defs>';
            },
            definitionChange: function (e) {
                var definitions = e.definitions;
                var action = e.action;
                if (action === 'add') {
                    this.addDefinitions(definitions);
                } else if (action === 'remove') {
                    this.removeDefinitions(definitions);
                }
            },
            createDefinition: function (type, item) {
                var nodeType;
                if (type === 'clip') {
                    nodeType = ClipNode;
                } else if (type === 'fill') {
                    if (item instanceof LinearGradient) {
                        nodeType = LinearGradientNode;
                    } else if (item instanceof RadialGradient) {
                        nodeType = RadialGradientNode;
                    }
                }
                return new nodeType(item);
            },
            addDefinitions: function (definitions) {
                var this$1 = this;
                for (var field in definitions) {
                    this$1.addDefinition(field, definitions[field]);
                }
            },
            addDefinition: function (type, srcElement) {
                var ref = this;
                var element = ref.element;
                var definitionMap = ref.definitionMap;
                var id = srcElement.id;
                var mapItem = definitionMap[id];
                if (!mapItem) {
                    var node = this.createDefinition(type, srcElement);
                    definitionMap[id] = {
                        element: node,
                        count: 1
                    };
                    this.append(node);
                    if (element) {
                        node.attachTo(this.element);
                    }
                } else {
                    mapItem.count++;
                }
            },
            removeDefinitions: function (definitions) {
                var this$1 = this;
                for (var field in definitions) {
                    this$1.removeDefinition(definitions[field]);
                }
            },
            removeDefinition: function (srcElement) {
                var definitionMap = this.definitionMap;
                var id = srcElement.id;
                var mapItem = definitionMap[id];
                if (mapItem) {
                    mapItem.count--;
                    if (mapItem.count === 0) {
                        this.remove(this.childNodes.indexOf(mapItem.element), 1);
                        delete definitionMap[id];
                    }
                }
            }
        });
        var RootNode = Node.extend({
            init: function (options) {
                Node.fn.init.call(this);
                this.options = options;
                this.defs = new DefinitionNode();
            },
            attachTo: function (domElement) {
                this.element = domElement;
                this.defs.attachTo(domElement.firstElementChild);
            },
            clear: function () {
                BaseNode.prototype.clear.call(this);
            },
            template: function () {
                return this.defs.render() + this.renderChildren();
            },
            definitionChange: function (e) {
                this.defs.definitionChange(e);
            }
        });
        function alignToScreen(element) {
            var ctm;
            try {
                ctm = element.getScreenCTM ? element.getScreenCTM() : null;
            } catch (e) {
            }
            if (ctm) {
                var left = -ctm.e % 1;
                var top = -ctm.f % 1;
                var style = element.style;
                if (left !== 0 || top !== 0) {
                    style.left = left + 'px';
                    style.top = top + 'px';
                }
            }
        }
        var Surface$1 = Surface.extend({
            init: function (element, options) {
                Surface.fn.init.call(this, element, options);
                this._root = new RootNode(this.options);
                renderSVG$1(this.element, this._template());
                this._rootElement = this.element.firstElementChild;
                alignToScreen(this._rootElement);
                this._root.attachTo(this._rootElement);
                bindEvents(this.element, {
                    click: this._click,
                    mouseover: this._mouseenter,
                    mouseout: this._mouseleave,
                    mousemove: this._mousemove
                });
                this.resize();
            },
            destroy: function () {
                if (this._root) {
                    this._root.destroy();
                    this._root = null;
                    this._rootElement = null;
                    unbindEvents(this.element, {
                        click: this._click,
                        mouseover: this._mouseenter,
                        mouseout: this._mouseleave,
                        mousemove: this._mousemove
                    });
                }
                Surface.fn.destroy.call(this);
            },
            translate: function (offset) {
                var viewBox = Math.round(offset.x) + ' ' + Math.round(offset.y) + ' ' + this._size.width + ' ' + this._size.height;
                this._offset = offset;
                this._rootElement.setAttribute('viewBox', viewBox);
            },
            draw: function (element) {
                Surface.fn.draw.call(this, element);
                this._root.load([element]);
            },
            clear: function () {
                Surface.fn.clear.call(this);
                this._root.clear();
            },
            svg: function () {
                return '<?xml version=\'1.0\' ?>' + this._template();
            },
            exportVisual: function () {
                var ref = this;
                var visual = ref._visual;
                var offset = ref._offset;
                if (offset) {
                    var wrap = new Group();
                    wrap.children.push(visual);
                    wrap.transform(transform().translate(-offset.x, -offset.y));
                    visual = wrap;
                }
                return visual;
            },
            _resize: function () {
                if (this._offset) {
                    this.translate(this._offset);
                }
            },
            _template: function () {
                return '<svg style=\'width: 100%; height: 100%; overflow: hidden;\' xmlns=\'' + SVG_NS + '\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' version=\'1.1\'>' + this._root.render() + '</svg>';
            }
        });
        Surface$1.prototype.type = 'svg';
        if (typeof document !== 'undefined' && document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1')) {
            Surface.support.svg = true;
            SurfaceFactory.current.register('svg', Surface$1, 10);
        }
        var GroupNode = Node.extend({
            template: function () {
                return '<g' + (this.renderTransform() + this.renderStyle() + this.renderOpacity() + this.renderDefinitions()) + '>' + this.renderChildren() + '</g>';
            },
            optionsChange: function (e) {
                if (e.field === 'transform') {
                    this.transformChange(e.value);
                }
                Node.fn.optionsChange.call(this, e);
            }
        });
        NODE_MAP.Group = GroupNode;
        var DASH_ARRAYS = {
            dot: [
                1.5,
                3.5
            ],
            dash: [
                4,
                3.5
            ],
            longdash: [
                8,
                3.5
            ],
            dashdot: [
                3.5,
                3.5,
                1.5,
                3.5
            ],
            longdashdot: [
                8,
                3.5,
                1.5,
                3.5
            ],
            longdashdotdot: [
                8,
                3.5,
                1.5,
                3.5,
                1.5,
                3.5
            ]
        };
        var SOLID = 'solid';
        var BUTT = 'butt';
        var ATTRIBUTE_MAP = {
            'fill.opacity': 'fill-opacity',
            'stroke.color': 'stroke',
            'stroke.width': 'stroke-width',
            'stroke.opacity': 'stroke-opacity'
        };
        var SPACE = ' ';
        var PathNode = Node.extend({
            geometryChange: function () {
                this.attr('d', this.renderData());
                this.invalidate();
            },
            optionsChange: function (e) {
                switch (e.field) {
                case 'fill':
                    if (e.value) {
                        this.allAttr(this.mapFill(e.value));
                    } else {
                        this.removeAttr('fill');
                    }
                    break;
                case 'fill.color':
                    this.allAttr(this.mapFill({ color: e.value }));
                    break;
                case 'stroke':
                    if (e.value) {
                        this.allAttr(this.mapStroke(e.value));
                    } else {
                        this.removeAttr('stroke');
                    }
                    break;
                case 'transform':
                    this.transformChange(e.value);
                    break;
                default:
                    var name = ATTRIBUTE_MAP[e.field];
                    if (name) {
                        this.attr(name, e.value);
                    }
                    break;
                }
                Node.fn.optionsChange.call(this, e);
            },
            content: function () {
                if (this.element) {
                    this.element.textContent = this.srcElement.content();
                }
            },
            renderData: function () {
                return this.printPath(this.srcElement);
            },
            printPath: function (path) {
                var this$1 = this;
                var segments = path.segments;
                var length = segments.length;
                if (length > 0) {
                    var parts = [];
                    var output, currentType;
                    for (var i = 1; i < length; i++) {
                        var segmentType = this$1.segmentType(segments[i - 1], segments[i]);
                        if (segmentType !== currentType) {
                            currentType = segmentType;
                            parts.push(segmentType);
                        }
                        if (segmentType === 'L') {
                            parts.push(this$1.printPoints(segments[i].anchor()));
                        } else {
                            parts.push(this$1.printPoints(segments[i - 1].controlOut(), segments[i].controlIn(), segments[i].anchor()));
                        }
                    }
                    output = 'M' + this.printPoints(segments[0].anchor()) + SPACE + parts.join(SPACE);
                    if (path.options.closed) {
                        output += 'Z';
                    }
                    return output;
                }
            },
            printPoints: function () {
                var points = arguments;
                var length = points.length;
                var result = [];
                for (var i = 0; i < length; i++) {
                    result.push(points[i].toString(3));
                }
                return result.join(' ');
            },
            segmentType: function (segmentStart, segmentEnd) {
                return segmentStart.controlOut() && segmentEnd.controlIn() ? 'C' : 'L';
            },
            mapStroke: function (stroke) {
                var attrs = [];
                if (stroke && !isTransparent(stroke.color)) {
                    attrs.push([
                        'stroke',
                        stroke.color
                    ]);
                    attrs.push([
                        'stroke-width',
                        stroke.width
                    ]);
                    attrs.push([
                        'stroke-linecap',
                        this.renderLinecap(stroke)
                    ]);
                    attrs.push([
                        'stroke-linejoin',
                        stroke.lineJoin
                    ]);
                    if (defined(stroke.opacity)) {
                        attrs.push([
                            'stroke-opacity',
                            stroke.opacity
                        ]);
                    }
                    if (defined(stroke.dashType)) {
                        attrs.push([
                            'stroke-dasharray',
                            this.renderDashType(stroke)
                        ]);
                    }
                } else {
                    attrs.push([
                        'stroke',
                        NONE
                    ]);
                }
                return attrs;
            },
            renderStroke: function () {
                return renderAllAttr(this.mapStroke(this.srcElement.options.stroke));
            },
            renderDashType: function (stroke) {
                var dashType = stroke.dashType;
                var width = stroke.width;
                if (width === void 0) {
                    width = 1;
                }
                if (dashType && dashType !== SOLID) {
                    var dashArray = DASH_ARRAYS[dashType.toLowerCase()];
                    var result = [];
                    for (var i = 0; i < dashArray.length; i++) {
                        result.push(dashArray[i] * width);
                    }
                    return result.join(' ');
                }
            },
            renderLinecap: function (stroke) {
                var dashType = stroke.dashType;
                var lineCap = stroke.lineCap;
                return dashType && dashType !== 'solid' ? BUTT : lineCap;
            },
            mapFill: function (fill) {
                var attrs = [];
                if (!(fill && fill.nodeType === 'Gradient')) {
                    if (fill && !isTransparent(fill.color)) {
                        attrs.push([
                            'fill',
                            fill.color
                        ]);
                        if (defined(fill.opacity)) {
                            attrs.push([
                                'fill-opacity',
                                fill.opacity
                            ]);
                        }
                    } else {
                        attrs.push([
                            'fill',
                            NONE
                        ]);
                    }
                }
                return attrs;
            },
            renderFill: function () {
                return renderAllAttr(this.mapFill(this.srcElement.options.fill));
            },
            template: function () {
                return '<path ' + this.renderStyle() + ' ' + this.renderOpacity() + ' ' + renderAttr('d', this.renderData()) + '' + this.renderStroke() + this.renderFill() + this.renderDefinitions() + this.renderTransform() + '></path>';
            }
        });
        NODE_MAP.Path = PathNode;
        var ArcNode = PathNode.extend({
            renderData: function () {
                return this.printPath(this.srcElement.toPath());
            }
        });
        NODE_MAP.Arc = ArcNode;
        var CircleNode = PathNode.extend({
            geometryChange: function () {
                var center = this.center();
                this.attr('cx', center.x);
                this.attr('cy', center.y);
                this.attr('r', this.radius());
                this.invalidate();
            },
            center: function () {
                return this.srcElement.geometry().center;
            },
            radius: function () {
                return this.srcElement.geometry().radius;
            },
            template: function () {
                return '<circle ' + this.renderStyle() + ' ' + this.renderOpacity() + 'cx=\'' + this.center().x + '\' cy=\'' + this.center().y + '\' r=\'' + this.radius() + '\'' + this.renderStroke() + ' ' + this.renderFill() + ' ' + this.renderDefinitions() + this.renderTransform() + ' ></circle>';
            }
        });
        NODE_MAP.Circle = CircleNode;
        var RectNode = PathNode.extend({
            geometryChange: function () {
                var geometry = this.srcElement.geometry();
                this.attr('x', geometry.origin.x);
                this.attr('y', geometry.origin.y);
                this.attr('width', geometry.size.width);
                this.attr('height', geometry.size.height);
                this.invalidate();
            },
            size: function () {
                return this.srcElement.geometry().size;
            },
            origin: function () {
                return this.srcElement.geometry().origin;
            },
            template: function () {
                return '<rect ' + this.renderStyle() + ' ' + this.renderOpacity() + ' x=\'' + this.origin().x + '\' y=\'' + this.origin().y + '\' ' + 'width=\'' + this.size().width + '\' height=\'' + this.size().height + '\' ' + this.renderStroke() + ' ' + this.renderFill() + ' ' + this.renderDefinitions() + ' ' + this.renderTransform() + ' />';
            }
        });
        NODE_MAP.Rect = RectNode;
        var ImageNode = PathNode.extend({
            geometryChange: function () {
                this.allAttr(this.mapPosition());
                this.invalidate();
            },
            optionsChange: function (e) {
                if (e.field === 'src') {
                    this.allAttr(this.mapSource());
                }
                PathNode.fn.optionsChange.call(this, e);
            },
            mapPosition: function () {
                var rect = this.srcElement.rect();
                var tl = rect.topLeft();
                return [
                    [
                        'x',
                        tl.x
                    ],
                    [
                        'y',
                        tl.y
                    ],
                    [
                        'width',
                        rect.width() + 'px'
                    ],
                    [
                        'height',
                        rect.height() + 'px'
                    ]
                ];
            },
            renderPosition: function () {
                return renderAllAttr(this.mapPosition());
            },
            mapSource: function (encode) {
                var src = this.srcElement.src();
                if (encode) {
                    src = kendo.htmlEncode(src);
                }
                return [[
                        'xlink:href',
                        src
                    ]];
            },
            renderSource: function () {
                return renderAllAttr(this.mapSource(true));
            },
            template: function () {
                return '<image preserveAspectRatio=\'none\' ' + this.renderStyle() + ' ' + this.renderTransform() + ' ' + this.renderOpacity() + this.renderPosition() + ' ' + this.renderSource() + ' ' + this.renderDefinitions() + '>' + '</image>';
            }
        });
        NODE_MAP.Image = ImageNode;
        function decodeEntities(text) {
            if (!text || !text.indexOf || text.indexOf('&') < 0) {
                return text;
            }
            var element = decodeEntities._element;
            element.innerHTML = text;
            return element.textContent || element.innerText;
        }
        if (typeof document !== 'undefined') {
            decodeEntities._element = document.createElement('span');
        }
        var TextNode = PathNode.extend({
            geometryChange: function () {
                var pos = this.pos();
                this.attr('x', pos.x);
                this.attr('y', pos.y);
                this.invalidate();
            },
            optionsChange: function (e) {
                if (e.field === 'font') {
                    this.attr('style', renderStyle(this.mapStyle()));
                    this.geometryChange();
                } else if (e.field === 'content') {
                    PathNode.fn.content.call(this, this.srcElement.content());
                }
                PathNode.fn.optionsChange.call(this, e);
            },
            mapStyle: function (encode) {
                var style = PathNode.fn.mapStyle.call(this, encode);
                var font = this.srcElement.options.font;
                if (encode) {
                    font = kendo.htmlEncode(font);
                }
                style.push([
                    'font',
                    font
                ]);
                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: function () {
                return '<text ' + this.renderStyle() + ' ' + this.renderOpacity() + ' x=\'' + this.pos().x + '\' y=\'' + this.pos().y + '\'' + this.renderStroke() + ' ' + this.renderTransform() + ' ' + this.renderDefinitions() + this.renderFill() + '>' + this.renderContent() + '</text>';
            }
        });
        NODE_MAP.Text = TextNode;
        var MultiPathNode = PathNode.extend({
            renderData: function () {
                var this$1 = this;
                var paths = this.srcElement.paths;
                if (paths.length > 0) {
                    var result = [];
                    for (var i = 0; i < paths.length; i++) {
                        result.push(this$1.printPath(paths[i]));
                    }
                    return result.join(' ');
                }
            }
        });
        NODE_MAP.MultiPath = MultiPathNode;
        var geometry = {
            Circle: Circle$2,
            Arc: Arc$2,
            Rect: Rect,
            Point: Point,
            Segment: Segment,
            Matrix: Matrix,
            Size: Size,
            toMatrix: toMatrix,
            Transformation: Transformation,
            transform: transform
        };
        function exportGroup(group) {
            var root = new RootNode();
            var bbox = group.clippedBBox();
            var rootGroup = group;
            if (bbox) {
                var origin = bbox.getOrigin();
                var exportRoot = new Group();
                exportRoot.transform(transform().translate(-origin.x, -origin.y));
                exportRoot.children.push(group);
                rootGroup = exportRoot;
            }
            root.load([rootGroup]);
            var svg = '<?xml version=\'1.0\' ?><svg xmlns=\'' + SVG_NS + '\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' version=\'1.1\'>' + root.render() + '</svg>';
            root.destroy();
            return svg;
        }
        var svg = {
            Surface: Surface$1,
            RootNode: RootNode,
            Node: Node,
            GroupNode: GroupNode,
            ArcNode: ArcNode,
            CircleNode: CircleNode,
            RectNode: RectNode,
            ImageNode: ImageNode,
            TextNode: TextNode,
            PathNode: PathNode,
            MultiPathNode: MultiPathNode,
            DefinitionNode: DefinitionNode,
            ClipNode: ClipNode,
            GradientStopNode: GradientStopNode,
            LinearGradientNode: LinearGradientNode,
            RadialGradientNode: RadialGradientNode,
            exportGroup: exportGroup
        };
        var NODE_MAP$2 = {};
        function renderPath(ctx, path) {
            var segments = path.segments;
            if (segments.length === 0) {
                return;
            }
            var segment = segments[0];
            var anchor = segment.anchor();
            ctx.moveTo(anchor.x, anchor.y);
            for (var i = 1; i < segments.length; i++) {
                segment = segments[i];
                anchor = segment.anchor();
                var prevSeg = segments[i - 1];
                var prevOut = prevSeg.controlOut();
                var controlIn = segment.controlIn();
                if (prevOut && controlIn) {
                    ctx.bezierCurveTo(prevOut.x, prevOut.y, controlIn.x, controlIn.y, anchor.x, anchor.y);
                } else {
                    ctx.lineTo(anchor.x, anchor.y);
                }
            }
            if (path.options.closed) {
                ctx.closePath();
            }
        }
        var Node$2 = BaseNode.extend({
            init: function (srcElement) {
                BaseNode.fn.init.call(this, srcElement);
                if (srcElement) {
                    this.initClip();
                }
            },
            initClip: function () {
                var clip = this.srcElement.clip();
                if (clip) {
                    this.clip = clip;
                    clip.addObserver(this);
                }
            },
            clear: function () {
                if (this.srcElement) {
                    this.srcElement.removeObserver(this);
                }
                this.clearClip();
                BaseNode.fn.clear.call(this);
            },
            clearClip: function () {
                if (this.clip) {
                    this.clip.removeObserver(this);
                    delete this.clip;
                }
            },
            setClip: function (ctx) {
                if (this.clip) {
                    ctx.beginPath();
                    renderPath(ctx, this.clip);
                    ctx.clip();
                }
            },
            optionsChange: function (e) {
                if (e.field === 'clip') {
                    this.clearClip();
                    this.initClip();
                }
                BaseNode.fn.optionsChange.call(this, e);
            },
            setTransform: function (ctx) {
                if (this.srcElement) {
                    var transform = this.srcElement.transform();
                    if (transform) {
                        ctx.transform.apply(ctx, transform.matrix().toArray(6));
                    }
                }
            },
            loadElements: function (elements, pos, cors) {
                var this$1 = this;
                for (var i = 0; i < elements.length; i++) {
                    var srcElement = elements[i];
                    var children = srcElement.children;
                    var childNode = new NODE_MAP$2[srcElement.nodeType](srcElement, cors);
                    if (children && children.length > 0) {
                        childNode.load(children, pos, cors);
                    }
                    if (defined(pos)) {
                        this$1.insertAt(childNode, pos);
                    } else {
                        this$1.append(childNode);
                    }
                }
            },
            load: function (elements, pos, cors) {
                this.loadElements(elements, pos, cors);
                this.invalidate();
            },
            setOpacity: function (ctx) {
                if (this.srcElement) {
                    var opacity = this.srcElement.opacity();
                    if (defined(opacity)) {
                        this.globalAlpha(ctx, opacity);
                    }
                }
            },
            globalAlpha: function (ctx, value) {
                var opactity = value;
                if (opactity && ctx.globalAlpha) {
                    opactity *= ctx.globalAlpha;
                }
                ctx.globalAlpha = opactity;
            },
            visible: function () {
                var src = this.srcElement;
                return !src || src && src.options.visible !== false;
            }
        });
        var GroupNode$2 = Node$2.extend({
            renderTo: function (ctx) {
                if (!this.visible()) {
                    return;
                }
                ctx.save();
                this.setTransform(ctx);
                this.setClip(ctx);
                this.setOpacity(ctx);
                var childNodes = this.childNodes;
                for (var i = 0; i < childNodes.length; i++) {
                    var child = childNodes[i];
                    if (child.visible()) {
                        child.renderTo(ctx);
                    }
                }
                ctx.restore();
            }
        });
        Traversable.extend(GroupNode$2.prototype, 'childNodes');
        NODE_MAP$2.Group = GroupNode$2;
        var FRAME_DELAY = 1000 / 60;
        var RootNode$2 = GroupNode$2.extend({
            init: function (canvas) {
                GroupNode$2.fn.init.call(this);
                this.canvas = canvas;
                this.ctx = canvas.getContext('2d');
                var invalidateHandler = this._invalidate.bind(this);
                this.invalidate = kendo.throttle(function () {
                    kendo.animationFrame(invalidateHandler);
                }, FRAME_DELAY);
            },
            destroy: function () {
                GroupNode$2.fn.destroy.call(this);
                this.canvas = null;
                this.ctx = null;
            },
            load: function (elements, pos, cors) {
                this.loadElements(elements, pos, cors);
                this._invalidate();
            },
            _invalidate: function () {
                if (!this.ctx) {
                    return;
                }
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                this.renderTo(this.ctx);
            }
        });
        Traversable.extend(RootNode$2.prototype, 'childNodes');
        var QuadRoot = Class.extend({
            init: function () {
                this.shapes = [];
            },
            _add: function (shape, bbox) {
                this.shapes.push({
                    bbox: bbox,
                    shape: shape
                });
                shape._quadNode = this;
            },
            pointShapes: function (point) {
                var shapes = this.shapes;
                var length = shapes.length;
                var result = [];
                for (var idx = 0; idx < length; idx++) {
                    if (shapes[idx].bbox.containsPoint(point)) {
                        result.push(shapes[idx].shape);
                    }
                }
                return result;
            },
            insert: function (shape, bbox) {
                this._add(shape, bbox);
            },
            remove: function (shape) {
                var shapes = this.shapes;
                var length = shapes.length;
                for (var idx = 0; idx < length; idx++) {
                    if (shapes[idx].shape === shape) {
                        shapes.splice(idx, 1);
                        break;
                    }
                }
            }
        });
        var QuadNode = QuadRoot.extend({
            init: function (rect) {
                QuadRoot.fn.init.call(this);
                this.children = [];
                this.rect = rect;
            },
            inBounds: function (rect) {
                var nodeRect = this.rect;
                var nodeBottomRight = nodeRect.bottomRight();
                var bottomRight = rect.bottomRight();
                var inBounds = nodeRect.origin.x <= rect.origin.x && nodeRect.origin.y <= rect.origin.y && bottomRight.x <= nodeBottomRight.x && bottomRight.y <= nodeBottomRight.y;
                return inBounds;
            },
            pointShapes: function (point) {
                var children = this.children;
                var length = children.length;
                var result = QuadRoot.fn.pointShapes.call(this, point);
                for (var idx = 0; idx < length; idx++) {
                    append(result, children[idx].pointShapes(point));
                }
                return result;
            },
            insert: function (shape, bbox) {
                var children = this.children;
                var inserted = false;
                if (this.inBounds(bbox)) {
                    if (this.shapes.length < 4) {
                        this._add(shape, bbox);
                    } else {
                        if (!children.length) {
                            this._initChildren();
                        }
                        for (var idx = 0; idx < children.length; idx++) {
                            if (children[idx].insert(shape, bbox)) {
                                inserted = true;
                                break;
                            }
                        }
                        if (!inserted) {
                            this._add(shape, bbox);
                        }
                    }
                    inserted = true;
                }
                return inserted;
            },
            _initChildren: function () {
                var ref = this;
                var rect = ref.rect;
                var children = ref.children;
                var center = rect.center();
                var halfWidth = rect.width() / 2;
                var halfHeight = rect.height() / 2;
                children.push(new QuadNode(new Rect([
                    rect.origin.x,
                    rect.origin.y
                ], [
                    halfWidth,
                    halfHeight
                ])), new QuadNode(new Rect([
                    center.x,
                    rect.origin.y
                ], [
                    halfWidth,
                    halfHeight
                ])), new QuadNode(new Rect([
                    rect.origin.x,
                    center.y
                ], [
                    halfWidth,
                    halfHeight
                ])), new QuadNode(new Rect([
                    center.x,
                    center.y
                ], [
                    halfWidth,
                    halfHeight
                ])));
            }
        });
        var ROOT_SIZE = 3000;
        var LEVEL_STEP = 10000;
        var MAX_LEVEL = 75;
        var ShapesQuadTree = Class.extend({
            init: function () {
                this.initRoots();
            },
            initRoots: function () {
                this.rootMap = {};
                this.root = new QuadRoot();
                this.rootElements = [];
            },
            clear: function () {
                var this$1 = this;
                var rootElements = this.rootElements;
                for (var idx = 0; idx < rootElements.length; idx++) {
                    this$1.remove(rootElements[idx]);
                }
                this.initRoots();
            },
            pointShape: function (point) {
                var sectorRoot = (this.rootMap[Math.floor(point.x / ROOT_SIZE)] || {})[Math.floor(point.y / ROOT_SIZE)];
                var result = this.root.pointShapes(point);
                if (sectorRoot) {
                    result = result.concat(sectorRoot.pointShapes(point));
                }
                this.assignZindex(result);
                result.sort(zIndexComparer);
                for (var idx = 0; idx < result.length; idx++) {
                    if (result[idx].containsPoint(point)) {
                        return result[idx];
                    }
                }
            },
            assignZindex: function (elements) {
                var this$1 = this;
                for (var idx = 0; idx < elements.length; idx++) {
                    var element = elements[idx];
                    var zIndex = 0;
                    var levelWeight = Math.pow(LEVEL_STEP, MAX_LEVEL);
                    var parents = [];
                    while (element) {
                        parents.push(element);
                        element = element.parent;
                    }
                    while (parents.length) {
                        element = parents.pop();
                        zIndex += ((element.parent ? element.parent.children : this$1.rootElements).indexOf(element) + 1) * levelWeight;
                        levelWeight /= LEVEL_STEP;
                    }
                    elements[idx]._zIndex = zIndex;
                }
            },
            optionsChange: function (e) {
                if (e.field === 'transform' || e.field === 'stroke.width') {
                    this.bboxChange(e.element);
                }
            },
            geometryChange: function (e) {
                this.bboxChange(e.element);
            },
            bboxChange: function (element) {
                var this$1 = this;
                if (element.nodeType === 'Group') {
                    for (var idx = 0; idx < element.children.length; idx++) {
                        this$1.bboxChange(element.children[idx]);
                    }
                } else {
                    if (element._quadNode) {
                        element._quadNode.remove(element);
                    }
                    this._insertShape(element);
                }
            },
            add: function (elements) {
                var elementsArray = Array.isArray(elements) ? elements.slice(0) : [elements];
                append(this.rootElements, elementsArray);
                this._insert(elementsArray);
            },
            childrenChange: function (e) {
                var this$1 = this;
                if (e.action === 'remove') {
                    for (var idx = 0; idx < e.items.length; idx++) {
                        this$1.remove(e.items[idx]);
                    }
                } else {
                    this._insert(Array.prototype.slice.call(e.items, 0));
                }
            },
            _insert: function (elements) {
                var this$1 = this;
                var element;
                while (elements.length > 0) {
                    element = elements.pop();
                    element.addObserver(this$1);
                    if (element.nodeType === 'Group') {
                        append(elements, element.children);
                    } else {
                        this$1._insertShape(element);
                    }
                }
            },
            _insertShape: function (shape) {
                var bbox = shape.bbox();
                if (bbox) {
                    var sectors = this.getSectors(bbox);
                    var x = sectors[0][0];
                    var y = sectors[1][0];
                    if (this.inRoot(sectors)) {
                        this.root.insert(shape, bbox);
                    } else {
                        var rootMap = this.rootMap;
                        if (!rootMap[x]) {
                            rootMap[x] = {};
                        }
                        if (!rootMap[x][y]) {
                            rootMap[x][y] = new QuadNode(new Rect([
                                x * ROOT_SIZE,
                                y * ROOT_SIZE
                            ], [
                                ROOT_SIZE,
                                ROOT_SIZE
                            ]));
                        }
                        rootMap[x][y].insert(shape, bbox);
                    }
                }
            },
            remove: function (element) {
                var this$1 = this;
                element.removeObserver(this);
                if (element.nodeType === 'Group') {
                    var children = element.children;
                    for (var idx = 0; idx < children.length; idx++) {
                        this$1.remove(children[idx]);
                    }
                } else if (element._quadNode) {
                    element._quadNode.remove(element);
                    delete element._quadNode;
                }
            },
            inRoot: function (sectors) {
                return sectors[0].length > 1 || sectors[1].length > 1;
            },
            getSectors: function (rect) {
                var bottomRight = rect.bottomRight();
                var bottomX = Math.floor(bottomRight.x / ROOT_SIZE);
                var bottomY = Math.floor(bottomRight.y / ROOT_SIZE);
                var sectors = [
                    [],
                    []
                ];
                for (var x = Math.floor(rect.origin.x / ROOT_SIZE); x <= bottomX; x++) {
                    sectors[0].push(x);
                }
                for (var y = Math.floor(rect.origin.y / ROOT_SIZE); y <= bottomY; y++) {
                    sectors[1].push(y);
                }
                return sectors;
            }
        });
        function zIndexComparer(x1, x2) {
            if (x1._zIndex < x2._zIndex) {
                return 1;
            }
            if (x1._zIndex > x2._zIndex) {
                return -1;
            }
            return 0;
        }
        var SurfaceCursor = Class.extend({
            init: function (surface) {
                surface.bind('mouseenter', this._mouseenter.bind(this));
                surface.bind('mouseleave', this._mouseleave.bind(this));
                this.element = surface.element;
            },
            clear: function () {
                this._resetCursor();
            },
            destroy: function () {
                this._resetCursor();
                delete this.element;
            },
            _mouseenter: function (e) {
                var cursor = this._shapeCursor(e);
                if (!cursor) {
                    this._resetCursor();
                } else {
                    if (!this._current) {
                        this._defaultCursor = this._getCursor();
                    }
                    this._setCursor(cursor);
                }
            },
            _mouseleave: function () {
                this._resetCursor();
            },
            _shapeCursor: function (e) {
                var shape = e.element;
                while (shape && !defined(shape.options.cursor)) {
                    shape = shape.parent;
                }
                if (shape) {
                    return shape.options.cursor;
                }
            },
            _getCursor: function () {
                if (this.element) {
                    return this.element.style.cursor;
                }
            },
            _setCursor: function (cursor) {
                if (this.element) {
                    this.element.style.cursor = cursor;
                    this._current = cursor;
                }
            },
            _resetCursor: function () {
                if (this._current) {
                    this._setCursor(this._defaultCursor || '');
                    delete this._current;
                }
            }
        });
        var Surface$3 = Surface.extend({
            init: function (element, options) {
                Surface.fn.init.call(this, element, options);
                this.element.innerHTML = this._template(this);
                var canvas = this.element.firstElementChild;
                var size = elementSize(element);
                canvas.width = size.width;
                canvas.height = size.height;
                this._rootElement = canvas;
                this._root = new RootNode$2(canvas);
                this._mouseTrackHandler = this._trackMouse.bind(this);
                bindEvents(this.element, {
                    click: this._mouseTrackHandler,
                    mousemove: this._mouseTrackHandler
                });
            },
            destroy: function () {
                Surface.fn.destroy.call(this);
                if (this._root) {
                    this._root.destroy();
                    this._root = null;
                }
                if (this._searchTree) {
                    this._searchTree.clear();
                    delete this._searchTree;
                }
                if (this._cursor) {
                    this._cursor.destroy();
                    delete this._cursor;
                }
                unbindEvents(this.element, {
                    click: this._mouseTrackHandler,
                    mousemove: this._mouseTrackHandler
                });
            },
            draw: function (element) {
                Surface.fn.draw.call(this, element);
                this._root.load([element], undefined, this.options.cors);
                if (this._searchTree) {
                    this._searchTree.add([element]);
                }
            },
            clear: function () {
                Surface.fn.clear.call(this);
                this._root.clear();
                if (this._searchTree) {
                    this._searchTree.clear();
                }
                if (this._cursor) {
                    this._cursor.clear();
                }
            },
            eventTarget: function (e) {
                if (this._searchTree) {
                    var point = this._surfacePoint(e);
                    var shape = this._searchTree.pointShape(point);
                    return shape;
                }
            },
            image: function () {
                var ref = this;
                var root = ref._root;
                var rootElement = ref._rootElement;
                var loadingStates = [];
                root.traverse(function (childNode) {
                    if (childNode.loading) {
                        loadingStates.push(childNode.loading);
                    }
                });
                var promise = createPromise();
                var resolveDataURL = function () {
                    root._invalidate();
                    try {
                        var data = rootElement.toDataURL();
                        promise.resolve(data);
                    } catch (e) {
                        promise.reject(e);
                    }
                };
                promiseAll(loadingStates).then(resolveDataURL, resolveDataURL);
                return promise;
            },
            suspendTracking: function () {
                Surface.fn.suspendTracking.call(this);
                if (this._searchTree) {
                    this._searchTree.clear();
                    delete this._searchTree;
                }
            },
            resumeTracking: function () {
                Surface.fn.resumeTracking.call(this);
                if (!this._searchTree) {
                    this._searchTree = new ShapesQuadTree();
                    var childNodes = this._root.childNodes;
                    var rootElements = [];
                    for (var idx = 0; idx < childNodes.length; idx++) {
                        rootElements.push(childNodes[idx].srcElement);
                    }
                    this._searchTree.add(rootElements);
                }
            },
            _resize: function () {
                this._rootElement.width = this._size.width;
                this._rootElement.height = this._size.height;
                this._root.invalidate();
            },
            _template: function () {
                return '<canvas style=\'width: 100%; height: 100%;\'></canvas>';
            },
            _enableTracking: function () {
                this._searchTree = new ShapesQuadTree();
                this._cursor = new SurfaceCursor(this);
                Surface.fn._enableTracking.call(this);
            },
            _trackMouse: function (e) {
                if (this._suspendedTracking) {
                    return;
                }
                var shape = this.eventTarget(e);
                if (e.type !== 'click') {
                    var currentShape = this._currentShape;
                    if (currentShape && currentShape !== shape) {
                        this.trigger('mouseleave', {
                            element: currentShape,
                            originalEvent: e,
                            type: 'mouseleave'
                        });
                    }
                    if (shape && currentShape !== shape) {
                        this.trigger('mouseenter', {
                            element: shape,
                            originalEvent: e,
                            type: 'mouseenter'
                        });
                    }
                    this.trigger('mousemove', {
                        element: shape,
                        originalEvent: e,
                        type: 'mousemove'
                    });
                    this._currentShape = shape;
                } else if (shape) {
                    this.trigger('click', {
                        element: shape,
                        originalEvent: e,
                        type: 'click'
                    });
                }
            }
        });
        Surface$3.prototype.type = 'canvas';
        if (typeof document !== 'undefined' && document.createElement('canvas').getContext) {
            Surface.support.canvas = true;
            SurfaceFactory.current.register('canvas', Surface$3, 20);
        }
        function addGradientStops(gradient, stops) {
            for (var idx = 0; idx < stops.length; idx++) {
                var stop = stops[idx];
                var color = kendo.parseColor(stop.color());
                color.a *= stop.opacity();
                gradient.addColorStop(stop.offset(), color.toCssRgba());
            }
        }
        var PathNode$2 = Node$2.extend({
            renderTo: function (ctx) {
                ctx.save();
                this.setTransform(ctx);
                this.setClip(ctx);
                this.setOpacity(ctx);
                ctx.beginPath();
                this.renderPoints(ctx, this.srcElement);
                this.setLineDash(ctx);
                this.setLineCap(ctx);
                this.setLineJoin(ctx);
                this.setFill(ctx);
                this.setStroke(ctx);
                ctx.restore();
            },
            setFill: function (ctx) {
                var fill = this.srcElement.options.fill;
                var hasFill = false;
                if (fill) {
                    if (fill.nodeType === 'Gradient') {
                        this.setGradientFill(ctx, fill);
                        hasFill = true;
                    } else if (!isTransparent(fill.color)) {
                        ctx.fillStyle = fill.color;
                        ctx.save();
                        this.globalAlpha(ctx, fill.opacity);
                        ctx.fill();
                        ctx.restore();
                        hasFill = true;
                    }
                }
                return hasFill;
            },
            setGradientFill: function (ctx, fill) {
                var bbox = this.srcElement.rawBBox();
                var gradient;
                if (fill instanceof LinearGradient) {
                    var start = fill.start();
                    var end = fill.end();
                    gradient = ctx.createLinearGradient(start.x, start.y, end.x, end.y);
                } else if (fill instanceof RadialGradient) {
                    var center = fill.center();
                    gradient = ctx.createRadialGradient(center.x, center.y, 0, center.x, center.y, fill.radius());
                }
                addGradientStops(gradient, fill.stops);
                ctx.save();
                if (!fill.userSpace()) {
                    ctx.transform(bbox.width(), 0, 0, bbox.height(), bbox.origin.x, bbox.origin.y);
                }
                ctx.fillStyle = gradient;
                ctx.fill();
                ctx.restore();
            },
            setStroke: function (ctx) {
                var stroke = this.srcElement.options.stroke;
                if (stroke && !isTransparent(stroke.color) && stroke.width > 0) {
                    ctx.strokeStyle = stroke.color;
                    ctx.lineWidth = valueOrDefault(stroke.width, 1);
                    ctx.save();
                    this.globalAlpha(ctx, stroke.opacity);
                    ctx.stroke();
                    ctx.restore();
                    return true;
                }
            },
            dashType: function () {
                var stroke = this.srcElement.options.stroke;
                if (stroke && stroke.dashType) {
                    return stroke.dashType.toLowerCase();
                }
            },
            setLineDash: function (ctx) {
                var dashType = this.dashType();
                if (dashType && dashType !== SOLID) {
                    var dashArray = DASH_ARRAYS[dashType];
                    if (ctx.setLineDash) {
                        ctx.setLineDash(dashArray);
                    } else {
                        ctx.mozDash = dashArray;
                        ctx.webkitLineDash = dashArray;
                    }
                }
            },
            setLineCap: function (ctx) {
                var dashType = this.dashType();
                var stroke = this.srcElement.options.stroke;
                if (dashType && dashType !== SOLID) {
                    ctx.lineCap = BUTT;
                } else if (stroke && stroke.lineCap) {
                    ctx.lineCap = stroke.lineCap;
                }
            },
            setLineJoin: function (ctx) {
                var stroke = this.srcElement.options.stroke;
                if (stroke && stroke.lineJoin) {
                    ctx.lineJoin = stroke.lineJoin;
                }
            },
            renderPoints: function (ctx, path) {
                renderPath(ctx, path);
            }
        });
        NODE_MAP$2.Path = PathNode$2;
        var ArcNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var path = this.srcElement.toPath();
                renderPath(ctx, path);
            }
        });
        NODE_MAP$2.Arc = ArcNode$2;
        var CircleNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var ref = this.srcElement.geometry();
                var center = ref.center;
                var radius = ref.radius;
                ctx.arc(center.x, center.y, radius, 0, Math.PI * 2);
            }
        });
        NODE_MAP$2.Circle = CircleNode$2;
        var RectNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var ref = this.srcElement.geometry();
                var origin = ref.origin;
                var size = ref.size;
                ctx.rect(origin.x, origin.y, size.width, size.height);
            }
        });
        NODE_MAP$2.Rect = RectNode$2;
        var ImageNode$2 = PathNode$2.extend({
            init: function (srcElement, cors) {
                PathNode$2.fn.init.call(this, srcElement);
                this.onLoad = this.onLoad.bind(this);
                this.onError = this.onError.bind(this);
                this.loading = createPromise();
                var img = this.img = new Image();
                if (cors && !/^data:/i.test(srcElement.src())) {
                    img.crossOrigin = cors;
                }
                img.src = srcElement.src();
                if (img.complete) {
                    this.onLoad();
                } else {
                    img.onload = this.onLoad;
                    img.onerror = this.onError;
                }
            },
            renderTo: function (ctx) {
                if (this.loading.state() === 'resolved') {
                    ctx.save();
                    this.setTransform(ctx);
                    this.setClip(ctx);
                    this.drawImage(ctx);
                    ctx.restore();
                }
            },
            optionsChange: function (e) {
                if (e.field === 'src') {
                    this.loading = createPromise();
                    this.img.src = this.srcElement.src();
                } else {
                    PathNode$2.fn.optionsChange.call(this, e);
                }
            },
            onLoad: function () {
                this.loading.resolve();
                this.invalidate();
            },
            onError: function () {
                this.loading.reject(new Error('Unable to load image \'' + this.img.src + '\'. Check for connectivity and verify CORS headers.'));
            },
            drawImage: function (ctx) {
                var rect = this.srcElement.rect();
                var topLeft = rect.topLeft();
                ctx.drawImage(this.img, topLeft.x, topLeft.y, rect.width(), rect.height());
            }
        });
        NODE_MAP$2.Image = ImageNode$2;
        var TextNode$2 = PathNode$2.extend({
            renderTo: function (ctx) {
                var text = this.srcElement;
                var pos = text.position();
                var size = text.measure();
                ctx.save();
                this.setTransform(ctx);
                this.setClip(ctx);
                this.setOpacity(ctx);
                ctx.beginPath();
                ctx.font = text.options.font;
                if (this.setFill(ctx)) {
                    ctx.fillText(text.content(), pos.x, pos.y + size.baseline);
                }
                if (this.setStroke(ctx)) {
                    this.setLineDash(ctx);
                    ctx.strokeText(text.content(), pos.x, pos.y + size.baseline);
                }
                ctx.restore();
            }
        });
        NODE_MAP$2.Text = TextNode$2;
        var MultiPathNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var paths = this.srcElement.paths;
                for (var i = 0; i < paths.length; i++) {
                    renderPath(ctx, paths[i]);
                }
            }
        });
        NODE_MAP$2.MultiPath = MultiPathNode$2;
        var canvas = {
            Surface: Surface$3,
            RootNode: RootNode$2,
            Node: Node$2,
            GroupNode: GroupNode$2,
            ArcNode: ArcNode$2,
            CircleNode: CircleNode$2,
            RectNode: RectNode$2,
            ImageNode: ImageNode$2,
            TextNode: TextNode$2,
            PathNode: PathNode$2,
            MultiPathNode: MultiPathNode$2
        };
        function exportImage(group, options) {
            var defaults = {
                width: '800px',
                height: '600px',
                cors: 'Anonymous'
            };
            var exportRoot = group;
            var bbox = group.clippedBBox();
            if (bbox) {
                var origin = bbox.getOrigin();
                exportRoot = new Group();
                exportRoot.transform(transform().translate(-origin.x, -origin.y));
                exportRoot.children.push(group);
                var size = bbox.getSize();
                defaults.width = size.width + 'px';
                defaults.height = size.height + 'px';
            }
            var surfaceOptions = $.extend(defaults, options);
            var container = document.createElement('div');
            var style = container.style;
            style.display = 'none';
            style.width = surfaceOptions.width;
            style.height = surfaceOptions.height;
            document.body.appendChild(container);
            var surface = new Surface$3(container, surfaceOptions);
            surface.suspendTracking();
            surface.draw(exportRoot);
            var promise = surface.image();
            var destroy = function () {
                surface.destroy();
                document.body.removeChild(container);
            };
            promise.then(destroy, destroy);
            return promise;
        }
        function exportSVG(group, options) {
            var svg = exportGroup(group);
            if (!options || !options.raw) {
                svg = 'data:image/svg+xml;base64,' + encodeBase64(svg);
            }
            return createPromise().resolve(svg);
        }
        var browser = support.browser;
        function slice$1(thing) {
            return Array.prototype.slice.call(thing);
        }
        var KENDO_PSEUDO_ELEMENT = 'KENDO-PSEUDO-ELEMENT';
        var IMAGE_CACHE = {};
        var nodeInfo = {};
        nodeInfo._root = nodeInfo;
        var TextRect = Text.extend({
            init: function (str, rect, options) {
                Text.fn.init.call(this, str, rect.getOrigin(), options);
                this._pdfRect = rect;
            },
            rect: function () {
                return this._pdfRect;
            },
            rawBBox: function () {
                return this._pdfRect;
            }
        });
        function addClass(el, cls) {
            if (el.classList) {
                el.classList.add(cls);
            } else {
                el.className += ' ' + cls;
            }
        }
        function removeClass(el, cls) {
            if (el.classList) {
                el.classList.remove(cls);
            } else {
                el.className = el.className.split(/\s+/).reduce(function (a, word) {
                    if (word != cls) {
                        a.push(word);
                    }
                    return a;
                }, []).join(' ');
            }
        }
        function setCSS(el, styles) {
            Object.keys(styles).forEach(function (key) {
                el.style[key] = styles[key];
            });
        }
        var matches = typeof Element !== 'undefined' && Element.prototype && function (p) {
            if (p.matches) {
                return function (el, selector) {
                    return el.matches(selector);
                };
            }
            if (p.webkitMatchesSelector) {
                return function (el, selector) {
                    return el.webkitMatchesSelector(selector);
                };
            }
            if (p.mozMatchesSelector) {
                return function (el, selector) {
                    return el.mozMatchesSelector(selector);
                };
            }
            if (p.msMatchesSelector) {
                return function (el, selector) {
                    return el.msMatchesSelector(selector);
                };
            }
            return function (s) {
                return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
            };
        }(Element.prototype);
        function closest(el, selector) {
            if (el.closest) {
                return el.closest(selector);
            }
            while (el && !/^\[object (?:HTML)?Document\]$/.test(String(el))) {
                if (matches(el, selector)) {
                    return el;
                }
                el = el.parentNode;
            }
        }
        var cloneNodes = function ($) {
            if ($) {
                return function cloneNodes(el) {
                    var clone = el.cloneNode(false);
                    if (el.nodeType == 1) {
                        var $el = $(el), $clone = $(clone), i;
                        var data = $el.data();
                        for (i in data) {
                            $clone.data(i, data[i]);
                        }
                        if (/^canvas$/i.test(el.tagName)) {
                            clone.getContext('2d').drawImage(el, 0, 0);
                        } else if (/^(?:input|select|textarea|option)$/i.test(el.tagName)) {
                            clone.removeAttribute('id');
                            clone.removeAttribute('name');
                            clone.value = el.value;
                            clone.checked = el.checked;
                            clone.selected = el.selected;
                        }
                        for (i = el.firstChild; i; i = i.nextSibling) {
                            clone.appendChild(cloneNodes(i));
                        }
                    }
                    return clone;
                };
            } else {
                return function cloneNodes(el) {
                    var clone = el.cloneNode(true);
                    var canvases = el.querySelectorAll('canvas');
                    if (canvases.length) {
                        slice$1(clone.querySelectorAll('canvas')).forEach(function (canvas$$1, i) {
                            canvas$$1.getContext('2d').drawImage(canvases[i], 0, 0);
                        });
                    }
                    var orig = el.querySelectorAll('input, select, textarea, option');
                    slice$1(clone.querySelectorAll('input, select, textarea, option')).forEach(function (el, i) {
                        el.removeAttribute('id');
                        el.removeAttribute('name');
                        el.value = orig[i].value;
                        el.checked = orig[i].checked;
                        el.selected = orig[i].selected;
                    });
                    return clone;
                };
            }
        }(typeof window !== 'undefined' && window.kendo && window.kendo.jQuery);
        function getXY(thing) {
            if (typeof thing == 'number') {
                return {
                    x: thing,
                    y: thing
                };
            }
            if (Array.isArray(thing)) {
                return {
                    x: thing[0],
                    y: thing[1]
                };
            }
            return {
                x: thing.x,
                y: thing.y
            };
        }
        function drawDOM(element, options) {
            if (!options) {
                options = {};
            }
            var promise = createPromise();
            if (!element) {
                return promise.reject('No element to export');
            }
            if (typeof window.getComputedStyle != 'function') {
                throw new Error('window.getComputedStyle is missing.  You are using an unsupported browser, or running in IE8 compatibility mode.  Drawing HTML is supported in Chrome, Firefox, Safari and IE9+.');
            }
            kendo.pdf.defineFont(getFontFaces(element.ownerDocument));
            var scale = getXY(options.scale || 1);
            function doOne(element) {
                var group = new Group();
                var pos = element.getBoundingClientRect();
                setTransform(group, [
                    scale.x,
                    0,
                    0,
                    scale.y,
                    -pos.left * scale.x,
                    -pos.top * scale.y
                ]);
                nodeInfo._clipbox = false;
                nodeInfo._matrix = Matrix.unit();
                nodeInfo._stackingContext = {
                    element: element,
                    group: group
                };
                if (options.avoidLinks === true) {
                    nodeInfo._avoidLinks = 'a';
                } else {
                    nodeInfo._avoidLinks = options.avoidLinks;
                }
                addClass(element, 'k-pdf-export');
                renderElement(element, group);
                removeClass(element, 'k-pdf-export');
                return group;
            }
            cacheImages(element, function () {
                var forceBreak = options && options.forcePageBreak;
                var hasPaperSize = options && options.paperSize && options.paperSize != 'auto';
                var paperOptions = kendo.pdf.getPaperOptions(function (key, def) {
                    if (key == 'paperSize') {
                        return hasPaperSize ? options[key] : 'A4';
                    }
                    return key in options ? options[key] : def;
                });
                var pageWidth = hasPaperSize && paperOptions.paperSize[0];
                var pageHeight = hasPaperSize && paperOptions.paperSize[1];
                var margin = options.margin && paperOptions.margin;
                var hasMargin = Boolean(margin);
                if (forceBreak || pageHeight) {
                    if (!margin) {
                        margin = {
                            left: 0,
                            top: 0,
                            right: 0,
                            bottom: 0
                        };
                    }
                    if (pageWidth) {
                        pageWidth /= scale.x;
                    }
                    if (pageHeight) {
                        pageHeight /= scale.y;
                    }
                    margin.left /= scale.x;
                    margin.right /= scale.x;
                    margin.top /= scale.y;
                    margin.bottom /= scale.y;
                    var group = new Group({
                        pdf: {
                            multiPage: true,
                            paperSize: hasPaperSize ? paperOptions.paperSize : 'auto',
                            _ignoreMargin: hasMargin
                        }
                    });
                    handlePageBreaks(function (x) {
                        if (options.progress) {
                            var canceled = false, pageNum = 0;
                            (function next() {
                                if (pageNum < x.pages.length) {
                                    var page = doOne(x.pages[pageNum]);
                                    group.append(page);
                                    options.progress({
                                        page: page,
                                        pageNum: ++pageNum,
                                        totalPages: x.pages.length,
                                        cancel: function () {
                                            canceled = true;
                                        }
                                    });
                                    if (!canceled) {
                                        setTimeout(next);
                                    } else {
                                        x.container.parentNode.removeChild(x.container);
                                    }
                                } else {
                                    x.container.parentNode.removeChild(x.container);
                                    promise.resolve(group);
                                }
                            }());
                        } else {
                            x.pages.forEach(function (page) {
                                group.append(doOne(page));
                            });
                            x.container.parentNode.removeChild(x.container);
                            promise.resolve(group);
                        }
                    }, element, forceBreak, pageWidth ? pageWidth - margin.left - margin.right : null, pageHeight ? pageHeight - margin.top - margin.bottom : null, margin, options);
                } else {
                    promise.resolve(doOne(element));
                }
            });
            function makeTemplate(template$$1) {
                if (template$$1 != null) {
                    if (typeof template$$1 == 'string') {
                        template$$1 = kendo.template(template$$1.replace(/^\s+|\s+$/g, ''));
                    }
                    if (typeof template$$1 == 'function') {
                        return function (data) {
                            var el = template$$1(data);
                            if (el && typeof el == 'string') {
                                var div = document.createElement('div');
                                div.innerHTML = el;
                                el = div.firstElementChild;
                            }
                            return el;
                        };
                    }
                    return function () {
                        return template$$1.cloneNode(true);
                    };
                }
            }
            function handlePageBreaks(callback, element, forceBreak, pageWidth, pageHeight, margin, options) {
                var template$$1 = makeTemplate(options.template);
                var doc = element.ownerDocument;
                var pages = [];
                var copy = options._destructive ? element : cloneNodes(element);
                var container = doc.createElement('KENDO-PDF-DOCUMENT');
                var adjust = 0;
                slice$1(copy.querySelectorAll('tfoot')).forEach(function (tfoot) {
                    tfoot.parentNode.appendChild(tfoot);
                });
                slice$1(copy.querySelectorAll('ol')).forEach(function (ol) {
                    slice$1(ol.children).forEach(function (li, index) {
                        li.setAttribute('kendo-split-index', index);
                    });
                });
                setCSS(container, {
                    display: 'block',
                    position: 'absolute',
                    boxSizing: 'content-box',
                    left: '-10000px',
                    top: '-10000px'
                });
                if (pageWidth) {
                    setCSS(container, {
                        width: pageWidth + 'px',
                        paddingLeft: margin.left + 'px',
                        paddingRight: margin.right + 'px'
                    });
                    setCSS(copy, { overflow: 'hidden' });
                }
                element.parentNode.insertBefore(container, element);
                container.appendChild(copy);
                if (options.beforePageBreak) {
                    setTimeout(function () {
                        options.beforePageBreak(container, doPageBreak);
                    }, 15);
                } else {
                    setTimeout(doPageBreak, 15);
                }
                function doPageBreak() {
                    if (forceBreak != '-' || pageHeight) {
                        splitElement(copy);
                    }
                    var page = makePage();
                    copy.parentNode.insertBefore(page, copy);
                    page.appendChild(copy);
                    if (template$$1) {
                        var count = pages.length;
                        pages.forEach(function (page, i) {
                            var el = template$$1({
                                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(el) {
                    if (options.keepTogether && matches(el, options.keepTogether) && el.offsetHeight <= pageHeight - adjust) {
                        return true;
                    }
                    var tag = el.tagName;
                    if (/^h[1-6]$/i.test(tag) && el.offsetHeight >= pageHeight - adjust) {
                        return false;
                    }
                    return el.getAttribute('data-kendo-chart') || /^(?:img|tr|thead|th|tfoot|iframe|svg|object|canvas|input|textarea|select|video|h[1-6])/i.test(el.tagName);
                }
                function splitElement(element) {
                    if (element.tagName == 'TABLE') {
                        setCSS(element, { tableLayout: 'fixed' });
                    }
                    var style = getComputedStyle(element);
                    var bottomPadding = parseFloat(getPropertyValue(style, 'padding-bottom'));
                    var bottomBorder = parseFloat(getPropertyValue(style, 'border-bottom-width'));
                    var saveAdjust = adjust;
                    adjust += bottomPadding + bottomBorder;
                    var isFirst = true;
                    for (var el = element.firstChild; el; el = el.nextSibling) {
                        if (el.nodeType == 1) {
                            isFirst = false;
                            if (matches(el, forceBreak)) {
                                breakAtElement(el);
                                continue;
                            }
                            if (!pageHeight) {
                                splitElement(el);
                                continue;
                            }
                            if (!/^(?:static|relative)$/.test(getPropertyValue(getComputedStyle(el), 'position'))) {
                                continue;
                            }
                            var fall = fallsOnMargin(el);
                            if (fall == 1) {
                                breakAtElement(el);
                            } else if (fall) {
                                if (keepTogether(el)) {
                                    breakAtElement(el);
                                } else {
                                    splitElement(el);
                                }
                            } else {
                                splitElement(el);
                            }
                        } else if (el.nodeType == 3 && pageHeight) {
                            splitText(el, isFirst);
                            isFirst = false;
                        }
                    }
                    adjust = saveAdjust;
                }
                function firstInParent(el) {
                    var p = el.parentNode, first = p.firstChild;
                    if (el === first) {
                        return true;
                    }
                    if (el === p.children[0]) {
                        if (first.nodeType == 7 || first.nodeType == 8) {
                            return true;
                        }
                        if (first.nodeType == 3) {
                            return !/\S/.test(first.data);
                        }
                    }
                    return false;
                }
                function breakAtElement(el) {
                    if (el.nodeType == 1 && el !== copy && firstInParent(el)) {
                        return breakAtElement(el.parentNode);
                    }
                    var table, colgroup, thead, grid, gridHead;
                    table = closest(el, 'table');
                    colgroup = table && table.querySelector('colgroup');
                    if (options.repeatHeaders) {
                        thead = table && table.querySelector('thead');
                        grid = closest(el, '.k-grid[data-role="grid"]');
                        if (grid && grid.querySelector('.k-auto-scrollable')) {
                            gridHead = grid.querySelector('.k-grid-header');
                        }
                    }
                    var page = makePage();
                    var range = doc.createRange();
                    range.setStartBefore(copy);
                    range.setEndBefore(el);
                    page.appendChild(range.extractContents());
                    copy.parentNode.insertBefore(page, copy);
                    preventBulletOnListItem(el.parentNode);
                    if (table) {
                        table = closest(el, 'table');
                        if (options.repeatHeaders && thead) {
                            table.insertBefore(thead.cloneNode(true), table.firstChild);
                        }
                        if (colgroup) {
                            table.insertBefore(colgroup.cloneNode(true), table.firstChild);
                        }
                    }
                    if (options.repeatHeaders && gridHead) {
                        grid = closest(el, '.k-grid[data-role="grid"]');
                        grid.insertBefore(gridHead.cloneNode(true), grid.firstChild);
                    }
                }
                function makePage() {
                    var page = doc.createElement('KENDO-PDF-PAGE');
                    setCSS(page, {
                        display: 'block',
                        boxSizing: 'content-box',
                        width: pageWidth ? pageWidth + 'px' : 'auto',
                        padding: margin.top + 'px ' + margin.right + 'px ' + margin.bottom + 'px ' + margin.left + 'px',
                        position: 'relative',
                        height: pageHeight ? pageHeight + 'px' : 'auto',
                        overflow: pageHeight || pageWidth ? 'hidden' : 'visible',
                        clear: 'both'
                    });
                    if (options && options.pageClassName) {
                        page.className = options.pageClassName;
                    }
                    pages.push(page);
                    return page;
                }
                function fallsOnMargin(thing) {
                    var box = thing.getBoundingClientRect();
                    if (box.width === 0 || box.height === 0) {
                        return 0;
                    }
                    var top = copy.getBoundingClientRect().top;
                    var available = pageHeight - adjust;
                    return box.height > available ? 3 : box.top - top > available ? 1 : box.bottom - top > available ? 2 : 0;
                }
                function splitText(node, isFirst) {
                    if (!/\S/.test(node.data)) {
                        return;
                    }
                    var len = node.data.length;
                    var range = doc.createRange();
                    range.selectNodeContents(node);
                    var fall = fallsOnMargin(range);
                    if (!fall) {
                        return;
                    }
                    var nextnode = node;
                    if (fall == 1) {
                        if (isFirst) {
                            breakAtElement(node.parentNode);
                        } else {
                            breakAtElement(node);
                        }
                    } else {
                        (function findEOP(min, pos, max) {
                            range.setEnd(node, pos);
                            if (min == pos || pos == max) {
                                return pos;
                            }
                            if (fallsOnMargin(range)) {
                                return findEOP(min, min + pos >> 1, pos);
                            } else {
                                return findEOP(pos, pos + max >> 1, max);
                            }
                        }(0, len >> 1, len));
                        if (!/\S/.test(range.toString()) && isFirst) {
                            breakAtElement(node.parentNode);
                        } else {
                            nextnode = node.splitText(range.endOffset);
                            var page = makePage();
                            range.setStartBefore(copy);
                            page.appendChild(range.extractContents());
                            copy.parentNode.insertBefore(page, copy);
                            preventBulletOnListItem(nextnode.parentNode);
                        }
                    }
                    splitText(nextnode);
                }
                function preventBulletOnListItem(el) {
                    var li = closest(el, 'li');
                    if (li) {
                        li.setAttribute('kendo-no-bullet', '1');
                        preventBulletOnListItem(li.parentNode);
                    }
                }
            }
            return promise;
        }
        drawDOM.getFontFaces = getFontFaces;
        drawDOM.drawText = function (element) {
            var group = new Group();
            nodeInfo._clipbox = false;
            nodeInfo._matrix = Matrix.unit();
            nodeInfo._stackingContext = {
                element: element,
                group: group
            };
            pushNodeInfo(element, getComputedStyle(element), group);
            if (element.firstChild.nodeType == 3) {
                renderText(element, element.firstChild, group);
            } else {
                _renderElement(element, group);
            }
            popNodeInfo();
            return group;
        };
        var parseBackgroundImage = function () {
            var tok_linear_gradient = /^((-webkit-|-moz-|-o-|-ms-)?linear-gradient\s*)\(/;
            var tok_percent = /^([-0-9.]+%)/;
            var tok_length = /^([-0-9.]+px)/;
            var tok_keyword = /^(left|right|top|bottom|to|center)\W/;
            var tok_angle = /^([-0-9.]+(deg|grad|rad|turn))/;
            var tok_whitespace = /^(\s+)/;
            var tok_popen = /^(\()/;
            var tok_pclose = /^(\))/;
            var tok_comma = /^(,)/;
            var tok_url = /^(url)\(/;
            var tok_content = /^(.*?)\)/;
            var cache1 = {}, cache2 = {};
            function parse(input) {
                var orig = input;
                if (hasOwnProperty(cache1, orig)) {
                    return cache1[orig];
                }
                function skip_ws() {
                    var m = tok_whitespace.exec(input);
                    if (m) {
                        input = input.substr(m[1].length);
                    }
                }
                function read(token) {
                    skip_ws();
                    var m = token.exec(input);
                    if (m) {
                        input = input.substr(m[1].length);
                        return m[1];
                    }
                }
                function read_stop() {
                    var color = kendo.parseColor(input, true);
                    var length, percent;
                    if (color) {
                        var match = /^#[0-9a-f]+/i.exec(input) || /^rgba?\(.*?\)/i.exec(input) || /^..*?\b/.exec(input);
                        input = input.substr(match[0].length);
                        color = color.toRGB();
                        if (!(length = read(tok_length))) {
                            percent = read(tok_percent);
                        }
                        return {
                            color: color,
                            length: length,
                            percent: percent
                        };
                    }
                }
                function read_linear_gradient(propName) {
                    var angle;
                    var to1, to2;
                    var stops = [];
                    var reverse = false;
                    if (read(tok_popen)) {
                        angle = read(tok_angle);
                        if (angle) {
                            angle = parseAngle(angle);
                            read(tok_comma);
                        } else {
                            to1 = read(tok_keyword);
                            if (to1 == 'to') {
                                to1 = read(tok_keyword);
                            } else if (to1 && /^-/.test(propName)) {
                                reverse = true;
                            }
                            to2 = read(tok_keyword);
                            read(tok_comma);
                        }
                        if (/-moz-/.test(propName) && angle == null && to1 == null) {
                            var x = read(tok_percent), y = read(tok_percent);
                            reverse = true;
                            if (x == '0%') {
                                to1 = 'left';
                            } else if (x == '100%') {
                                to1 = 'right';
                            }
                            if (y == '0%') {
                                to2 = 'top';
                            } else if (y == '100%') {
                                to2 = 'bottom';
                            }
                            read(tok_comma);
                        }
                        while (input && !read(tok_pclose)) {
                            var stop = read_stop();
                            if (!stop) {
                                break;
                            }
                            stops.push(stop);
                            read(tok_comma);
                        }
                        return {
                            type: 'linear',
                            angle: angle,
                            to: to1 && to2 ? to1 + ' ' + to2 : to1 ? to1 : to2 ? to2 : null,
                            stops: stops,
                            reverse: reverse
                        };
                    }
                }
                function read_url() {
                    if (read(tok_popen)) {
                        var url = read(tok_content);
                        url = url.replace(/^['"]+|["']+$/g, '');
                        read(tok_pclose);
                        return {
                            type: 'url',
                            url: url
                        };
                    }
                }
                var tok;
                if (tok = read(tok_linear_gradient)) {
                    tok = read_linear_gradient(tok);
                } else if (tok = read(tok_url)) {
                    tok = read_url();
                }
                return cache1[orig] = tok || { type: 'none' };
            }
            return function (input) {
                if (hasOwnProperty(cache2, input)) {
                    return cache2[input];
                }
                return cache2[input] = splitProperty(input).map(parse);
            };
        }();
        var splitProperty = function () {
            var cache = {};
            return function (input, separator) {
                if (!separator) {
                    separator = /^\s*,\s*/;
                }
                var cacheKey = input + separator;
                if (hasOwnProperty(cache, cacheKey)) {
                    return cache[cacheKey];
                }
                var ret = [];
                var last$$1 = 0, pos = 0;
                var in_paren = 0;
                var in_string = false;
                var m;
                function looking_at(rx) {
                    return m = rx.exec(input.substr(pos));
                }
                function trim(str) {
                    return str.replace(/^\s+|\s+$/g, '');
                }
                while (pos < input.length) {
                    if (!in_string && looking_at(/^[\(\[\{]/)) {
                        in_paren++;
                        pos++;
                    } else if (!in_string && looking_at(/^[\)\]\}]/)) {
                        in_paren--;
                        pos++;
                    } else if (!in_string && looking_at(/^[\"\']/)) {
                        in_string = m[0];
                        pos++;
                    } else if (in_string == '\'' && looking_at(/^\\\'/)) {
                        pos += 2;
                    } else if (in_string == '"' && looking_at(/^\\\"/)) {
                        pos += 2;
                    } else if (in_string == '\'' && looking_at(/^\'/)) {
                        in_string = false;
                        pos++;
                    } else if (in_string == '"' && looking_at(/^\"/)) {
                        in_string = false;
                        pos++;
                    } else if (looking_at(separator)) {
                        if (!in_string && !in_paren && pos > last$$1) {
                            ret.push(trim(input.substring(last$$1, pos)));
                            last$$1 = pos + m[0].length;
                        }
                        pos += m[0].length;
                    } else {
                        pos++;
                    }
                }
                if (last$$1 < pos) {
                    ret.push(trim(input.substring(last$$1, pos)));
                }
                return cache[cacheKey] = ret;
            };
        }();
        var getFontURL = function (cache) {
            return function (el) {
                var url = cache[el];
                if (!url) {
                    var m;
                    if (m = /url\((['"]?)([^'")]*?)\1\)\s+format\((['"]?)truetype\3\)/.exec(el)) {
                        url = cache[el] = m[2];
                    } else if (m = /url\((['"]?)([^'")]*?\.ttf)\1\)/.exec(el)) {
                        url = cache[el] = m[2];
                    }
                }
                return url;
            };
        }(Object.create ? Object.create(null) : {});
        var getFontHeight = function (cache) {
            return function (font) {
                var height = cache[font];
                if (height == null) {
                    height = cache[font] = kendoUtil.measureText('Mapq', { font: font }).height;
                }
                return height;
            };
        }(Object.create ? Object.create(null) : {});
        function getFontFaces(doc) {
            if (doc == null) {
                doc = document;
            }
            var result = {};
            for (var i = 0; i < doc.styleSheets.length; ++i) {
                doStylesheet(doc.styleSheets[i]);
            }
            return result;
            function doStylesheet(ss) {
                if (ss) {
                    var rules = null;
                    try {
                        rules = ss.cssRules;
                    } catch (ex) {
                    }
                    if (rules) {
                        addRules(ss, rules);
                    }
                }
            }
            function findFonts(rule) {
                var src = getPropertyValue(rule.style, 'src');
                if (src) {
                    return splitProperty(src).reduce(function (a, el) {
                        var font = getFontURL(el);
                        if (font) {
                            a.push(font);
                        }
                        return a;
                    }, []);
                } else {
                    var font = getFontURL(rule.cssText);
                    return font ? [font] : [];
                }
            }
            function addRules(styleSheet, rules) {
                for (var i = 0; i < rules.length; ++i) {
                    var r = rules[i];
                    switch (r.type) {
                    case 3:
                        doStylesheet(r.styleSheet);
                        break;
                    case 5:
                        var style = r.style;
                        var family = splitProperty(getPropertyValue(style, 'font-family'));
                        var bold = /^([56789]00|bold)$/i.test(getPropertyValue(style, 'font-weight'));
                        var italic = 'italic' == getPropertyValue(style, 'font-style');
                        var src = findFonts(r);
                        if (src.length > 0) {
                            addRule(styleSheet, family, bold, italic, src[0]);
                        }
                    }
                }
            }
            function addRule(styleSheet, names, bold, italic, url) {
                if (!/^data:/i.test(url)) {
                    if (!(/^[^\/:]+:\/\//.test(url) || /^\//.test(url))) {
                        url = String(styleSheet.href).replace(/[^\/]*$/, '') + url;
                    }
                }
                names.forEach(function (name) {
                    name = name.replace(/^(['"]?)(.*?)\1$/, '$2');
                    if (bold) {
                        name += '|bold';
                    }
                    if (italic) {
                        name += '|italic';
                    }
                    result[name] = url;
                });
            }
        }
        function hasOwnProperty(obj, key) {
            return Object.prototype.hasOwnProperty.call(obj, key);
        }
        function getCounter(name) {
            name = '_counter_' + name;
            return nodeInfo[name];
        }
        function getAllCounters(name) {
            var values = [], p = nodeInfo;
            name = '_counter_' + name;
            while (p) {
                if (hasOwnProperty(p, name)) {
                    values.push(p[name]);
                }
                p = Object.getPrototypeOf(p);
            }
            return values.reverse();
        }
        function incCounter(name, inc) {
            var p = nodeInfo;
            name = '_counter_' + name;
            while (p && !hasOwnProperty(p, name)) {
                p = Object.getPrototypeOf(p);
            }
            if (!p) {
                p = nodeInfo._root;
            }
            p[name] = (p[name] || 0) + (inc == null ? 1 : inc);
        }
        function resetCounter(name, val) {
            name = '_counter_' + name;
            nodeInfo[name] = val == null ? 0 : val;
        }
        function doCounters(a, f, def) {
            for (var i = 0; i < a.length;) {
                var name = a[i++];
                var val = parseFloat(a[i]);
                if (isNaN(val)) {
                    f(name, def);
                } else {
                    f(name, val);
                    ++i;
                }
            }
        }
        function updateCounters(style) {
            var counterReset = getPropertyValue(style, 'counter-reset');
            if (counterReset) {
                doCounters(splitProperty(counterReset, /^\s+/), resetCounter, 0);
            }
            var counterIncrement = getPropertyValue(style, 'counter-increment');
            if (counterIncrement) {
                doCounters(splitProperty(counterIncrement, /^\s+/), incCounter, 1);
            }
        }
        function parseColor$1(str, css) {
            var color = kendo.parseColor(str, true);
            if (color) {
                color = color.toRGB();
                if (css) {
                    color = color.toCssRgba();
                } else if (color.a === 0) {
                    color = null;
                }
            }
            return color;
        }
        function whenImagesAreActuallyLoaded(elements, callback) {
            var pending = 0;
            elements.forEach(function (el) {
                var images = el.querySelectorAll('img');
                for (var i = 0; i < images.length; ++i) {
                    var img = images[i];
                    if (!img.complete) {
                        pending++;
                        img.onload = img.onerror = next;
                    }
                }
            });
            if (!pending) {
                next();
            }
            function next() {
                if (--pending <= 0) {
                    callback();
                }
            }
        }
        function cacheImages(element, callback) {
            var urls = [];
            function add(url) {
                if (!IMAGE_CACHE[url]) {
                    IMAGE_CACHE[url] = true;
                    urls.push(url);
                }
            }
            (function dive(element) {
                if (/^img$/i.test(element.tagName)) {
                    add(element.src);
                }
                parseBackgroundImage(getPropertyValue(getComputedStyle(element), 'background-image')).forEach(function (bg) {
                    if (bg.type == 'url') {
                        add(bg.url);
                    }
                });
                if (element.children) {
                    slice$1(element.children).forEach(dive);
                }
            }(element));
            var count = urls.length;
            function next() {
                if (--count <= 0) {
                    callback();
                }
            }
            if (count === 0) {
                next();
            }
            urls.forEach(function (url) {
                var img = IMAGE_CACHE[url] = new window.Image();
                if (!/^data:/i.test(url)) {
                    img.crossOrigin = 'Anonymous';
                }
                img.src = url;
                if (img.complete) {
                    next();
                } else {
                    img.onload = next;
                    img.onerror = function () {
                        IMAGE_CACHE[url] = null;
                        next();
                    };
                }
            });
        }
        function alphaNumeral(n) {
            var result = '';
            do {
                var r = n % 26;
                result = String.fromCharCode(97 + r) + result;
                n = Math.floor(n / 26);
            } while (n > 0);
            return result;
        }
        function pushNodeInfo(element, style, group) {
            nodeInfo = Object.create(nodeInfo);
            nodeInfo[element.tagName.toLowerCase()] = {
                element: element,
                style: style
            };
            var decoration = getPropertyValue(style, 'text-decoration');
            if (decoration && decoration != 'none') {
                var color = getPropertyValue(style, 'color');
                decoration.split(/\s+/g).forEach(function (name) {
                    if (!nodeInfo[name]) {
                        nodeInfo[name] = color;
                    }
                });
            }
            if (createsStackingContext(style)) {
                nodeInfo._stackingContext = {
                    element: element,
                    group: group
                };
            }
        }
        function popNodeInfo() {
            nodeInfo = Object.getPrototypeOf(nodeInfo);
        }
        function updateClipbox(path) {
            if (nodeInfo._clipbox != null) {
                var box = path.bbox(nodeInfo._matrix);
                if (nodeInfo._clipbox) {
                    nodeInfo._clipbox = Rect.intersect(nodeInfo._clipbox, box);
                } else {
                    nodeInfo._clipbox = box;
                }
            }
        }
        function emptyClipbox() {
            var cb = nodeInfo._clipbox;
            if (cb == null) {
                return true;
            }
            if (cb) {
                return cb.width() === 0 || cb.height() === 0;
            }
        }
        function createsStackingContext(style) {
            function prop(name) {
                return getPropertyValue(style, name);
            }
            if (prop('transform') != 'none' || prop('position') != 'static' || prop('z-index') != 'auto' || prop('opacity') < 1) {
                return true;
            }
        }
        function getComputedStyle(element, pseudoElt) {
            return window.getComputedStyle(element, pseudoElt || null);
        }
        function getPropertyValue(style, prop, defa) {
            var val = style.getPropertyValue(prop);
            if (val == null || val === '') {
                if (browser.webkit) {
                    val = style.getPropertyValue('-webkit-' + prop);
                } else if (browser.mozilla) {
                    val = style.getPropertyValue('-moz-' + prop);
                } else if (browser.opera) {
                    val = style.getPropertyValue('-o-' + prop);
                } else if (browser.msie) {
                    val = style.getPropertyValue('-ms-' + prop);
                }
            }
            if (arguments.length > 2 && (val == null || val === '')) {
                return defa;
            } else {
                return val;
            }
        }
        function pleaseSetPropertyValue(style, prop, value, important) {
            style.setProperty(prop, value, important);
            if (browser.webkit) {
                style.setProperty('-webkit-' + prop, value, important);
            } else if (browser.mozilla) {
                style.setProperty('-moz-' + prop, value, important);
            } else if (browser.opera) {
                style.setProperty('-o-' + prop, value, important);
            } else if (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$1(getPropertyValue(style, side + '-color'), true)
            };
        }
        function saveStyle(element, func) {
            var prev = element.style.cssText;
            var result = func();
            element.style.cssText = prev;
            return result;
        }
        function getBorderRadius(style, side) {
            var r = getPropertyValue(style, 'border-' + side + '-radius').split(/\s+/g).map(parseFloat);
            if (r.length == 1) {
                r.push(r[0]);
            }
            return sanitizeRadius({
                x: r[0],
                y: r[1]
            });
        }
        function getContentBox(element) {
            var box = element.getBoundingClientRect();
            box = innerBox(box, 'border-*-width', element);
            box = innerBox(box, 'padding-*', element);
            return box;
        }
        function innerBox(box, prop, element) {
            var style, wt, wr, wb, wl;
            if (typeof prop == 'string') {
                style = getComputedStyle(element);
                wt = parseFloat(getPropertyValue(style, prop.replace('*', 'top')));
                wr = parseFloat(getPropertyValue(style, prop.replace('*', 'right')));
                wb = parseFloat(getPropertyValue(style, prop.replace('*', 'bottom')));
                wl = parseFloat(getPropertyValue(style, prop.replace('*', 'left')));
            } else if (typeof prop == 'number') {
                wt = wr = wb = wl = prop;
            }
            return {
                top: box.top + wt,
                right: box.right - wr,
                bottom: box.bottom - wb,
                left: box.left + wl,
                width: box.right - box.left - wr - wl,
                height: box.bottom - box.top - wb - wt
            };
        }
        function getTransform(style) {
            var transform$$1 = getPropertyValue(style, 'transform');
            if (transform$$1 == 'none') {
                return null;
            }
            var matrix = /^\s*matrix\(\s*(.*?)\s*\)\s*$/.exec(transform$$1);
            if (matrix) {
                var origin = getPropertyValue(style, 'transform-origin');
                matrix = matrix[1].split(/\s*,\s*/g).map(parseFloat);
                origin = origin.split(/\s+/g).map(parseFloat);
                return {
                    matrix: matrix,
                    origin: origin
                };
            }
        }
        function radiansToDegrees(radians) {
            return 180 * radians / Math.PI % 360;
        }
        function parseAngle(angle) {
            var num = parseFloat(angle);
            if (/grad$/.test(angle)) {
                return Math.PI * num / 200;
            } else if (/rad$/.test(angle)) {
                return num;
            } else if (/turn$/.test(angle)) {
                return Math.PI * num * 2;
            } else if (/deg$/.test(angle)) {
                return Math.PI * num / 180;
            }
        }
        function setTransform(shape, m) {
            m = new Matrix(m[0], m[1], m[2], m[3], m[4], m[5]);
            shape.transform(m);
            return m;
        }
        function setClipping(shape, clipPath) {
            shape.clip(clipPath);
        }
        function addArcToPath(path, x, y, options) {
            var points = new Arc$2([
                    x,
                    y
                ], options).curvePoints(), i = 1;
            while (i < points.length) {
                path.curveTo(points[i++], points[i++], points[i++]);
            }
        }
        function sanitizeRadius(r) {
            if (r.x <= 0 || r.y <= 0) {
                r.x = r.y = 0;
            }
            return r;
        }
        function adjustBorderRadiusForBox(box, rTL, rTR, rBR, rBL) {
            var tl_x = Math.max(0, rTL.x), tl_y = Math.max(0, rTL.y);
            var tr_x = Math.max(0, rTR.x), tr_y = Math.max(0, rTR.y);
            var br_x = Math.max(0, rBR.x), br_y = Math.max(0, rBR.y);
            var bl_x = Math.max(0, rBL.x), bl_y = Math.max(0, rBL.y);
            var f = Math.min(box.width / (tl_x + tr_x), box.height / (tr_y + br_y), box.width / (br_x + bl_x), box.height / (bl_y + tl_y));
            if (f < 1) {
                tl_x *= f;
                tl_y *= f;
                tr_x *= f;
                tr_y *= f;
                br_x *= f;
                br_y *= f;
                bl_x *= f;
                bl_y *= f;
            }
            return {
                tl: {
                    x: tl_x,
                    y: tl_y
                },
                tr: {
                    x: tr_x,
                    y: tr_y
                },
                br: {
                    x: br_x,
                    y: br_y
                },
                bl: {
                    x: bl_x,
                    y: bl_y
                }
            };
        }
        function elementRoundBox(element, box, type) {
            var style = getComputedStyle(element);
            var rTL = getBorderRadius(style, 'top-left');
            var rTR = getBorderRadius(style, 'top-right');
            var rBL = getBorderRadius(style, 'bottom-left');
            var rBR = getBorderRadius(style, 'bottom-right');
            if (type == 'padding' || type == 'content') {
                var bt = getBorder(style, 'top');
                var br = getBorder(style, 'right');
                var bb = getBorder(style, 'bottom');
                var bl = getBorder(style, 'left');
                rTL.x -= bl.width;
                rTL.y -= bt.width;
                rTR.x -= br.width;
                rTR.y -= bt.width;
                rBR.x -= br.width;
                rBR.y -= bb.width;
                rBL.x -= bl.width;
                rBL.y -= bb.width;
                if (type == 'content') {
                    var pt = parseFloat(getPropertyValue(style, 'padding-top'));
                    var pr = parseFloat(getPropertyValue(style, 'padding-right'));
                    var pb = parseFloat(getPropertyValue(style, 'padding-bottom'));
                    var pl = parseFloat(getPropertyValue(style, 'padding-left'));
                    rTL.x -= pl;
                    rTL.y -= pt;
                    rTR.x -= pr;
                    rTR.y -= pt;
                    rBR.x -= pr;
                    rBR.y -= pb;
                    rBL.x -= pl;
                    rBL.y -= pb;
                }
            }
            if (typeof type == 'number') {
                rTL.x -= type;
                rTL.y -= type;
                rTR.x -= type;
                rTR.y -= type;
                rBR.x -= type;
                rBR.y -= type;
                rBL.x -= type;
                rBL.y -= type;
            }
            return roundBox(box, rTL, rTR, rBR, rBL);
        }
        function roundBox(box, rTL0, rTR0, rBR0, rBL0) {
            var tmp = adjustBorderRadiusForBox(box, rTL0, rTR0, rBR0, rBL0);
            var rTL = tmp.tl;
            var rTR = tmp.tr;
            var rBR = tmp.br;
            var rBL = tmp.bl;
            var path = new Path({
                fill: null,
                stroke: null
            });
            path.moveTo(box.left, box.top + rTL.y);
            if (rTL.x) {
                addArcToPath(path, box.left + rTL.x, box.top + rTL.y, {
                    startAngle: -180,
                    endAngle: -90,
                    radiusX: rTL.x,
                    radiusY: rTL.y
                });
            }
            path.lineTo(box.right - rTR.x, box.top);
            if (rTR.x) {
                addArcToPath(path, box.right - rTR.x, box.top + rTR.y, {
                    startAngle: -90,
                    endAngle: 0,
                    radiusX: rTR.x,
                    radiusY: rTR.y
                });
            }
            path.lineTo(box.right, box.bottom - rBR.y);
            if (rBR.x) {
                addArcToPath(path, box.right - rBR.x, box.bottom - rBR.y, {
                    startAngle: 0,
                    endAngle: 90,
                    radiusX: rBR.x,
                    radiusY: rBR.y
                });
            }
            path.lineTo(box.left + rBL.x, box.bottom);
            if (rBL.x) {
                addArcToPath(path, box.left + rBL.x, box.bottom - rBL.y, {
                    startAngle: 90,
                    endAngle: 180,
                    radiusX: rBL.x,
                    radiusY: rBL.y
                });
            }
            return path.close();
        }
        function formatCounter(val, style) {
            var str = String(parseFloat(val));
            switch (style) {
            case 'decimal-leading-zero':
                if (str.length < 2) {
                    str = '0' + str;
                }
                return str;
            case 'lower-roman':
                return arabicToRoman(val).toLowerCase();
            case 'upper-roman':
                return arabicToRoman(val).toUpperCase();
            case 'lower-latin':
            case 'lower-alpha':
                return alphaNumeral(val - 1);
            case 'upper-latin':
            case 'upper-alpha':
                return alphaNumeral(val - 1).toUpperCase();
            default:
                return str;
            }
        }
        function evalPseudoElementContent(element, content) {
            function displayCounter(name, style, separator) {
                if (!separator) {
                    return formatCounter(getCounter(name) || 0, style);
                }
                separator = separator.replace(/^\s*(["'])(.*)\1\s*$/, '$2');
                return getAllCounters(name).map(function (val) {
                    return formatCounter(val, style);
                }).join(separator);
            }
            var a = splitProperty(content, /^\s+/);
            var result = [], m;
            a.forEach(function (el) {
                var tmp;
                if (m = /^\s*(["'])(.*)\1\s*$/.exec(el)) {
                    result.push(m[2].replace(/\\([0-9a-f]{4})/gi, function (s, p) {
                        return String.fromCharCode(parseInt(p, 16));
                    }));
                } else if (m = /^\s*counter\((.*?)\)\s*$/.exec(el)) {
                    tmp = splitProperty(m[1]);
                    result.push(displayCounter(tmp[0], tmp[1]));
                } else if (m = /^\s*counters\((.*?)\)\s*$/.exec(el)) {
                    tmp = splitProperty(m[1]);
                    result.push(displayCounter(tmp[0], tmp[2], tmp[1]));
                } else if (m = /^\s*attr\((.*?)\)\s*$/.exec(el)) {
                    result.push(element.getAttribute(m[1]) || '');
                } else {
                    result.push(el);
                }
            });
            return result.join('');
        }
        function getCssText(style) {
            if (style.cssText) {
                return style.cssText;
            }
            var result = [];
            for (var i = 0; i < style.length; ++i) {
                result.push(style[i] + ': ' + getPropertyValue(style, style[i]));
            }
            return result.join(';\n');
        }
        function _renderWithPseudoElements(element, group) {
            if (element.tagName == KENDO_PSEUDO_ELEMENT) {
                _renderElement(element, group);
                return;
            }
            var fake = [];
            function pseudo(kind, place) {
                var style = getComputedStyle(element, kind);
                updateCounters(style);
                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$1(backgroundColor);
            var backgroundImage = parseBackgroundImage(getPropertyValue(style, 'background-image'));
            var backgroundRepeat = splitProperty(getPropertyValue(style, 'background-repeat'));
            var backgroundPosition = splitProperty(getPropertyValue(style, 'background-position'));
            var backgroundOrigin = splitProperty(getPropertyValue(style, 'background-origin'));
            var backgroundSize = splitProperty(getPropertyValue(style, 'background-size'));
            if (browser.msie && browser.version < 10) {
                backgroundPosition = splitProperty(element.currentStyle.backgroundPosition);
            }
            var innerbox = innerBox(element.getBoundingClientRect(), 'border-*-width', element);
            (function () {
                var clip = getPropertyValue(style, 'clip');
                var m = /^\s*rect\((.*)\)\s*$/.exec(clip);
                if (m) {
                    var a = m[1].split(/[ ,]+/g);
                    var top = a[0] == 'auto' ? innerbox.top : parseFloat(a[0]) + innerbox.top;
                    var right = a[1] == 'auto' ? innerbox.right : parseFloat(a[1]) + innerbox.left;
                    var bottom = a[2] == 'auto' ? innerbox.bottom : parseFloat(a[2]) + innerbox.top;
                    var left = a[3] == 'auto' ? innerbox.left : parseFloat(a[3]) + innerbox.left;
                    var tmp = new Group();
                    var clipPath = new Path().moveTo(left, top).lineTo(right, top).lineTo(right, bottom).lineTo(left, bottom).close();
                    setClipping(tmp, clipPath);
                    group.append(tmp);
                    group = tmp;
                    updateClipbox(clipPath);
                }
            }());
            var boxes, i, cells;
            var display = getPropertyValue(style, 'display');
            if (display == 'table-row') {
                boxes = [];
                for (i = 0, cells = element.children; i < cells.length; ++i) {
                    boxes.push(cells[i].getBoundingClientRect());
                }
            } else {
                boxes = element.getClientRects();
                if (boxes.length == 1) {
                    boxes = [element.getBoundingClientRect()];
                }
            }
            boxes = adjustBoxes(boxes);
            for (i = 0; i < boxes.length; ++i) {
                drawOneBox(boxes[i], i === 0, i == boxes.length - 1);
            }
            if (boxes.length > 0 && display == 'list-item' && !element.getAttribute('kendo-no-bullet')) {
                drawBullet(boxes[0]);
            }
            (function () {
                function clipit() {
                    var clipPath = elementRoundBox(element, innerbox, 'padding');
                    var tmp = new Group();
                    setClipping(tmp, clipPath);
                    group.append(tmp);
                    group = tmp;
                    updateClipbox(clipPath);
                }
                if (isFormField(element)) {
                    clipit();
                } else if (/^(hidden|auto|scroll)/.test(getPropertyValue(style, 'overflow'))) {
                    clipit();
                } else if (/^(hidden|auto|scroll)/.test(getPropertyValue(style, 'overflow-x'))) {
                    clipit();
                } else if (/^(hidden|auto|scroll)/.test(getPropertyValue(style, 'overflow-y'))) {
                    clipit();
                }
            }());
            if (!maybeRenderWidget(element, group)) {
                renderContents(element, group);
            }
            return group;
            function adjustBoxes(boxes) {
                if (/^td$/i.test(element.tagName)) {
                    var table = nodeInfo.table;
                    if (table && getPropertyValue(table.style, 'border-collapse') == 'collapse') {
                        var tableBorderLeft = getBorder(table.style, 'left').width;
                        var tableBorderTop = getBorder(table.style, 'top').width;
                        if (tableBorderLeft === 0 && tableBorderTop === 0) {
                            return boxes;
                        }
                        var tableBox = table.element.getBoundingClientRect();
                        var firstCell = table.element.rows[0].cells[0];
                        var firstCellBox = firstCell.getBoundingClientRect();
                        if (firstCellBox.top == tableBox.top || firstCellBox.left == tableBox.left) {
                            return slice$1(boxes).map(function (box) {
                                return {
                                    left: box.left + tableBorderLeft,
                                    top: box.top + tableBorderTop,
                                    right: box.right + tableBorderLeft,
                                    bottom: box.bottom + tableBorderTop,
                                    height: box.height,
                                    width: box.width
                                };
                            });
                        }
                    }
                }
                return boxes;
            }
            function drawEdge(color, len, Wtop, Wleft, Wright, rl, rr, transform$$1) {
                if (Wtop <= 0) {
                    return;
                }
                var path, edge = new Group();
                setTransform(edge, transform$$1);
                group.append(edge);
                sanitizeRadius(rl);
                sanitizeRadius(rr);
                path = new Path({
                    fill: { color: color },
                    stroke: null
                });
                edge.append(path);
                path.moveTo(rl.x ? Math.max(rl.x, Wleft) : 0, 0).lineTo(len - (rr.x ? Math.max(rr.x, Wright) : 0), 0).lineTo(len - Math.max(rr.x, Wright), Wtop).lineTo(Math.max(rl.x, Wleft), Wtop).close();
                if (rl.x) {
                    drawRoundCorner(Wleft, rl, [
                        -1,
                        0,
                        0,
                        1,
                        rl.x,
                        0
                    ]);
                }
                if (rr.x) {
                    drawRoundCorner(Wright, rr, [
                        1,
                        0,
                        0,
                        1,
                        len - rr.x,
                        0
                    ]);
                }
                function drawRoundCorner(Wright, r, transform$$1) {
                    var angle = Math.PI / 2 * Wright / (Wright + Wtop);
                    var ri = {
                        x: r.x - Wright,
                        y: r.y - Wtop
                    };
                    var path = new Path({
                        fill: { color: color },
                        stroke: null
                    }).moveTo(0, 0);
                    setTransform(path, transform$$1);
                    addArcToPath(path, 0, r.y, {
                        startAngle: -90,
                        endAngle: -radiansToDegrees(angle),
                        radiusX: r.x,
                        radiusY: r.y
                    });
                    if (ri.x > 0 && ri.y > 0) {
                        path.lineTo(ri.x * Math.cos(angle), r.y - ri.y * Math.sin(angle));
                        addArcToPath(path, 0, r.y, {
                            startAngle: -radiansToDegrees(angle),
                            endAngle: -90,
                            radiusX: ri.x,
                            radiusY: ri.y,
                            anticlockwise: true
                        });
                    } else if (ri.x > 0) {
                        path.lineTo(ri.x, Wtop).lineTo(0, Wtop);
                    } else {
                        path.lineTo(ri.x, Wtop).lineTo(ri.x, 0);
                    }
                    edge.append(path.close());
                }
            }
            function drawBackground(box) {
                var background = new Group();
                setClipping(background, roundBox(box, rTL0, rTR0, rBR0, rBL0));
                group.append(background);
                if (element.tagName == 'A' && element.href && !/^#?$/.test(element.getAttribute('href'))) {
                    if (!nodeInfo._avoidLinks || !matches(element, nodeInfo._avoidLinks)) {
                        background._pdfLink = {
                            url: element.href,
                            top: box.top,
                            right: box.right,
                            bottom: box.bottom,
                            left: box.left
                        };
                    }
                }
                if (backgroundColor) {
                    var path = new Path({
                        fill: { color: backgroundColor.toCssRgba() },
                        stroke: null
                    });
                    path.moveTo(box.left, box.top).lineTo(box.right, box.top).lineTo(box.right, box.bottom).lineTo(box.left, box.bottom).close();
                    background.append(path);
                }
                for (var i = backgroundImage.length; --i >= 0;) {
                    drawOneBackground(background, box, backgroundImage[i], backgroundRepeat[i % backgroundRepeat.length], backgroundPosition[i % backgroundPosition.length], backgroundOrigin[i % backgroundOrigin.length], backgroundSize[i % backgroundSize.length]);
                }
            }
            function drawOneBackground(group, box, background, backgroundRepeat, backgroundPosition, backgroundOrigin, backgroundSize) {
                if (!background || background == 'none') {
                    return;
                }
                if (background.type == 'url') {
                    if (/^url\(\"data:image\/svg/i.test(background.url)) {
                        return;
                    }
                    var img = IMAGE_CACHE[background.url];
                    if (img && img.width > 0 && img.height > 0) {
                        drawBackgroundImage(group, box, img.width, img.height, function (group, rect) {
                            group.append(new Image$1(background.url, rect));
                        });
                    }
                } else if (background.type == 'linear') {
                    drawBackgroundImage(group, box, box.width, box.height, gradientRenderer(background));
                } else {
                    return;
                }
                function drawBackgroundImage(group, box, img_width, img_height, renderBG) {
                    var aspect_ratio = img_width / img_height, f;
                    var orgBox = box;
                    if (backgroundOrigin == 'content-box') {
                        orgBox = innerBox(orgBox, 'border-*-width', element);
                        orgBox = innerBox(orgBox, 'padding-*', element);
                    } else if (backgroundOrigin == 'padding-box') {
                        orgBox = innerBox(orgBox, 'border-*-width', element);
                    }
                    if (!/^\s*auto(\s+auto)?\s*$/.test(backgroundSize)) {
                        if (backgroundSize == 'contain') {
                            f = Math.min(orgBox.width / img_width, orgBox.height / img_height);
                            img_width *= f;
                            img_height *= f;
                        } else if (backgroundSize == 'cover') {
                            f = Math.max(orgBox.width / img_width, orgBox.height / img_height);
                            img_width *= f;
                            img_height *= f;
                        } else {
                            var size = backgroundSize.split(/\s+/g);
                            if (/%$/.test(size[0])) {
                                img_width = orgBox.width * parseFloat(size[0]) / 100;
                            } else {
                                img_width = parseFloat(size[0]);
                            }
                            if (size.length == 1 || size[1] == 'auto') {
                                img_height = img_width / aspect_ratio;
                            } else if (/%$/.test(size[1])) {
                                img_height = orgBox.height * parseFloat(size[1]) / 100;
                            } else {
                                img_height = parseFloat(size[1]);
                            }
                        }
                    }
                    var pos = String(backgroundPosition);
                    switch (pos) {
                    case 'bottom':
                        pos = '50% 100%';
                        break;
                    case 'top':
                        pos = '50% 0';
                        break;
                    case 'left':
                        pos = '0 50%';
                        break;
                    case 'right':
                        pos = '100% 50%';
                        break;
                    case 'center':
                        pos = '50% 50%';
                        break;
                    }
                    pos = pos.split(/\s+/);
                    if (pos.length == 1) {
                        pos[1] = '50%';
                    }
                    if (/%$/.test(pos[0])) {
                        pos[0] = parseFloat(pos[0]) / 100 * (orgBox.width - img_width);
                    } else {
                        pos[0] = parseFloat(pos[0]);
                    }
                    if (/%$/.test(pos[1])) {
                        pos[1] = parseFloat(pos[1]) / 100 * (orgBox.height - img_height);
                    } else {
                        pos[1] = parseFloat(pos[1]);
                    }
                    var rect = new Rect([
                        orgBox.left + pos[0],
                        orgBox.top + pos[1]
                    ], [
                        img_width,
                        img_height
                    ]);
                    function rewX() {
                        while (rect.origin.x > box.left) {
                            rect.origin.x -= img_width;
                        }
                    }
                    function rewY() {
                        while (rect.origin.y > box.top) {
                            rect.origin.y -= img_height;
                        }
                    }
                    function repeatX() {
                        while (rect.origin.x < box.right) {
                            renderBG(group, rect.clone());
                            rect.origin.x += img_width;
                        }
                    }
                    if (backgroundRepeat == 'no-repeat') {
                        renderBG(group, rect);
                    } else if (backgroundRepeat == 'repeat-x') {
                        rewX();
                        repeatX();
                    } else if (backgroundRepeat == 'repeat-y') {
                        rewY();
                        while (rect.origin.y < box.bottom) {
                            renderBG(group, rect.clone());
                            rect.origin.y += img_height;
                        }
                    } else if (backgroundRepeat == 'repeat') {
                        rewX();
                        rewY();
                        var origin = rect.origin.clone();
                        while (rect.origin.y < box.bottom) {
                            rect.origin.x = origin.x;
                            repeatX();
                            rect.origin.y += img_height;
                        }
                    }
                }
            }
            function drawBullet() {
                var listStyleType = getPropertyValue(style, 'list-style-type');
                if (listStyleType == 'none') {
                    return;
                }
                var listStylePosition = getPropertyValue(style, 'list-style-position');
                function _drawBullet(f) {
                    saveStyle(element, function () {
                        element.style.position = 'relative';
                        var bullet = element.ownerDocument.createElement(KENDO_PSEUDO_ELEMENT);
                        bullet.style.position = 'absolute';
                        bullet.style.boxSizing = 'border-box';
                        if (listStylePosition == 'outside') {
                            bullet.style.width = '6em';
                            bullet.style.left = '-6.8em';
                            bullet.style.textAlign = 'right';
                        } else {
                            bullet.style.left = '0px';
                        }
                        f(bullet);
                        element.insertBefore(bullet, element.firstChild);
                        renderElement(bullet, group);
                        element.removeChild(bullet);
                    });
                }
                function elementIndex(f) {
                    var a = element.parentNode.children;
                    var k = element.getAttribute('kendo-split-index');
                    if (k != null) {
                        return f(k | 0, a.length);
                    }
                    for (var i = 0; i < a.length; ++i) {
                        if (a[i] === element) {
                            return f(i, a.length);
                        }
                    }
                }
                switch (listStyleType) {
                case 'circle':
                case 'disc':
                case 'square':
                    _drawBullet(function (bullet) {
                        bullet.style.fontSize = '60%';
                        bullet.style.lineHeight = '200%';
                        bullet.style.paddingRight = '0.5em';
                        bullet.style.fontFamily = 'DejaVu Serif';
                        bullet.innerHTML = {
                            'disc': '\u25CF',
                            'circle': '\u25EF',
                            'square': '\u25A0'
                        }[listStyleType];
                    });
                    break;
                case 'decimal':
                case 'decimal-leading-zero':
                    _drawBullet(function (bullet) {
                        elementIndex(function (idx) {
                            ++idx;
                            if (listStyleType == 'decimal-leading-zero' && idx < 10) {
                                idx = '0' + idx;
                            }
                            bullet.innerHTML = idx + '.';
                        });
                    });
                    break;
                case 'lower-roman':
                case 'upper-roman':
                    _drawBullet(function (bullet) {
                        elementIndex(function (idx) {
                            idx = arabicToRoman(idx + 1);
                            if (listStyleType == 'upper-roman') {
                                idx = idx.toUpperCase();
                            }
                            bullet.innerHTML = idx + '.';
                        });
                    });
                    break;
                case 'lower-latin':
                case 'lower-alpha':
                case 'upper-latin':
                case 'upper-alpha':
                    _drawBullet(function (bullet) {
                        elementIndex(function (idx) {
                            idx = alphaNumeral(idx);
                            if (/^upper/i.test(listStyleType)) {
                                idx = idx.toUpperCase();
                            }
                            bullet.innerHTML = idx + '.';
                        });
                    });
                    break;
                }
            }
            function drawOneBox(box, isFirst, isLast) {
                if (box.width === 0 || box.height === 0) {
                    return;
                }
                drawBackground(box);
                var shouldDrawLeft = left.width > 0 && (isFirst && dir == 'ltr' || isLast && dir == 'rtl');
                var shouldDrawRight = right.width > 0 && (isLast && dir == 'ltr' || isFirst && dir == 'rtl');
                if (top.width === 0 && left.width === 0 && right.width === 0 && bottom.width === 0) {
                    return;
                }
                if (top.color == right.color && top.color == bottom.color && top.color == left.color) {
                    if (top.width == right.width && top.width == bottom.width && top.width == left.width) {
                        if (shouldDrawLeft && shouldDrawRight) {
                            box = innerBox(box, top.width / 2);
                            var path = elementRoundBox(element, box, top.width / 2);
                            path.options.stroke = {
                                color: top.color,
                                width: top.width
                            };
                            group.append(path);
                            return;
                        }
                    }
                }
                if (rTL0.x === 0 && rTR0.x === 0 && rBR0.x === 0 && rBL0.x === 0) {
                    if (top.width < 2 && left.width < 2 && right.width < 2 && bottom.width < 2) {
                        if (top.width > 0) {
                            group.append(new Path({
                                stroke: {
                                    width: top.width,
                                    color: top.color
                                }
                            }).moveTo(box.left, box.top + top.width / 2).lineTo(box.right, box.top + top.width / 2));
                        }
                        if (bottom.width > 0) {
                            group.append(new Path({
                                stroke: {
                                    width: bottom.width,
                                    color: bottom.color
                                }
                            }).moveTo(box.left, box.bottom - bottom.width / 2).lineTo(box.right, box.bottom - bottom.width / 2));
                        }
                        if (shouldDrawLeft) {
                            group.append(new Path({
                                stroke: {
                                    width: left.width,
                                    color: left.color
                                }
                            }).moveTo(box.left + left.width / 2, box.top).lineTo(box.left + left.width / 2, box.bottom));
                        }
                        if (shouldDrawRight) {
                            group.append(new Path({
                                stroke: {
                                    width: right.width,
                                    color: right.color
                                }
                            }).moveTo(box.right - right.width / 2, box.top).lineTo(box.right - right.width / 2, box.bottom));
                        }
                        return;
                    }
                }
                var tmp = adjustBorderRadiusForBox(box, rTL0, rTR0, rBR0, rBL0);
                var rTL = tmp.tl;
                var rTR = tmp.tr;
                var rBR = tmp.br;
                var rBL = tmp.bl;
                drawEdge(top.color, box.width, top.width, left.width, right.width, rTL, rTR, [
                    1,
                    0,
                    0,
                    1,
                    box.left,
                    box.top
                ]);
                drawEdge(bottom.color, box.width, bottom.width, right.width, left.width, rBR, rBL, [
                    -1,
                    0,
                    0,
                    -1,
                    box.right,
                    box.bottom
                ]);
                function inv(p) {
                    return {
                        x: p.y,
                        y: p.x
                    };
                }
                drawEdge(left.color, box.height, left.width, bottom.width, top.width, inv(rBL), inv(rTL), [
                    0,
                    -1,
                    1,
                    0,
                    box.left,
                    box.bottom
                ]);
                drawEdge(right.color, box.height, right.width, top.width, bottom.width, inv(rTR), inv(rBR), [
                    0,
                    1,
                    -1,
                    0,
                    box.right,
                    box.top
                ]);
            }
        }
        function gradientRenderer(gradient) {
            return function (group, rect) {
                var width = rect.width(), height = rect.height();
                switch (gradient.type) {
                case 'linear':
                    var angle = gradient.angle != null ? gradient.angle : Math.PI;
                    switch (gradient.to) {
                    case 'top':
                        angle = 0;
                        break;
                    case 'left':
                        angle = -Math.PI / 2;
                        break;
                    case 'bottom':
                        angle = Math.PI;
                        break;
                    case 'right':
                        angle = Math.PI / 2;
                        break;
                    case 'top left':
                    case 'left top':
                        angle = -Math.atan2(height, width);
                        break;
                    case 'top right':
                    case 'right top':
                        angle = Math.atan2(height, width);
                        break;
                    case 'bottom left':
                    case 'left bottom':
                        angle = Math.PI + Math.atan2(height, width);
                        break;
                    case 'bottom right':
                    case 'right bottom':
                        angle = Math.PI - Math.atan2(height, width);
                        break;
                    }
                    if (gradient.reverse) {
                        angle -= Math.PI;
                    }
                    angle %= 2 * Math.PI;
                    if (angle < 0) {
                        angle += 2 * Math.PI;
                    }
                    var pxlen = Math.abs(width * Math.sin(angle)) + Math.abs(height * Math.cos(angle));
                    var scaledAngle = Math.atan(width * Math.tan(angle) / height);
                    var sin = Math.sin(scaledAngle), cos = Math.cos(scaledAngle);
                    var len = Math.abs(sin) + Math.abs(cos);
                    var x = len / 2 * sin;
                    var y = len / 2 * cos;
                    if (angle > Math.PI / 2 && angle <= 3 * Math.PI / 2) {
                        x = -x;
                        y = -y;
                    }
                    var implicit = [], right = 0;
                    var stops = gradient.stops.map(function (s, i) {
                        var offset = s.percent;
                        if (offset) {
                            offset = parseFloat(offset) / 100;
                        } else if (s.length) {
                            offset = parseFloat(s.length) / pxlen;
                        } else if (i === 0) {
                            offset = 0;
                        } else if (i == gradient.stops.length - 1) {
                            offset = 1;
                        }
                        var stop = {
                            color: s.color.toCssRgba(),
                            offset: offset
                        };
                        if (offset != null) {
                            right = offset;
                            implicit.forEach(function (s, i) {
                                var stop = s.stop;
                                stop.offset = s.left + (right - s.left) * (i + 1) / (implicit.length + 1);
                            });
                            implicit = [];
                        } else {
                            implicit.push({
                                left: right,
                                stop: stop
                            });
                        }
                        return stop;
                    });
                    var start = [
                        0.5 - x,
                        0.5 + y
                    ];
                    var end = [
                        0.5 + x,
                        0.5 - y
                    ];
                    group.append(Path.fromRect(rect).stroke(null).fill(new LinearGradient({
                        start: start,
                        end: end,
                        stops: stops,
                        userSpace: false
                    })));
                    break;
                case 'radial':
                    if (window.console && window.console.log) {
                        window.console.log('Radial gradients are not yet supported in HTML renderer');
                    }
                    break;
                }
            };
        }
        function maybeRenderWidget(element, group) {
            if (window.kendo && window.kendo.jQuery && element.getAttribute(window.kendo.attr('role'))) {
                var widget = window.kendo.widgetInstance(window.kendo.jQuery(element));
                if (widget && (widget.exportDOMVisual || widget.exportVisual)) {
                    var visual;
                    if (widget.exportDOMVisual) {
                        visual = widget.exportDOMVisual();
                    } else {
                        visual = widget.exportVisual();
                    }
                    if (!visual) {
                        return false;
                    }
                    var wrap$$1 = new Group();
                    wrap$$1.children.push(visual);
                    var bbox = element.getBoundingClientRect();
                    wrap$$1.transform(transform().translate(bbox.left, bbox.top));
                    group.append(wrap$$1);
                    return true;
                }
            }
        }
        function renderImage(element, url, group) {
            var box = getContentBox(element);
            var rect = new Rect([
                box.left,
                box.top
            ], [
                box.width,
                box.height
            ]);
            var image = new Image$1(url, rect);
            setClipping(image, elementRoundBox(element, box, 'content'));
            group.append(image);
        }
        function zIndexSort(a, b) {
            var sa = getComputedStyle(a);
            var sb = getComputedStyle(b);
            var za = parseFloat(getPropertyValue(sa, 'z-index'));
            var zb = parseFloat(getPropertyValue(sb, 'z-index'));
            var pa = getPropertyValue(sa, 'position');
            var pb = getPropertyValue(sb, 'position');
            if (isNaN(za) && isNaN(zb)) {
                if (/static|absolute/.test(pa) && /static|absolute/.test(pb)) {
                    return 0;
                }
                if (pa == 'static') {
                    return -1;
                }
                if (pb == 'static') {
                    return 1;
                }
                return 0;
            }
            if (isNaN(za)) {
                return zb === 0 ? 0 : zb > 0 ? -1 : 1;
            }
            if (isNaN(zb)) {
                return za === 0 ? 0 : za > 0 ? 1 : -1;
            }
            return parseFloat(za) - parseFloat(zb);
        }
        function isFormField(element) {
            return /^(?:textarea|select|input)$/i.test(element.tagName);
        }
        function getSelectedOption(element) {
            if (element.selectedOptions && element.selectedOptions.length > 0) {
                return element.selectedOptions[0];
            }
            return element.options[element.selectedIndex];
        }
        function renderCheckbox(element, group) {
            var style = getComputedStyle(element);
            var color = getPropertyValue(style, 'color');
            var box = element.getBoundingClientRect();
            if (element.type == 'checkbox') {
                group.append(Path.fromRect(new Rect([
                    box.left + 1,
                    box.top + 1
                ], [
                    box.width - 2,
                    box.height - 2
                ])).stroke(color, 1));
                if (element.checked) {
                    group.append(new Path().stroke(color, 1.2).moveTo(box.left + 0.22 * box.width, box.top + 0.55 * box.height).lineTo(box.left + 0.45 * box.width, box.top + 0.75 * box.height).lineTo(box.left + 0.78 * box.width, box.top + 0.22 * box.width));
                }
            } else {
                group.append(new Circle(new Circle$2([
                    (box.left + box.right) / 2,
                    (box.top + box.bottom) / 2
                ], Math.min(box.width - 2, box.height - 2) / 2)).stroke(color, 1));
                if (element.checked) {
                    group.append(new Circle(new Circle$2([
                        (box.left + box.right) / 2,
                        (box.top + box.bottom) / 2
                    ], Math.min(box.width - 8, box.height - 8) / 2)).fill(color).stroke(null));
                }
            }
        }
        function renderFormField(element, group) {
            var tag = element.tagName.toLowerCase();
            if (tag == 'input' && (element.type == 'checkbox' || element.type == 'radio')) {
                return renderCheckbox(element, group);
            }
            var p = element.parentNode;
            var doc = element.ownerDocument;
            var el = doc.createElement(KENDO_PSEUDO_ELEMENT);
            var option;
            el.style.cssText = getCssText(getComputedStyle(element));
            if (tag == 'input') {
                el.style.whiteSpace = 'pre';
            }
            if (tag == 'select' || tag == 'textarea') {
                el.style.overflow = 'auto';
            }
            if (tag == 'select') {
                if (element.multiple) {
                    for (var i = 0; i < element.options.length; ++i) {
                        option = doc.createElement(KENDO_PSEUDO_ELEMENT);
                        option.style.cssText = getCssText(getComputedStyle(element.options[i]));
                        option.style.display = 'block';
                        option.textContent = element.options[i].textContent;
                        el.appendChild(option);
                    }
                } else {
                    option = getSelectedOption(element);
                    if (option) {
                        el.textContent = option.textContent;
                    }
                }
            } else {
                el.textContent = element.value;
            }
            p.insertBefore(el, element);
            el.scrollLeft = element.scrollLeft;
            el.scrollTop = element.scrollTop;
            element.style.display = 'none';
            renderContents(el, group);
            element.style.display = '';
            p.removeChild(el);
        }
        function renderContents(element, group) {
            if (nodeInfo._stackingContext.element === element) {
                nodeInfo._stackingContext.group = group;
            }
            switch (element.tagName.toLowerCase()) {
            case 'img':
                renderImage(element, element.src, group);
                break;
            case 'canvas':
                try {
                    renderImage(element, element.toDataURL('image/png'), group);
                } catch (ex) {
                }
                break;
            case 'textarea':
            case 'input':
            case 'select':
                renderFormField(element, group);
                break;
            default:
                var children = [], floats = [], positioned = [];
                for (var i = element.firstChild; i; i = i.nextSibling) {
                    switch (i.nodeType) {
                    case 3:
                        if (/\S/.test(i.data)) {
                            renderText(element, i, group);
                        }
                        break;
                    case 1:
                        var style = getComputedStyle(i);
                        var floating = getPropertyValue(style, 'float');
                        var position = getPropertyValue(style, 'position');
                        if (position != 'static') {
                            positioned.push(i);
                        } else if (floating != 'none') {
                            floats.push(i);
                        } else {
                            children.push(i);
                        }
                        break;
                    }
                }
                mergeSort(children, zIndexSort).forEach(function (el) {
                    renderElement(el, group);
                });
                mergeSort(floats, zIndexSort).forEach(function (el) {
                    renderElement(el, group);
                });
                mergeSort(positioned, zIndexSort).forEach(function (el) {
                    renderElement(el, group);
                });
            }
        }
        function renderText(element, node, group) {
            if (emptyClipbox()) {
                return;
            }
            var style = getComputedStyle(element);
            if (parseFloat(getPropertyValue(style, 'text-indent')) < -500) {
                return;
            }
            var text = node.data;
            var start = 0;
            var end = text.search(/\S\s*$/) + 1;
            if (!end) {
                return;
            }
            var fontSize = getPropertyValue(style, 'font-size');
            var lineHeight = getPropertyValue(style, 'line-height');
            var font = [
                getPropertyValue(style, 'font-style'),
                getPropertyValue(style, 'font-variant'),
                getPropertyValue(style, 'font-weight'),
                fontSize,
                getPropertyValue(style, 'font-family')
            ].join(' ');
            fontSize = parseFloat(fontSize);
            lineHeight = parseFloat(lineHeight);
            if (fontSize === 0) {
                return;
            }
            var color = getPropertyValue(style, 'color');
            var range = element.ownerDocument.createRange();
            var align$$1 = getPropertyValue(style, 'text-align');
            var isJustified = align$$1 == 'justify';
            var columnCount = getPropertyValue(style, 'column-count', 1);
            var whiteSpace = getPropertyValue(style, 'white-space');
            var 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;
            var underline = nodeInfo['underline'];
            var lineThrough = nodeInfo['line-through'];
            var overline = nodeInfo['overline'];
            var hasDecoration = underline || lineThrough || overline;
            while (!doChunk()) {
            }
            if (browser.msie && textOverflow == 'ellipsis') {
                element.style.textOverflow = saveTextOverflow;
            }
            if (hasDecoration) {
                range.selectNode(node);
                slice$1(range.getClientRects()).forEach(decorate);
            }
            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 || columnCount > 1) {
                    pos = text.substr(start).search(/\s/);
                    if (pos >= 0) {
                        range.setEnd(node, start + pos);
                        var r = actuallyGetRangeBoundingRect(range);
                        if (r.bottom == box.bottom) {
                            box = r;
                            found = true;
                            start += pos;
                        }
                    }
                }
                if (!found) {
                    pos = function findEOL(min, eol, max) {
                        range.setEnd(node, eol);
                        var r = actuallyGetRangeBoundingRect(range);
                        if (r.bottom != box.bottom && min < eol) {
                            return findEOL(min, min + eol >> 1, eol);
                        } else if (r.right != box.right) {
                            box = r;
                            if (eol < max) {
                                return findEOL(eol, eol + max >> 1, max);
                            } else {
                                return eol;
                            }
                        } else {
                            return eol;
                        }
                    }(start, Math.min(end, start + estimateLineLength), end);
                    if (pos == start) {
                        return true;
                    }
                    start = pos;
                    pos = range.toString().search(/\s+$/);
                    if (pos === 0) {
                        return false;
                    }
                    if (pos > 0) {
                        range.setEnd(node, range.startOffset + pos);
                        box = actuallyGetRangeBoundingRect(range);
                    }
                }
                if (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 Rect([
                    box.left,
                    box.top
                ], [
                    box.width,
                    box.height
                ]), {
                    font: font,
                    fill: { color: color }
                });
                group.append(text);
            }
            function decorate(box) {
                line(underline, box.bottom);
                line(lineThrough, box.bottom - box.height / 2.7);
                line(overline, box.top);
                function line(color, ypos) {
                    if (color) {
                        var width = fontSize / 12;
                        var path = new Path({
                            stroke: {
                                width: width,
                                color: color
                            }
                        });
                        ypos -= width;
                        path.moveTo(box.left, ypos).lineTo(box.right, ypos);
                        group.append(path);
                    }
                }
            }
        }
        function groupInStackingContext(element, group, zIndex) {
            var main;
            if (zIndex != 'auto') {
                main = nodeInfo._stackingContext.group;
                zIndex = parseFloat(zIndex);
            } else {
                main = group;
                zIndex = 0;
            }
            var a = main.children;
            for (var i = 0; i < a.length; ++i) {
                if (a[i]._dom_zIndex != null && a[i]._dom_zIndex > zIndex) {
                    break;
                }
            }
            var tmp = new Group();
            main.insert(i, tmp);
            tmp._dom_zIndex = zIndex;
            if (main !== group) {
                if (nodeInfo._clipbox) {
                    var m = nodeInfo._matrix.invert();
                    var r = nodeInfo._clipbox.transformCopy(m);
                    setClipping(tmp, Path.fromRect(r));
                }
            }
            return tmp;
        }
        function renderElement(element, container) {
            var style = getComputedStyle(element);
            updateCounters(style);
            if (/^(style|script|link|meta|iframe|svg|col|colgroup)$/i.test(element.tagName)) {
                return;
            }
            if (nodeInfo._clipbox == null) {
                return;
            }
            var opacity = parseFloat(getPropertyValue(style, 'opacity'));
            var visibility = getPropertyValue(style, 'visibility');
            var display = getPropertyValue(style, 'display');
            if (opacity === 0 || visibility == 'hidden' || display == 'none') {
                return;
            }
            var tr = getTransform(style);
            var group;
            var zIndex = getPropertyValue(style, 'z-index');
            if ((tr || opacity < 1) && zIndex == 'auto') {
                zIndex = 0;
            }
            group = groupInStackingContext(element, container, zIndex);
            if (opacity < 1) {
                group.opacity(opacity * group.opacity());
            }
            pushNodeInfo(element, style, group);
            if (!tr) {
                _renderWithPseudoElements(element, group);
            } else {
                saveStyle(element, function () {
                    pleaseSetPropertyValue(element.style, 'transform', 'none', 'important');
                    pleaseSetPropertyValue(element.style, 'transition', 'none', 'important');
                    if (getPropertyValue(style, 'position') == 'static') {
                        pleaseSetPropertyValue(element.style, 'position', 'relative', 'important');
                    }
                    var bbox = element.getBoundingClientRect();
                    var x = bbox.left + tr.origin[0];
                    var y = bbox.top + tr.origin[1];
                    var m = [
                        1,
                        0,
                        0,
                        1,
                        -x,
                        -y
                    ];
                    m = mmul(m, tr.matrix);
                    m = mmul(m, [
                        1,
                        0,
                        0,
                        1,
                        x,
                        y
                    ]);
                    m = setTransform(group, m);
                    nodeInfo._matrix = nodeInfo._matrix.multiplyCopy(m);
                    _renderWithPseudoElements(element, group);
                });
            }
            popNodeInfo();
        }
        function mmul(a, b) {
            var a1 = a[0], b1 = a[1], c1 = a[2], d1 = a[3], e1 = a[4], f1 = a[5];
            var a2 = b[0], b2 = b[1], c2 = b[2], d2 = b[3], e2 = b[4], f2 = b[5];
            return [
                a1 * a2 + b1 * c2,
                a1 * b2 + b1 * d2,
                c1 * a2 + d1 * c2,
                c1 * b2 + d1 * d2,
                e1 * a2 + f1 * c2 + e2,
                e1 * b2 + f1 * d2 + f2
            ];
        }
        var drawing = {
            svg: svg,
            canvas: canvas,
            util: util,
            PathParser: PathParser,
            Surface: Surface,
            BaseNode: BaseNode,
            SurfaceFactory: SurfaceFactory,
            OptionsStore: OptionsStore,
            exportImage: exportImage,
            exportSVG: exportSVG,
            QuadNode: QuadNode,
            ShapesQuadTree: ShapesQuadTree,
            ObserversMixin: ObserversMixin,
            Element: Element$1,
            Circle: Circle,
            Arc: Arc,
            Path: Path,
            MultiPath: MultiPath,
            Text: Text,
            Image: Image$1,
            Group: Group,
            Layout: Layout,
            Rect: Rect$2,
            align: align,
            vAlign: vAlign,
            stack: stack,
            vStack: vStack,
            wrap: wrap,
            vWrap: vWrap,
            fit: fit,
            LinearGradient: LinearGradient,
            RadialGradient: RadialGradient,
            GradientStop: GradientStop,
            Gradient: Gradient,
            Animation: Animation,
            AnimationFactory: AnimationFactory,
            drawDOM: drawDOM
        };
        kendo.deepExtend(kendo, {
            drawing: drawing,
            geometry: geometry
        });
        kendo.drawing.Segment = kendo.geometry.Segment;
        kendo.dataviz.drawing = kendo.drawing;
        kendo.dataviz.geometry = kendo.geometry;
        kendo.drawing.util.measureText = kendo.util.measureText;
        kendo.drawing.util.objectKey = kendo.util.objectKey;
        kendo.drawing.Color = kendo.Color;
        kendo.util.encodeBase64 = kendo.drawing.util.encodeBase64;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.popup', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'popup',
        name: 'Pop-up',
        category: 'framework',
        depends: ['core'],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, Class = kendo.Class, support = kendo.support, getOffset = kendo.getOffset, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, OPEN = 'open', CLOSE = 'close', DEACTIVATE = 'deactivate', ACTIVATE = 'activate', CENTER = 'center', LEFT = 'left', RIGHT = 'right', TOP = 'top', BOTTOM = 'bottom', ABSOLUTE = 'absolute', HIDDEN = 'hidden', BODY = 'body', LOCATION = 'location', POSITION = 'position', VISIBLE = 'visible', EFFECTS = 'effects', ACTIVE = 'k-state-active', ACTIVEBORDER = 'k-state-border', ACTIVEBORDERREGEXP = /k-state-border-(\w+)/, ACTIVECHILDREN = '.k-picker-wrap, .k-dropdown-wrap, .k-link', MOUSEDOWN = 'down', DOCUMENT_ELEMENT = $(document.documentElement), proxy = $.proxy, WINDOW = $(window), SCROLL = 'scroll', cssPrefix = support.transitions.css, TRANSFORM = cssPrefix + 'transform', extend = $.extend, NS = '.kendoPopup', styles = [
                'font-size',
                'font-family',
                'font-stretch',
                'font-style',
                'font-weight',
                'line-height'
            ];
        function contains(container, target) {
            if (!container || !target) {
                return false;
            }
            return container === target || $.contains(container, target);
        }
        var Popup = Widget.extend({
            init: function (element, options) {
                var that = this, parentPopup;
                options = options || {};
                if (options.isRtl) {
                    options.origin = options.origin || BOTTOM + ' ' + RIGHT;
                    options.position = options.position || TOP + ' ' + RIGHT;
                }
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                that.collisions = options.collision ? options.collision.split(' ') : [];
                that.downEvent = kendo.applyEventMap(MOUSEDOWN, kendo.guid());
                if (that.collisions.length === 1) {
                    that.collisions.push(that.collisions[0]);
                }
                parentPopup = $(that.options.anchor).closest('.k-popup,.k-group').filter(':not([class^=km-])');
                options.appendTo = $($(options.appendTo)[0] || parentPopup[0] || document.body);
                that.element.hide().addClass('k-popup k-group k-reset').toggleClass('k-rtl', !!options.isRtl).css({ position: ABSOLUTE }).appendTo(options.appendTo).on('mouseenter' + NS, function () {
                    that._hovered = true;
                }).on('mouseleave' + NS, function () {
                    that._hovered = false;
                });
                that.wrapper = $();
                if (options.animation === false) {
                    options.animation = {
                        open: { effects: {} },
                        close: {
                            hide: true,
                            effects: {}
                        }
                    };
                }
                extend(options.animation.open, {
                    complete: function () {
                        that.wrapper.css({ overflow: VISIBLE });
                        that._activated = true;
                        that._trigger(ACTIVATE);
                    }
                });
                extend(options.animation.close, {
                    complete: function () {
                        that._animationClose();
                    }
                });
                that._mousedownProxy = function (e) {
                    that._mousedown(e);
                };
                if (support.mobileOS.android) {
                    that._resizeProxy = function (e) {
                        setTimeout(function () {
                            that._resize(e);
                        }, 600);
                    };
                } else {
                    that._resizeProxy = function (e) {
                        that._resize(e);
                    };
                }
                if (options.toggleTarget) {
                    $(options.toggleTarget).on(options.toggleEvent + NS, $.proxy(that.toggle, that));
                }
            },
            events: [
                OPEN,
                ACTIVATE,
                CLOSE,
                DEACTIVATE
            ],
            options: {
                name: 'Popup',
                toggleEvent: 'click',
                origin: BOTTOM + ' ' + LEFT,
                position: TOP + ' ' + LEFT,
                anchor: BODY,
                appendTo: null,
                collision: 'flip fit',
                viewport: window,
                copyAnchorStyles: true,
                autosize: false,
                modal: false,
                adjustSize: {
                    width: 0,
                    height: 0
                },
                animation: {
                    open: {
                        effects: 'slideIn:down',
                        transition: true,
                        duration: 200
                    },
                    close: {
                        duration: 100,
                        hide: true
                    }
                }
            },
            _animationClose: function () {
                var that = this;
                var location = that.wrapper.data(LOCATION);
                that.wrapper.hide();
                if (location) {
                    that.wrapper.css(location);
                }
                if (that.options.anchor != BODY) {
                    that._hideDirClass();
                }
                that._closing = false;
                that._trigger(DEACTIVATE);
            },
            destroy: function () {
                var that = this, options = that.options, element = that.element.off(NS), parent;
                Widget.fn.destroy.call(that);
                if (options.toggleTarget) {
                    $(options.toggleTarget).off(NS);
                }
                if (!options.modal) {
                    DOCUMENT_ELEMENT.unbind(that.downEvent, that._mousedownProxy);
                    that._toggleResize(false);
                }
                kendo.destroy(that.element.children());
                element.removeData();
                if (options.appendTo[0] === document.body) {
                    parent = element.parent('.k-animation-container');
                    if (parent[0]) {
                        parent.remove();
                    } else {
                        element.remove();
                    }
                }
            },
            open: function (x, y) {
                var that = this, fixed = {
                        isFixed: !isNaN(parseInt(y, 10)),
                        x: x,
                        y: y
                    }, element = that.element, options = that.options, animation, wrapper, anchor = $(options.anchor), mobile = element[0] && element.hasClass('km-widget');
                if (!that.visible()) {
                    if (options.copyAnchorStyles) {
                        if (mobile && styles[0] == 'font-size') {
                            styles.shift();
                        }
                        element.css(kendo.getComputedStyles(anchor[0], styles));
                    }
                    if (element.data('animating') || that._trigger(OPEN)) {
                        return;
                    }
                    that._activated = false;
                    if (!options.modal) {
                        DOCUMENT_ELEMENT.unbind(that.downEvent, that._mousedownProxy).bind(that.downEvent, that._mousedownProxy);
                        that._toggleResize(false);
                        that._toggleResize(true);
                    }
                    that.wrapper = wrapper = kendo.wrap(element, options.autosize).css({
                        overflow: HIDDEN,
                        display: 'block',
                        position: ABSOLUTE
                    });
                    if (support.mobileOS.android) {
                        wrapper.css(TRANSFORM, 'translatez(0)');
                    }
                    wrapper.css(POSITION);
                    if ($(options.appendTo)[0] == document.body) {
                        wrapper.css(TOP, '-10000px');
                    }
                    that.flipped = that._position(fixed);
                    animation = that._openAnimation();
                    if (options.anchor != BODY) {
                        that._showDirClass(animation);
                    }
                    element.data(EFFECTS, animation.effects).kendoStop(true).kendoAnimate(animation);
                }
            },
            _location: function (isFixed) {
                var that = this, element = that.element, options = that.options, wrapper, anchor = $(options.anchor), mobile = element[0] && element.hasClass('km-widget');
                if (options.copyAnchorStyles) {
                    if (mobile && styles[0] == 'font-size') {
                        styles.shift();
                    }
                    element.css(kendo.getComputedStyles(anchor[0], styles));
                }
                that.wrapper = wrapper = kendo.wrap(element, options.autosize).css({
                    overflow: HIDDEN,
                    display: 'block',
                    position: ABSOLUTE
                });
                if (support.mobileOS.android) {
                    wrapper.css(TRANSFORM, 'translatez(0)');
                }
                wrapper.css(POSITION);
                if ($(options.appendTo)[0] == document.body) {
                    wrapper.css(TOP, '-10000px');
                }
                that._position(isFixed || {});
                var offset = wrapper.offset();
                return {
                    width: kendo._outerWidth(wrapper),
                    height: kendo._outerHeight(wrapper),
                    left: offset.left,
                    top: offset.top
                };
            },
            _openAnimation: function () {
                var animation = extend(true, {}, this.options.animation.open);
                animation.effects = kendo.parseEffects(animation.effects, this.flipped);
                return animation;
            },
            _hideDirClass: function () {
                var anchor = $(this.options.anchor);
                var direction = ((anchor.attr('class') || '').match(ACTIVEBORDERREGEXP) || [
                    '',
                    'down'
                ])[1];
                var dirClass = ACTIVEBORDER + '-' + direction;
                anchor.removeClass(dirClass).children(ACTIVECHILDREN).removeClass(ACTIVE).removeClass(dirClass);
                this.element.removeClass(ACTIVEBORDER + '-' + kendo.directions[direction].reverse);
            },
            _showDirClass: function (animation) {
                var direction = animation.effects.slideIn ? animation.effects.slideIn.direction : 'down';
                var dirClass = ACTIVEBORDER + '-' + direction;
                $(this.options.anchor).addClass(dirClass).children(ACTIVECHILDREN).addClass(ACTIVE).addClass(dirClass);
                this.element.addClass(ACTIVEBORDER + '-' + kendo.directions[direction].reverse);
            },
            position: function () {
                if (this.visible()) {
                    this.flipped = this._position();
                }
            },
            toggle: function () {
                var that = this;
                that[that.visible() ? CLOSE : OPEN]();
            },
            visible: function () {
                return this.element.is(':' + VISIBLE);
            },
            close: function (skipEffects) {
                var that = this, options = that.options, wrap, animation, openEffects, closeEffects;
                if (that.visible()) {
                    wrap = that.wrapper[0] ? that.wrapper : kendo.wrap(that.element).hide();
                    that._toggleResize(false);
                    if (that._closing || that._trigger(CLOSE)) {
                        that._toggleResize(true);
                        return;
                    }
                    that.element.find('.k-popup').each(function () {
                        var that = $(this), popup = that.data('kendoPopup');
                        if (popup) {
                            popup.close(skipEffects);
                        }
                    });
                    DOCUMENT_ELEMENT.unbind(that.downEvent, that._mousedownProxy);
                    if (skipEffects) {
                        animation = {
                            hide: true,
                            effects: {}
                        };
                    } else {
                        animation = extend(true, {}, options.animation.close);
                        openEffects = that.element.data(EFFECTS);
                        closeEffects = animation.effects;
                        if (!closeEffects && !kendo.size(closeEffects) && openEffects && kendo.size(openEffects)) {
                            animation.effects = openEffects;
                            animation.reverse = true;
                        }
                        that._closing = true;
                    }
                    that.element.kendoStop(true);
                    wrap.css({ overflow: HIDDEN });
                    that.element.kendoAnimate(animation);
                    if (skipEffects) {
                        that._animationClose();
                    }
                }
            },
            _trigger: function (ev) {
                return this.trigger(ev, { type: ev });
            },
            _resize: function (e) {
                var that = this;
                if (support.resize.indexOf(e.type) !== -1) {
                    clearTimeout(that._resizeTimeout);
                    that._resizeTimeout = setTimeout(function () {
                        that._position();
                        that._resizeTimeout = null;
                    }, 50);
                } else {
                    if (!that._hovered || that._activated && that.element.hasClass('k-list-container')) {
                        that.close();
                    }
                }
            },
            _toggleResize: function (toggle) {
                var method = toggle ? 'on' : 'off';
                var eventNames = support.resize;
                if (!(support.mobileOS.ios || support.mobileOS.android)) {
                    eventNames += ' ' + SCROLL;
                }
                this._scrollableParents()[method](SCROLL, this._resizeProxy);
                WINDOW[method](eventNames, this._resizeProxy);
            },
            _mousedown: function (e) {
                var that = this, container = that.element[0], options = that.options, anchor = $(options.anchor)[0], toggleTarget = options.toggleTarget, target = kendo.eventTarget(e), popup = $(target).closest('.k-popup'), mobile = popup.parent().parent('.km-shim').length;
                popup = popup[0];
                if (!mobile && popup && popup !== that.element[0]) {
                    return;
                }
                if ($(e.target).closest('a').data('rel') === 'popover') {
                    return;
                }
                if (!contains(container, target) && !contains(anchor, target) && !(toggleTarget && contains($(toggleTarget)[0], target))) {
                    that.close();
                }
            },
            _fit: function (position, size, viewPortSize) {
                var output = 0;
                if (position + size > viewPortSize) {
                    output = viewPortSize - (position + size);
                }
                if (position < 0) {
                    output = -position;
                }
                return output;
            },
            _flip: function (offset, size, anchorSize, viewPortSize, origin, position, boxSize) {
                var output = 0;
                boxSize = boxSize || size;
                if (position !== origin && position !== CENTER && origin !== CENTER) {
                    if (offset + boxSize > viewPortSize) {
                        output += -(anchorSize + size);
                    }
                    if (offset + output < 0) {
                        output += anchorSize + size;
                    }
                }
                return output;
            },
            _scrollableParents: function () {
                return $(this.options.anchor).parentsUntil('body').filter(function (index, element) {
                    return kendo.isScrollable(element);
                });
            },
            _position: function (fixed) {
                var that = this, element = that.element, wrapper = that.wrapper, options = that.options, viewport = $(options.viewport), zoomLevel = support.zoomLevel(), isWindow = !!(viewport[0] == window && window.innerWidth && zoomLevel <= 1.02), anchor = $(options.anchor), origins = options.origin.toLowerCase().split(' '), positions = options.position.toLowerCase().split(' '), collisions = that.collisions, siblingContainer, parents, parentZIndex, zIndex = 10002, idx = 0, docEl = document.documentElement, length, viewportOffset, viewportWidth, viewportHeight;
                if (options.viewport === window) {
                    viewportOffset = {
                        top: window.pageYOffset || document.documentElement.scrollTop || 0,
                        left: window.pageXOffset || document.documentElement.scrollLeft || 0
                    };
                } else {
                    viewportOffset = viewport.offset();
                }
                if (isWindow) {
                    viewportWidth = window.innerWidth;
                    viewportHeight = window.innerHeight;
                } else {
                    viewportWidth = viewport.width();
                    viewportHeight = viewport.height();
                }
                if (isWindow && docEl.scrollHeight - docEl.clientHeight > 0) {
                    viewportWidth -= kendo.support.scrollbar();
                }
                siblingContainer = anchor.parents().filter(wrapper.siblings());
                if (siblingContainer[0]) {
                    parentZIndex = Math.max(Number(siblingContainer.css('zIndex')), 0);
                    if (parentZIndex) {
                        zIndex = parentZIndex + 10;
                    } else {
                        parents = anchor.parentsUntil(siblingContainer);
                        for (length = parents.length; idx < length; idx++) {
                            parentZIndex = Number($(parents[idx]).css('zIndex'));
                            if (parentZIndex && zIndex < parentZIndex) {
                                zIndex = parentZIndex + 10;
                            }
                        }
                    }
                }
                wrapper.css('zIndex', zIndex);
                if (fixed && fixed.isFixed) {
                    wrapper.css({
                        left: fixed.x,
                        top: fixed.y
                    });
                } else {
                    wrapper.css(that._align(origins, positions));
                }
                var pos = getOffset(wrapper, POSITION, anchor[0] === wrapper.offsetParent()[0]), offset = getOffset(wrapper), anchorParent = anchor.offsetParent().parent('.k-animation-container,.k-popup,.k-group');
                if (anchorParent.length) {
                    pos = getOffset(wrapper, POSITION, true);
                    offset = getOffset(wrapper);
                }
                offset.top -= viewportOffset.top;
                offset.left -= viewportOffset.left;
                if (!that.wrapper.data(LOCATION)) {
                    wrapper.data(LOCATION, extend({}, pos));
                }
                var offsets = extend({}, offset), location = extend({}, pos), adjustSize = options.adjustSize;
                if (collisions[0] === 'fit') {
                    location.top += that._fit(offsets.top, outerHeight(wrapper) + adjustSize.height, viewportHeight / zoomLevel);
                }
                if (collisions[1] === 'fit') {
                    location.left += that._fit(offsets.left, outerWidth(wrapper) + adjustSize.width, viewportWidth / zoomLevel);
                }
                var flipPos = extend({}, location);
                var elementHeight = outerHeight(element);
                var wrapperHeight = outerHeight(wrapper);
                if (!wrapper.height() && elementHeight) {
                    wrapperHeight = wrapperHeight + elementHeight;
                }
                if (collisions[0] === 'flip') {
                    location.top += that._flip(offsets.top, elementHeight, outerHeight(anchor), viewportHeight / zoomLevel, origins[0], positions[0], wrapperHeight);
                }
                if (collisions[1] === 'flip') {
                    location.left += that._flip(offsets.left, outerWidth(element), outerWidth(anchor), viewportWidth / zoomLevel, origins[1], positions[1], outerWidth(wrapper));
                }
                element.css(POSITION, ABSOLUTE);
                wrapper.css(location);
                return location.left != flipPos.left || location.top != flipPos.top;
            },
            _align: function (origin, position) {
                var that = this, element = that.wrapper, anchor = $(that.options.anchor), verticalOrigin = origin[0], horizontalOrigin = origin[1], verticalPosition = position[0], horizontalPosition = position[1], anchorOffset = getOffset(anchor), appendTo = $(that.options.appendTo), appendToOffset, width = outerWidth(element), height = outerHeight(element), anchorWidth = outerWidth(anchor), anchorHeight = outerHeight(anchor), top = anchorOffset.top, left = anchorOffset.left, round = Math.round;
                if (appendTo[0] != document.body) {
                    appendToOffset = getOffset(appendTo);
                    top -= appendToOffset.top;
                    left -= appendToOffset.left;
                }
                if (verticalOrigin === BOTTOM) {
                    top += anchorHeight;
                }
                if (verticalOrigin === CENTER) {
                    top += round(anchorHeight / 2);
                }
                if (verticalPosition === BOTTOM) {
                    top -= height;
                }
                if (verticalPosition === CENTER) {
                    top -= round(height / 2);
                }
                if (horizontalOrigin === RIGHT) {
                    left += anchorWidth;
                }
                if (horizontalOrigin === CENTER) {
                    left += round(anchorWidth / 2);
                }
                if (horizontalPosition === RIGHT) {
                    left -= width;
                }
                if (horizontalPosition === CENTER) {
                    left -= round(width / 2);
                }
                return {
                    top: top,
                    left: left
                };
            }
        });
        ui.plugin(Popup);
        var tabKeyTrapNS = 'kendoTabKeyTrap';
        var focusableNodesSelector = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex], *[contenteditable]';
        var TabKeyTrap = Class.extend({
            init: function (element) {
                this.element = $(element);
                this.element.autoApplyNS(tabKeyTrapNS);
            },
            trap: function () {
                this.element.on('keydown', proxy(this._keepInTrap, this));
            },
            removeTrap: function () {
                this.element.kendoDestroy(tabKeyTrapNS);
            },
            destroy: function () {
                this.element.kendoDestroy(tabKeyTrapNS);
                this.element = undefined;
            },
            shouldTrap: function () {
                return true;
            },
            _keepInTrap: function (e) {
                if (e.which !== 9 || !this.shouldTrap()) {
                    return;
                }
                var target = e.target;
                var elements = this.element.find(focusableNodesSelector).filter(':visible[tabindex!=-1]');
                var focusableItems = elements.sort(function (prevEl, nextEl) {
                    return prevEl.tabIndex - nextEl.tabIndex;
                });
                var focusableItemsCount = focusableItems.length;
                var lastIndex = focusableItemsCount - 1;
                var focusedItemIndex = focusableItems.index(target);
                if (e.shiftKey) {
                    if (focusedItemIndex === 0) {
                        focusableItems.get(lastIndex).focus();
                    } else {
                        focusableItems.get(focusedItemIndex - 1).focus();
                    }
                } else {
                    if (focusedItemIndex === lastIndex) {
                        focusableItems.get(0).focus();
                    } else {
                        focusableItems.get(focusedItemIndex + 1).focus();
                    }
                }
                e.preventDefault();
            }
        });
        ui.Popup.TabKeyTrap = TabKeyTrap;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/surface-tooltip', [
        'kendo.popup',
        'drawing/kendo-drawing'
    ], f);
}(function () {
    (function ($) {
        var NS = '.kendo';
        var kendo = window.kendo;
        var deepExtend = kendo.deepExtend;
        var utils = kendo.drawing.util;
        var defined = utils.defined;
        var limitValue = utils.limitValue;
        var eventCoordinates = utils.eventCoordinates;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var proxy = $.proxy;
        var TOOLTIP_TEMPLATE = '<div class="k-tooltip">' + '<div class="k-tooltip-content"></div>' + '</div>';
        var TOOLTIP_CLOSE_TEMPLATE = '<div class="k-tooltip-button"><a href="\\#" class="k-icon k-i-close">close</a></div>';
        var SurfaceTooltip = kendo.Class.extend({
            init: function (surface, options) {
                this.element = $(TOOLTIP_TEMPLATE);
                this.content = this.element.children('.k-tooltip-content');
                options = options || {};
                this.options = deepExtend({}, this.options, this._tooltipOptions(options));
                this.popupOptions = {
                    appendTo: options.appendTo,
                    animation: options.animation,
                    copyAnchorStyles: false,
                    collision: 'fit fit'
                };
                this._openPopupHandler = $.proxy(this._openPopup, this);
                this.surface = surface;
                this._bindEvents();
            },
            options: {
                position: 'top',
                showOn: 'mouseenter',
                offset: 7,
                autoHide: true,
                hideDelay: 0,
                showAfter: 100
            },
            _bindEvents: function () {
                this._showHandler = proxy(this._showEvent, this);
                this._surfaceLeaveHandler = proxy(this._surfaceLeave, this);
                this._mouseleaveHandler = proxy(this._mouseleave, this);
                this._mousemoveHandler = proxy(this._mousemove, this);
                this.surface.bind('click', this._showHandler);
                this.surface.bind('mouseenter', this._showHandler);
                this.surface.bind('mouseleave', this._mouseleaveHandler);
                this.surface.bind('mousemove', this._mousemoveHandler);
                this.surface.element.on('mouseleave' + NS, this._surfaceLeaveHandler);
                this.element.on('click' + NS, '.k-tooltip-button', proxy(this._hideClick, this));
            },
            getPopup: function () {
                if (!this.popup) {
                    this.popup = new kendo.ui.Popup(this.element, this.popupOptions);
                }
                return this.popup;
            },
            destroy: function () {
                var popup = this.popup;
                this.surface.unbind('click', this._showHandler);
                this.surface.unbind('mouseenter', this._showHandler);
                this.surface.unbind('mouseleave', this._mouseleaveHandler);
                this.surface.unbind('mousemove', this._mousemoveHandler);
                this.surface.element.off('mouseleave' + NS, this._surfaceLeaveHandler);
                this.element.off('click' + NS);
                if (popup) {
                    popup.destroy();
                    delete this.popup;
                }
                delete this.popupOptions;
                clearTimeout(this._timeout);
                delete this.element;
                delete this.content;
                delete this.surface;
            },
            _tooltipOptions: function (options) {
                options = options || {};
                return {
                    position: options.position,
                    showOn: options.showOn,
                    offset: options.offset,
                    autoHide: options.autoHide,
                    width: options.width,
                    height: options.height,
                    content: options.content,
                    shared: options.shared,
                    hideDelay: options.hideDelay,
                    showAfter: options.showAfter
                };
            },
            _tooltipShape: function (shape) {
                while (shape && !shape.options.tooltip) {
                    shape = shape.parent;
                }
                return shape;
            },
            _updateContent: function (target, shape, options) {
                var content = options.content;
                if (kendo.isFunction(content)) {
                    content = content({
                        element: shape,
                        target: target
                    });
                }
                if (content) {
                    this.content.html(content);
                    return true;
                }
            },
            _position: function (shape, options, elementSize, event) {
                var position = options.position;
                var tooltipOffset = options.offset || 0;
                var surface = this.surface;
                var offset = surface._instance._elementOffset();
                var size = surface.getSize();
                var surfaceOffset = surface._instance._offset;
                var bbox = shape.bbox();
                var width = elementSize.width;
                var height = elementSize.height;
                var left = 0, top = 0;
                bbox.origin.translate(offset.left, offset.top);
                if (surfaceOffset) {
                    bbox.origin.translate(-surfaceOffset.x, -surfaceOffset.y);
                }
                if (position == 'cursor' && event) {
                    var coord = eventCoordinates(event);
                    left = coord.x - width / 2;
                    top = coord.y - height - tooltipOffset;
                } else if (position == 'left') {
                    left = bbox.origin.x - width - tooltipOffset;
                    top = bbox.center().y - height / 2;
                } else if (position == 'right') {
                    left = bbox.bottomRight().x + tooltipOffset;
                    top = bbox.center().y - height / 2;
                } else if (position == 'bottom') {
                    left = bbox.center().x - width / 2;
                    top = bbox.bottomRight().y + tooltipOffset;
                } else {
                    left = bbox.center().x - width / 2;
                    top = bbox.origin.y - height - tooltipOffset;
                }
                return {
                    left: limitValue(left, offset.left, offset.left + size.width),
                    top: limitValue(top, offset.top, offset.top + size.height)
                };
            },
            show: function (shape, options) {
                this._show(shape, shape, deepExtend({}, this.options, this._tooltipOptions(shape.options.tooltip), options));
            },
            hide: function () {
                var popup = this.popup;
                var current = this._current;
                delete this._current;
                clearTimeout(this._showTimeout);
                if (popup && popup.visible() && current && !this.surface.trigger('tooltipClose', {
                        element: current.shape,
                        target: current.target,
                        popup: popup
                    })) {
                    popup.close();
                }
            },
            _hideClick: function (e) {
                e.preventDefault();
                this.hide();
            },
            _show: function (target, shape, options, event, delay) {
                var current = this._current;
                clearTimeout(this._timeout);
                if (current && (current.shape === shape && options.shared || current.target === target)) {
                    return;
                }
                clearTimeout(this._showTimeout);
                var popup = this.getPopup();
                if (!this.surface.trigger('tooltipOpen', {
                        element: shape,
                        target: target,
                        popup: popup
                    }) && this._updateContent(target, shape, options)) {
                    this._autoHide(options);
                    var elementSize = this._measure(options);
                    if (popup.visible()) {
                        popup.close(true);
                    }
                    this._current = {
                        options: options,
                        elementSize: elementSize,
                        shape: shape,
                        target: target,
                        position: this._position(options.shared ? shape : target, options, elementSize, event)
                    };
                    if (delay) {
                        this._showTimeout = setTimeout(this._openPopupHandler, options.showAfter || 0);
                    } else {
                        this._openPopup();
                    }
                }
            },
            _openPopup: function () {
                var current = this._current;
                var position = current.position;
                this.getPopup().open(position.left, position.top);
            },
            _autoHide: function (options) {
                if (options.autoHide && this._closeButton) {
                    this.element.removeClass('k-tooltip-closable');
                    this._closeButton.remove();
                    delete this._closeButton;
                }
                if (!options.autoHide && !this._closeButton) {
                    this.element.addClass('k-tooltip-closable');
                    this._closeButton = $(TOOLTIP_CLOSE_TEMPLATE).prependTo(this.element);
                }
            },
            _showEvent: function (e) {
                var shape = this._tooltipShape(e.element);
                if (shape) {
                    var options = deepExtend({}, this.options, this._tooltipOptions(shape.options.tooltip));
                    if (options && options.showOn == e.type) {
                        this._show(e.element, shape, options, e.originalEvent, true);
                    }
                }
            },
            _measure: function (options) {
                var popup = this.getPopup();
                var width, height;
                this.element.css({
                    width: 'auto',
                    height: 'auto'
                });
                var visible = popup.visible();
                if (!visible) {
                    popup.wrapper.show();
                }
                this.element.css({
                    width: defined(options.width) ? options.width : 'auto',
                    height: defined(options.height) ? options.height : 'auto'
                });
                width = outerWidth(this.element);
                height = outerHeight(this.element);
                if (!visible) {
                    popup.wrapper.hide();
                }
                return {
                    width: width,
                    height: height
                };
            },
            _mouseleave: function (e) {
                if (this.popup && !this._popupRelatedTarget(e.originalEvent)) {
                    var tooltip = this;
                    var current = tooltip._current;
                    if (current && current.options.autoHide) {
                        tooltip._timeout = setTimeout(function () {
                            clearTimeout(tooltip._showTimeout);
                            tooltip.hide();
                        }, current.options.hideDelay || 0);
                    }
                }
            },
            _mousemove: function (e) {
                var current = this._current;
                if (current && e.element) {
                    var options = current.options;
                    if (options.position == 'cursor') {
                        var position = this._position(e.element, options, current.elementSize, e.originalEvent);
                        current.position = position;
                        this.getPopup().wrapper.css({
                            left: position.left,
                            top: position.top
                        });
                    }
                }
            },
            _surfaceLeave: function (e) {
                if (this.popup && !this._popupRelatedTarget(e)) {
                    clearTimeout(this._showTimeout);
                    this.hide();
                }
            },
            _popupRelatedTarget: function (e) {
                return e.relatedTarget && $(e.relatedTarget).closest(this.popup.wrapper).length;
            }
        });
        kendo.drawing.SurfaceTooltip = SurfaceTooltip;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/surface', [
        'drawing/kendo-drawing',
        'drawing/surface-tooltip'
    ], f);
}(function () {
    (function ($) {
        var kendo = window.kendo;
        var draw = kendo.drawing;
        var DrawingSurface = draw.Surface;
        var Widget = kendo.ui.Widget;
        var deepExtend = kendo.deepExtend;
        var proxy = $.proxy;
        kendo.support.svg = DrawingSurface.support.svg;
        kendo.support.canvas = DrawingSurface.support.canvas;
        var Surface = Widget.extend({
            init: function (element, options) {
                this.options = deepExtend({}, this.options, options);
                Widget.fn.init.call(this, element, this.options);
                this._instance = DrawingSurface.create(this.element[0], options);
                if (this._instance.translate) {
                    this.translate = translate;
                }
                this._triggerInstanceHandler = proxy(this._triggerInstanceEvent, this);
                this._bindHandler('click');
                this._bindHandler('mouseenter');
                this._bindHandler('mouseleave');
                this._bindHandler('mousemove');
                this._enableTracking();
            },
            options: {
                name: 'Surface',
                tooltip: {}
            },
            events: [
                'click',
                'mouseenter',
                'mouseleave',
                'mousemove',
                'resize',
                'tooltipOpen',
                'tooltipClose'
            ],
            _triggerInstanceEvent: function (e) {
                this.trigger(e.type, e);
            },
            _bindHandler: function (event) {
                this._instance.bind(event, this._triggerInstanceHandler);
            },
            draw: function (element) {
                this._instance.draw(element);
            },
            clear: function () {
                if (this._instance) {
                    this._instance.clear();
                }
                this.hideTooltip();
            },
            destroy: function () {
                if (this._instance) {
                    this._instance.destroy();
                    delete this._instance;
                }
                if (this._tooltip) {
                    this._tooltip.destroy();
                    delete this._tooltip;
                }
                Widget.fn.destroy.call(this);
            },
            exportVisual: function () {
                return this._instance.exportVisual();
            },
            eventTarget: function (e) {
                return this._instance.eventTarget(e);
            },
            showTooltip: function (shape, options) {
                if (this._tooltip) {
                    this._tooltip.show(shape, options);
                }
            },
            hideTooltip: function () {
                if (this._tooltip) {
                    this._tooltip.hide();
                }
            },
            suspendTracking: function () {
                this._instance.suspendTracking();
                this.hideTooltip();
            },
            resumeTracking: function () {
                this._instance.resumeTracking();
            },
            getSize: function () {
                return {
                    width: this.element.width(),
                    height: this.element.height()
                };
            },
            setSize: function (size) {
                this.element.css({
                    width: size.width,
                    height: size.height
                });
                this._size = size;
                this._instance.currentSize(size);
                this._resize();
            },
            _resize: function () {
                this._instance.currentSize(this._size);
                this._instance._resize();
            },
            _enableTracking: function () {
                if (kendo.ui.Popup) {
                    this._tooltip = new draw.SurfaceTooltip(this, this.options.tooltip || {});
                }
            }
        });
        kendo.ui.plugin(Surface);
        Surface.create = function (element, options) {
            return new Surface(element, options);
        };
        kendo.drawing.Surface = Surface;
        function translate(offset) {
            this._instance.translate(offset);
        }
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('drawing/html', ['drawing/kendo-drawing'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo;
        var drawing = kendo.drawing;
        var drawDOM = drawing.drawDOM;
        drawing.drawDOM = function (element, options) {
            return drawDOM($(element)[0], options);
        };
        drawing.drawDOM.drawText = drawDOM.drawText;
        drawing.drawDOM.getFontFaces = drawDOM.getFontFaces;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.drawing', [
        'drawing/util',
        'drawing/kendo-drawing',
        'drawing/surface-tooltip',
        'drawing/surface',
        'drawing/html'
    ], f);
}(function () {
    var __meta__ = {
        id: 'drawing',
        name: 'Drawing API',
        category: 'framework',
        description: 'The Kendo UI low-level drawing API',
        depends: [
            'core',
            'color',
            'popup'
        ]
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.validator', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'validator',
        name: 'Validator',
        category: 'web',
        description: 'The Validator offers an easy way to do a client-side form validation.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, NS = '.kendoValidator', INVALIDMSG = 'k-invalid-msg', invalidMsgRegExp = new RegExp(INVALIDMSG, 'i'), INVALIDINPUT = 'k-invalid', VALIDINPUT = 'k-valid', emailRegExp = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/i, urlRegExp = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i, INPUTSELECTOR = ':input:not(:button,[type=submit],[type=reset],[disabled],[readonly])', CHECKBOXSELECTOR = ':checkbox:not([disabled],[readonly])', NUMBERINPUTSELECTOR = '[type=number],[type=range]', BLUR = 'blur', NAME = 'name', FORM = 'form', NOVALIDATE = 'novalidate', VALIDATE = 'validate', CHANGE = 'change', VALIDATE_INPUT = 'validateInput', proxy = $.proxy, patternMatcher = function (value, pattern) {
                if (typeof pattern === 'string') {
                    pattern = new RegExp('^(?:' + pattern + ')$');
                }
                return pattern.test(value);
            }, matcher = function (input, selector, pattern) {
                var value = input.val();
                if (input.filter(selector).length && value !== '') {
                    return patternMatcher(value, pattern);
                }
                return true;
            }, hasAttribute = function (input, name) {
                if (input.length) {
                    return input[0].attributes[name] != null;
                }
                return false;
            };
        if (!kendo.ui.validator) {
            kendo.ui.validator = {
                rules: {},
                messages: {}
            };
        }
        function resolveRules(element) {
            var resolvers = kendo.ui.validator.ruleResolvers || {}, rules = {}, name;
            for (name in resolvers) {
                $.extend(true, rules, resolvers[name].resolve(element));
            }
            return rules;
        }
        function decode(value) {
            return value.replace(/&amp/g, '&amp;').replace(/&quot;/g, '"').replace(/&#39;/g, '\'').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
        }
        function numberOfDecimalDigits(value) {
            value = (value + '').split('.');
            if (value.length > 1) {
                return value[1].length;
            }
            return 0;
        }
        function parseHtml(text) {
            if ($.parseHTML) {
                return $($.parseHTML(text));
            }
            return $(text);
        }
        function searchForMessageContainer(elements, fieldName) {
            var containers = $(), element, attr;
            for (var idx = 0, length = elements.length; idx < length; idx++) {
                element = elements[idx];
                if (invalidMsgRegExp.test(element.className)) {
                    attr = element.getAttribute(kendo.attr('for'));
                    if (attr === fieldName) {
                        containers = containers.add(element);
                    }
                }
            }
            return containers;
        }
        var Validator = Widget.extend({
            init: function (element, options) {
                var that = this, resolved = resolveRules(element), validateAttributeSelector = '[' + kendo.attr('validate') + '!=false]';
                options = options || {};
                options.rules = $.extend({}, kendo.ui.validator.rules, resolved.rules, options.rules);
                options.messages = $.extend({}, kendo.ui.validator.messages, resolved.messages, options.messages);
                Widget.fn.init.call(that, element, options);
                that._errorTemplate = kendo.template(that.options.errorTemplate);
                if (that.element.is(FORM)) {
                    that.element.attr(NOVALIDATE, NOVALIDATE);
                }
                that._inputSelector = INPUTSELECTOR + validateAttributeSelector;
                that._checkboxSelector = CHECKBOXSELECTOR + validateAttributeSelector;
                that._errors = {};
                that._attachEvents();
                that._isValidated = false;
            },
            events: [
                VALIDATE,
                CHANGE,
                VALIDATE_INPUT
            ],
            options: {
                name: 'Validator',
                errorTemplate: '<div class="k-widget k-tooltip k-tooltip-validation">' + '<span class="k-icon k-i-warning"> </span> #=message#</div>',// 
                messages: {
                    required: '{0} is required',
                    pattern: '{0} is not valid',
                    min: '{0} should be greater than or equal to {1}',
                    max: '{0} should be smaller than or equal to {1}',
                    step: '{0} is not valid',
                    email: '{0} is not valid email',
                    url: '{0} is not valid URL',
                    date: '{0} is not valid date',
                    dateCompare: 'End date should be greater than or equal to the start date'
                },
                rules: {
                    required: function (input) {
                        var checkbox = input.filter('[type=checkbox]').length && !input.is(':checked'), value = input.val();
                        return !(hasAttribute(input, 'required') && (!value || value === '' || value.length === 0 || checkbox));
                    },
                    pattern: function (input) {
                        if (input.filter('[type=text],[type=email],[type=url],[type=tel],[type=search],[type=password]').filter('[pattern]').length && input.val() !== '') {
                            return patternMatcher(input.val(), input.attr('pattern'));
                        }
                        return true;
                    },
                    min: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[min]').length && input.val() !== '') {
                            var min = parseFloat(input.attr('min')) || 0, val = kendo.parseFloat(input.val());
                            return min <= val;
                        }
                        return true;
                    },
                    max: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[max]').length && input.val() !== '') {
                            var max = parseFloat(input.attr('max')) || 0, val = kendo.parseFloat(input.val());
                            return max >= val;
                        }
                        return true;
                    },
                    step: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[step]').length && input.val() !== '') {
                            var min = parseFloat(input.attr('min')) || 0, step = parseFloat(input.attr('step')) || 1, val = parseFloat(input.val()), decimals = numberOfDecimalDigits(step), raise;
                            if (decimals) {
                                raise = Math.pow(10, decimals);
                                return Math.floor((val - min) * raise) % (step * raise) / Math.pow(100, decimals) === 0;
                            }
                            return (val - min) % step === 0;
                        }
                        return true;
                    },
                    email: function (input) {
                        return matcher(input, '[type=email],[' + kendo.attr('type') + '=email]', emailRegExp);
                    },
                    url: function (input) {
                        return matcher(input, '[type=url],[' + kendo.attr('type') + '=url]', urlRegExp);
                    },
                    date: function (input) {
                        if (input.filter('[type^=date],[' + kendo.attr('type') + '=date]').length && input.val() !== '') {
                            return kendo.parseDate(input.val(), input.attr(kendo.attr('format'))) !== null;
                        }
                        return true;
                    }
                },
                validateOnBlur: true
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.off(NS);
            },
            value: function () {
                if (!this._isValidated) {
                    return false;
                }
                return this.errors().length === 0;
            },
            _submit: function (e) {
                if (!this.validate()) {
                    e.stopPropagation();
                    e.stopImmediatePropagation();
                    e.preventDefault();
                    return false;
                }
                return true;
            },
            _checkElement: function (element) {
                var state = this.value();
                this.validateInput(element);
                if (this.value() !== state) {
                    this.trigger(CHANGE);
                }
            },
            _attachEvents: function () {
                var that = this;
                if (that.element.is(FORM)) {
                    that.element.on('submit' + NS, proxy(that._submit, that));
                }
                if (that.options.validateOnBlur) {
                    if (!that.element.is(INPUTSELECTOR)) {
                        that.element.on(BLUR + NS, that._inputSelector, function () {
                            that._checkElement($(this));
                        });
                        that.element.on('click' + NS, that._checkboxSelector, function () {
                            that._checkElement($(this));
                        });
                    } else {
                        that.element.on(BLUR + NS, function () {
                            that._checkElement(that.element);
                        });
                        if (that.element.is(CHECKBOXSELECTOR)) {
                            that.element.on('click' + NS, function () {
                                that._checkElement(that.element);
                            });
                        }
                    }
                }
            },
            validate: function () {
                var inputs;
                var idx;
                var result = false;
                var length;
                var isValid = this.value();
                this._errors = {};
                if (!this.element.is(INPUTSELECTOR)) {
                    var invalid = false;
                    inputs = this.element.find(this._inputSelector);
                    for (idx = 0, length = inputs.length; idx < length; idx++) {
                        if (!this.validateInput(inputs.eq(idx))) {
                            invalid = true;
                        }
                    }
                    result = !invalid;
                } else {
                    result = this.validateInput(this.element);
                }
                this.trigger(VALIDATE, { valid: result });
                if (isValid !== result) {
                    this.trigger(CHANGE);
                }
                return result;
            },
            validateInput: function (input) {
                input = $(input);
                this._isValidated = true;
                var that = this, template = that._errorTemplate, result = that._checkValidity(input), valid = result.valid, className = '.' + INVALIDMSG, fieldName = input.attr(NAME) || '', lbl = that._findMessageContainer(fieldName).add(input.next(className).filter(function () {
                        var element = $(this);
                        if (element.filter('[' + kendo.attr('for') + ']').length) {
                            return element.attr(kendo.attr('for')) === fieldName;
                        }
                        return true;
                    })).hide(), messageText, wasValid = !input.attr('aria-invalid');
                input.removeAttr('aria-invalid');
                if (!valid) {
                    messageText = that._extractMessage(input, result.key);
                    that._errors[fieldName] = messageText;
                    var messageLabel = parseHtml(template({ message: decode(messageText) }));
                    var lblId = lbl.attr('id');
                    that._decorateMessageContainer(messageLabel, fieldName);
                    if (lblId) {
                        messageLabel.attr('id', lblId);
                    }
                    if (!lbl.replaceWith(messageLabel).length) {
                        messageLabel.insertAfter(input);
                    }
                    messageLabel.show();
                    input.attr('aria-invalid', true);
                } else {
                    delete that._errors[fieldName];
                }
                if (wasValid !== valid) {
                    this.trigger(VALIDATE_INPUT, {
                        valid: valid,
                        input: input
                    });
                }
                input.toggleClass(INVALIDINPUT, !valid);
                input.toggleClass(VALIDINPUT, valid);
                return valid;
            },
            hideMessages: function () {
                var that = this, className = '.' + INVALIDMSG, element = that.element;
                if (!element.is(INPUTSELECTOR)) {
                    element.find(className).hide();
                } else {
                    element.next(className).hide();
                }
            },
            _findMessageContainer: function (fieldName) {
                var locators = kendo.ui.validator.messageLocators, name, containers = $();
                for (var idx = 0, length = this.element.length; idx < length; idx++) {
                    containers = containers.add(searchForMessageContainer(this.element[idx].getElementsByTagName('*'), fieldName));
                }
                for (name in locators) {
                    containers = containers.add(locators[name].locate(this.element, fieldName));
                }
                return containers;
            },
            _decorateMessageContainer: function (container, fieldName) {
                var locators = kendo.ui.validator.messageLocators, name;
                container.addClass(INVALIDMSG).attr(kendo.attr('for'), fieldName || '');
                for (name in locators) {
                    locators[name].decorate(container, fieldName);
                }
                container.attr('role', 'alert');
            },
            _extractMessage: function (input, ruleKey) {
                var that = this, customMessage = that.options.messages[ruleKey], fieldName = input.attr(NAME);
                customMessage = kendo.isFunction(customMessage) ? customMessage(input) : customMessage;
                return kendo.format(input.attr(kendo.attr(ruleKey + '-msg')) || input.attr('validationMessage') || input.attr('title') || customMessage || '', fieldName, input.attr(ruleKey) || input.attr(kendo.attr(ruleKey)));
            },
            _checkValidity: function (input) {
                var rules = this.options.rules, rule;
                for (rule in rules) {
                    if (!rules[rule].call(this, input)) {
                        return {
                            valid: false,
                            key: rule
                        };
                    }
                }
                return { valid: true };
            },
            errors: function () {
                var results = [], errors = this._errors, error;
                for (error in errors) {
                    results.push(errors[error]);
                }
                return results;
            }
        });
        kendo.ui.plugin(Validator);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.userevents', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'userevents',
        name: 'User Events',
        category: 'framework',
        depends: ['core'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, Class = kendo.Class, Observable = kendo.Observable, now = $.now, extend = $.extend, OS = support.mobileOS, invalidZeroEvents = OS && OS.android, DEFAULT_MIN_HOLD = 800, DEFAULT_THRESHOLD = support.browser.msie ? 5 : 0, PRESS = 'press', HOLD = 'hold', SELECT = 'select', START = 'start', MOVE = 'move', END = 'end', CANCEL = 'cancel', TAP = 'tap', RELEASE = 'release', GESTURESTART = 'gesturestart', GESTURECHANGE = 'gesturechange', GESTUREEND = 'gestureend', GESTURETAP = 'gesturetap';
        var THRESHOLD = {
            'api': 0,
            'touch': 0,
            'mouse': 9,
            'pointer': 9
        };
        var ENABLE_GLOBAL_SURFACE = !support.touch || support.mouseAndTouchPresent;
        function touchDelta(touch1, touch2) {
            var x1 = touch1.x.location, y1 = touch1.y.location, x2 = touch2.x.location, y2 = touch2.y.location, dx = x1 - x2, dy = y1 - y2;
            return {
                center: {
                    x: (x1 + x2) / 2,
                    y: (y1 + y2) / 2
                },
                distance: Math.sqrt(dx * dx + dy * dy)
            };
        }
        function getTouches(e) {
            var touches = [], originalEvent = e.originalEvent, currentTarget = e.currentTarget, idx = 0, length, changedTouches, touch;
            if (e.api) {
                touches.push({
                    id: 2,
                    event: e,
                    target: e.target,
                    currentTarget: e.target,
                    location: e,
                    type: 'api'
                });
            } else if (e.type.match(/touch/)) {
                changedTouches = originalEvent ? originalEvent.changedTouches : [];
                for (length = changedTouches.length; idx < length; idx++) {
                    touch = changedTouches[idx];
                    touches.push({
                        location: touch,
                        event: e,
                        target: touch.target,
                        currentTarget: currentTarget,
                        id: touch.identifier,
                        type: 'touch'
                    });
                }
            } else if (support.pointers || support.msPointers) {
                touches.push({
                    location: originalEvent,
                    event: e,
                    target: e.target,
                    currentTarget: currentTarget,
                    id: originalEvent.pointerId,
                    type: 'pointer'
                });
            } else {
                touches.push({
                    id: 1,
                    event: e,
                    target: e.target,
                    currentTarget: currentTarget,
                    location: e,
                    type: 'mouse'
                });
            }
            return touches;
        }
        var TouchAxis = Class.extend({
            init: function (axis, location) {
                var that = this;
                that.axis = axis;
                that._updateLocationData(location);
                that.startLocation = that.location;
                that.velocity = that.delta = 0;
                that.timeStamp = now();
            },
            move: function (location) {
                var that = this, offset = location['page' + that.axis], timeStamp = now(), timeDelta = timeStamp - that.timeStamp || 1;
                if (!offset && invalidZeroEvents) {
                    return;
                }
                that.delta = offset - that.location;
                that._updateLocationData(location);
                that.initialDelta = offset - that.startLocation;
                that.velocity = that.delta / timeDelta;
                that.timeStamp = timeStamp;
            },
            _updateLocationData: function (location) {
                var that = this, axis = that.axis;
                that.location = location['page' + axis];
                that.client = location['client' + axis];
                that.screen = location['screen' + axis];
            }
        });
        var Touch = Class.extend({
            init: function (userEvents, target, touchInfo) {
                extend(this, {
                    x: new TouchAxis('X', touchInfo.location),
                    y: new TouchAxis('Y', touchInfo.location),
                    type: touchInfo.type,
                    useClickAsTap: userEvents.useClickAsTap,
                    threshold: userEvents.threshold || THRESHOLD[touchInfo.type],
                    userEvents: userEvents,
                    target: target,
                    currentTarget: touchInfo.currentTarget,
                    initialTouch: touchInfo.target,
                    id: touchInfo.id,
                    pressEvent: touchInfo,
                    _moved: false,
                    _finished: false
                });
            },
            press: function () {
                this._holdTimeout = setTimeout($.proxy(this, '_hold'), this.userEvents.minHold);
                this._trigger(PRESS, this.pressEvent);
            },
            _hold: function () {
                this._trigger(HOLD, this.pressEvent);
            },
            move: function (touchInfo) {
                var that = this;
                if (that._finished) {
                    return;
                }
                that.x.move(touchInfo.location);
                that.y.move(touchInfo.location);
                if (!that._moved) {
                    if (that._withinIgnoreThreshold()) {
                        return;
                    }
                    if (!UserEvents.current || UserEvents.current === that.userEvents) {
                        that._start(touchInfo);
                    } else {
                        return that.dispose();
                    }
                }
                if (!that._finished) {
                    that._trigger(MOVE, touchInfo);
                }
            },
            end: function (touchInfo) {
                this.endTime = now();
                if (this._finished) {
                    return;
                }
                this._finished = true;
                this._trigger(RELEASE, touchInfo);
                if (this._moved) {
                    this._trigger(END, touchInfo);
                } else {
                    if (!this.useClickAsTap) {
                        this._trigger(TAP, touchInfo);
                    }
                }
                clearTimeout(this._holdTimeout);
                this.dispose();
            },
            dispose: function () {
                var userEvents = this.userEvents, activeTouches = userEvents.touches;
                this._finished = true;
                this.pressEvent = null;
                clearTimeout(this._holdTimeout);
                activeTouches.splice($.inArray(this, activeTouches), 1);
            },
            skip: function () {
                this.dispose();
            },
            cancel: function () {
                this.dispose();
            },
            isMoved: function () {
                return this._moved;
            },
            _start: function (touchInfo) {
                clearTimeout(this._holdTimeout);
                this.startTime = now();
                this._moved = true;
                this._trigger(START, touchInfo);
            },
            _trigger: function (name, touchInfo) {
                var that = this, jQueryEvent = touchInfo.event, data = {
                        touch: that,
                        x: that.x,
                        y: that.y,
                        target: that.target,
                        event: jQueryEvent
                    };
                if (that.userEvents.notify(name, data)) {
                    jQueryEvent.preventDefault();
                }
            },
            _withinIgnoreThreshold: function () {
                var xDelta = this.x.initialDelta, yDelta = this.y.initialDelta;
                return Math.sqrt(xDelta * xDelta + yDelta * yDelta) <= this.threshold;
            }
        });
        function withEachUpEvent(callback) {
            var downEvents = kendo.eventMap.up.split(' '), idx = 0, length = downEvents.length;
            for (; idx < length; idx++) {
                callback(downEvents[idx]);
            }
        }
        var UserEvents = Observable.extend({
            init: function (element, options) {
                var that = this, filter, ns = kendo.guid();
                options = options || {};
                filter = that.filter = options.filter;
                that.threshold = options.threshold || DEFAULT_THRESHOLD;
                that.minHold = options.minHold || DEFAULT_MIN_HOLD;
                that.touches = [];
                that._maxTouches = options.multiTouch ? 2 : 1;
                that.allowSelection = options.allowSelection;
                that.captureUpIfMoved = options.captureUpIfMoved;
                that.useClickAsTap = !options.fastTap && !support.delayedClick();
                that.eventNS = ns;
                element = $(element).handler(that);
                Observable.fn.init.call(that);
                extend(that, {
                    element: element,
                    surface: options.global && ENABLE_GLOBAL_SURFACE ? $(element[0].ownerDocument.documentElement) : $(options.surface || element),
                    stopPropagation: options.stopPropagation,
                    pressed: false
                });
                that.surface.handler(that).on(kendo.applyEventMap('move', ns), '_move').on(kendo.applyEventMap('up cancel', ns), '_end');
                element.on(kendo.applyEventMap('down', ns), filter, '_start');
                if (that.useClickAsTap) {
                    element.on(kendo.applyEventMap('click', ns), filter, '_click');
                }
                if (support.pointers || support.msPointers) {
                    if (support.browser.version < 11) {
                        element.css('-ms-touch-action', 'pinch-zoom double-tap-zoom');
                    } else {
                        element.css('touch-action', options.touchAction || 'none');
                    }
                }
                if (options.preventDragEvent) {
                    element.on(kendo.applyEventMap('dragstart', ns), kendo.preventDefault);
                }
                element.on(kendo.applyEventMap('mousedown', ns), filter, { root: element }, '_select');
                if (that.captureUpIfMoved && support.eventCapture) {
                    var surfaceElement = that.surface[0], preventIfMovingProxy = $.proxy(that.preventIfMoving, that);
                    withEachUpEvent(function (eventName) {
                        surfaceElement.addEventListener(eventName, preventIfMovingProxy, true);
                    });
                }
                that.bind([
                    PRESS,
                    HOLD,
                    TAP,
                    START,
                    MOVE,
                    END,
                    RELEASE,
                    CANCEL,
                    GESTURESTART,
                    GESTURECHANGE,
                    GESTUREEND,
                    GESTURETAP,
                    SELECT
                ], options);
            },
            preventIfMoving: function (e) {
                if (this._isMoved()) {
                    e.preventDefault();
                }
            },
            destroy: function () {
                var that = this;
                if (that._destroyed) {
                    return;
                }
                that._destroyed = true;
                if (that.captureUpIfMoved && support.eventCapture) {
                    var surfaceElement = that.surface[0];
                    withEachUpEvent(function (eventName) {
                        surfaceElement.removeEventListener(eventName, that.preventIfMoving);
                    });
                }
                that.element.kendoDestroy(that.eventNS);
                that.surface.kendoDestroy(that.eventNS);
                that.element.removeData('handler');
                that.surface.removeData('handler');
                that._disposeAll();
                that.unbind();
                delete that.surface;
                delete that.element;
                delete that.currentTarget;
            },
            capture: function () {
                UserEvents.current = this;
            },
            cancel: function () {
                this._disposeAll();
                this.trigger(CANCEL);
            },
            notify: function (eventName, data) {
                var that = this, touches = that.touches;
                if (this._isMultiTouch()) {
                    switch (eventName) {
                    case MOVE:
                        eventName = GESTURECHANGE;
                        break;
                    case END:
                        eventName = GESTUREEND;
                        break;
                    case TAP:
                        eventName = GESTURETAP;
                        break;
                    }
                    extend(data, { touches: touches }, touchDelta(touches[0], touches[1]));
                }
                return this.trigger(eventName, extend(data, { type: eventName }));
            },
            press: function (x, y, target) {
                this._apiCall('_start', x, y, target);
            },
            move: function (x, y) {
                this._apiCall('_move', x, y);
            },
            end: function (x, y) {
                this._apiCall('_end', x, y);
            },
            _isMultiTouch: function () {
                return this.touches.length > 1;
            },
            _maxTouchesReached: function () {
                return this.touches.length >= this._maxTouches;
            },
            _disposeAll: function () {
                var touches = this.touches;
                while (touches.length > 0) {
                    touches.pop().dispose();
                }
            },
            _isMoved: function () {
                return $.grep(this.touches, function (touch) {
                    return touch.isMoved();
                }).length;
            },
            _select: function (e) {
                if (!this.allowSelection || this.trigger(SELECT, { event: e })) {
                    e.preventDefault();
                }
            },
            _start: function (e) {
                var that = this, idx = 0, filter = that.filter, target, touches = getTouches(e), length = touches.length, touch, which = e.which;
                if (which && which > 1 || that._maxTouchesReached()) {
                    return;
                }
                UserEvents.current = null;
                that.currentTarget = e.currentTarget;
                if (that.stopPropagation) {
                    e.stopPropagation();
                }
                for (; idx < length; idx++) {
                    if (that._maxTouchesReached()) {
                        break;
                    }
                    touch = touches[idx];
                    if (filter) {
                        target = $(touch.currentTarget);
                    } else {
                        target = that.element;
                    }
                    if (!target.length) {
                        continue;
                    }
                    touch = new Touch(that, target, touch);
                    that.touches.push(touch);
                    touch.press();
                    if (that._isMultiTouch()) {
                        that.notify('gesturestart', {});
                    }
                }
            },
            _move: function (e) {
                this._eachTouch('move', e);
            },
            _end: function (e) {
                this._eachTouch('end', e);
            },
            _click: function (e) {
                var data = {
                    touch: {
                        initialTouch: e.target,
                        target: $(e.currentTarget),
                        endTime: now(),
                        x: {
                            location: e.pageX,
                            client: e.clientX
                        },
                        y: {
                            location: e.pageY,
                            client: e.clientY
                        }
                    },
                    x: e.pageX,
                    y: e.pageY,
                    target: $(e.currentTarget),
                    event: e,
                    type: 'tap'
                };
                if (this.trigger('tap', data)) {
                    e.preventDefault();
                }
            },
            _eachTouch: function (methodName, e) {
                var that = this, dict = {}, touches = getTouches(e), activeTouches = that.touches, idx, touch, touchInfo, matchingTouch;
                for (idx = 0; idx < activeTouches.length; idx++) {
                    touch = activeTouches[idx];
                    dict[touch.id] = touch;
                }
                for (idx = 0; idx < touches.length; idx++) {
                    touchInfo = touches[idx];
                    matchingTouch = dict[touchInfo.id];
                    if (matchingTouch) {
                        matchingTouch[methodName](touchInfo);
                    }
                }
            },
            _apiCall: function (type, x, y, target) {
                this[type]({
                    api: true,
                    pageX: x,
                    pageY: y,
                    clientX: x,
                    clientY: y,
                    target: $(target || this.element)[0],
                    stopPropagation: $.noop,
                    preventDefault: $.noop
                });
            }
        });
        UserEvents.defaultThreshold = function (value) {
            DEFAULT_THRESHOLD = value;
        };
        UserEvents.minHold = function (value) {
            DEFAULT_MIN_HOLD = value;
        };
        kendo.getTouches = getTouches;
        kendo.touchDelta = touchDelta;
        kendo.UserEvents = UserEvents;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.draganddrop', [
        'kendo.core',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'draganddrop',
        name: 'Drag & drop',
        category: 'framework',
        description: 'Drag & drop functionality for any DOM element.',
        depends: [
            'core',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, document = window.document, $window = $(window), Class = kendo.Class, Widget = kendo.ui.Widget, Observable = kendo.Observable, UserEvents = kendo.UserEvents, proxy = $.proxy, extend = $.extend, getOffset = kendo.getOffset, draggables = {}, dropTargets = {}, dropAreas = {}, lastDropTarget, elementUnderCursor = kendo.elementUnderCursor, KEYUP = 'keyup', CHANGE = 'change', DRAGSTART = 'dragstart', HOLD = 'hold', DRAG = 'drag', DRAGEND = 'dragend', DRAGCANCEL = 'dragcancel', HINTDESTROYED = 'hintDestroyed', DRAGENTER = 'dragenter', DRAGLEAVE = 'dragleave', DROP = 'drop';
        function contains(parent, child) {
            try {
                return $.contains(parent, child) || parent == child;
            } catch (e) {
                return false;
            }
        }
        function numericCssPropery(element, property) {
            return parseInt(element.css(property), 10) || 0;
        }
        function within(value, range) {
            return Math.min(Math.max(value, range.min), range.max);
        }
        function containerBoundaries(container, element) {
            var offset = getOffset(container), outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, minX = offset.left + numericCssPropery(container, 'borderLeftWidth') + numericCssPropery(container, 'paddingLeft'), minY = offset.top + numericCssPropery(container, 'borderTopWidth') + numericCssPropery(container, 'paddingTop'), maxX = minX + container.width() - outerWidth(element, true), maxY = minY + container.height() - outerHeight(element, true);
            return {
                x: {
                    min: minX,
                    max: maxX
                },
                y: {
                    min: minY,
                    max: maxY
                }
            };
        }
        function checkTarget(target, targets, areas) {
            var theTarget, theFilter, i = 0, targetLen = targets && targets.length, areaLen = areas && areas.length;
            while (target && target.parentNode) {
                for (i = 0; i < targetLen; i++) {
                    theTarget = targets[i];
                    if (theTarget.element[0] === target) {
                        return {
                            target: theTarget,
                            targetElement: target
                        };
                    }
                }
                for (i = 0; i < areaLen; i++) {
                    theFilter = areas[i];
                    if ($.contains(theFilter.element[0], target) && support.matchesSelector.call(target, theFilter.options.filter)) {
                        return {
                            target: theFilter,
                            targetElement: target
                        };
                    }
                }
                target = target.parentNode;
            }
            return undefined;
        }
        var TapCapture = Observable.extend({
            init: function (element, options) {
                var that = this, domElement = element[0];
                that.capture = false;
                if (domElement.addEventListener) {
                    $.each(kendo.eventMap.down.split(' '), function () {
                        domElement.addEventListener(this, proxy(that._press, that), true);
                    });
                    $.each(kendo.eventMap.up.split(' '), function () {
                        domElement.addEventListener(this, proxy(that._release, that), true);
                    });
                } else {
                    $.each(kendo.eventMap.down.split(' '), function () {
                        domElement.attachEvent(this, proxy(that._press, that));
                    });
                    $.each(kendo.eventMap.up.split(' '), function () {
                        domElement.attachEvent(this, proxy(that._release, that));
                    });
                }
                Observable.fn.init.call(that);
                that.bind([
                    'press',
                    'release'
                ], options || {});
            },
            captureNext: function () {
                this.capture = true;
            },
            cancelCapture: function () {
                this.capture = false;
            },
            _press: function (e) {
                var that = this;
                that.trigger('press');
                if (that.capture) {
                    e.preventDefault();
                }
            },
            _release: function (e) {
                var that = this;
                that.trigger('release');
                if (that.capture) {
                    e.preventDefault();
                    that.cancelCapture();
                }
            }
        });
        var PaneDimension = Observable.extend({
            init: function (options) {
                var that = this;
                Observable.fn.init.call(that);
                that.forcedEnabled = false;
                $.extend(that, options);
                that.scale = 1;
                if (that.horizontal) {
                    that.measure = 'offsetWidth';
                    that.scrollSize = 'scrollWidth';
                    that.axis = 'x';
                } else {
                    that.measure = 'offsetHeight';
                    that.scrollSize = 'scrollHeight';
                    that.axis = 'y';
                }
            },
            makeVirtual: function () {
                $.extend(this, {
                    virtual: true,
                    forcedEnabled: true,
                    _virtualMin: 0,
                    _virtualMax: 0
                });
            },
            virtualSize: function (min, max) {
                if (this._virtualMin !== min || this._virtualMax !== max) {
                    this._virtualMin = min;
                    this._virtualMax = max;
                    this.update();
                }
            },
            outOfBounds: function (offset) {
                return offset > this.max || offset < this.min;
            },
            forceEnabled: function () {
                this.forcedEnabled = true;
            },
            getSize: function () {
                return this.container[0][this.measure];
            },
            getTotal: function () {
                return this.element[0][this.scrollSize];
            },
            rescale: function (scale) {
                this.scale = scale;
            },
            update: function (silent) {
                var that = this, total = that.virtual ? that._virtualMax : that.getTotal(), scaledTotal = total * that.scale, size = that.getSize();
                if (total === 0 && !that.forcedEnabled) {
                    return;
                }
                that.max = that.virtual ? -that._virtualMin : 0;
                that.size = size;
                that.total = scaledTotal;
                that.min = Math.min(that.max, size - scaledTotal);
                that.minScale = size / total;
                that.centerOffset = (scaledTotal - size) / 2;
                that.enabled = that.forcedEnabled || scaledTotal > size;
                if (!silent) {
                    that.trigger(CHANGE, that);
                }
            }
        });
        var PaneDimensions = Observable.extend({
            init: function (options) {
                var that = this;
                Observable.fn.init.call(that);
                that.x = new PaneDimension(extend({ horizontal: true }, options));
                that.y = new PaneDimension(extend({ horizontal: false }, options));
                that.container = options.container;
                that.forcedMinScale = options.minScale;
                that.maxScale = options.maxScale || 100;
                that.bind(CHANGE, options);
            },
            rescale: function (newScale) {
                this.x.rescale(newScale);
                this.y.rescale(newScale);
                this.refresh();
            },
            centerCoordinates: function () {
                return {
                    x: Math.min(0, -this.x.centerOffset),
                    y: Math.min(0, -this.y.centerOffset)
                };
            },
            refresh: function () {
                var that = this;
                that.x.update();
                that.y.update();
                that.enabled = that.x.enabled || that.y.enabled;
                that.minScale = that.forcedMinScale || Math.min(that.x.minScale, that.y.minScale);
                that.fitScale = Math.max(that.x.minScale, that.y.minScale);
                that.trigger(CHANGE);
            }
        });
        var PaneAxis = Observable.extend({
            init: function (options) {
                var that = this;
                extend(that, options);
                Observable.fn.init.call(that);
            },
            outOfBounds: function () {
                return this.dimension.outOfBounds(this.movable[this.axis]);
            },
            dragMove: function (delta) {
                var that = this, dimension = that.dimension, axis = that.axis, movable = that.movable, position = movable[axis] + delta;
                if (!dimension.enabled) {
                    return;
                }
                if (position < dimension.min && delta < 0 || position > dimension.max && delta > 0) {
                    delta *= that.resistance;
                }
                movable.translateAxis(axis, delta);
                that.trigger(CHANGE, that);
            }
        });
        var Pane = Class.extend({
            init: function (options) {
                var that = this, x, y, resistance, movable;
                extend(that, { elastic: true }, options);
                resistance = that.elastic ? 0.5 : 0;
                movable = that.movable;
                that.x = x = new PaneAxis({
                    axis: 'x',
                    dimension: that.dimensions.x,
                    resistance: resistance,
                    movable: movable
                });
                that.y = y = new PaneAxis({
                    axis: 'y',
                    dimension: that.dimensions.y,
                    resistance: resistance,
                    movable: movable
                });
                that.userEvents.bind([
                    'press',
                    'move',
                    'end',
                    'gesturestart',
                    'gesturechange'
                ], {
                    gesturestart: function (e) {
                        that.gesture = e;
                        that.offset = that.dimensions.container.offset();
                    },
                    press: function (e) {
                        if ($(e.event.target).closest('a').is('[data-navigate-on-press=true]')) {
                            e.sender.cancel();
                        }
                    },
                    gesturechange: function (e) {
                        var previousGesture = that.gesture, previousCenter = previousGesture.center, center = e.center, scaleDelta = e.distance / previousGesture.distance, minScale = that.dimensions.minScale, maxScale = that.dimensions.maxScale, coordinates;
                        if (movable.scale <= minScale && scaleDelta < 1) {
                            scaleDelta += (1 - scaleDelta) * 0.8;
                        }
                        if (movable.scale * scaleDelta >= maxScale) {
                            scaleDelta = maxScale / movable.scale;
                        }
                        var offsetX = movable.x + that.offset.left, offsetY = movable.y + that.offset.top;
                        coordinates = {
                            x: (offsetX - previousCenter.x) * scaleDelta + center.x - offsetX,
                            y: (offsetY - previousCenter.y) * scaleDelta + center.y - offsetY
                        };
                        movable.scaleWith(scaleDelta);
                        x.dragMove(coordinates.x);
                        y.dragMove(coordinates.y);
                        that.dimensions.rescale(movable.scale);
                        that.gesture = e;
                        e.preventDefault();
                    },
                    move: function (e) {
                        if (e.event.target.tagName.match(/textarea|input/i)) {
                            return;
                        }
                        if (x.dimension.enabled || y.dimension.enabled) {
                            x.dragMove(e.x.delta);
                            y.dragMove(e.y.delta);
                            e.preventDefault();
                        } else {
                            e.touch.skip();
                        }
                    },
                    end: function (e) {
                        e.preventDefault();
                    }
                });
            }
        });
        var TRANSFORM_STYLE = support.transitions.prefix + 'Transform', translate;
        if (support.hasHW3D) {
            translate = function (x, y, scale) {
                return 'translate3d(' + x + 'px,' + y + 'px,0) scale(' + scale + ')';
            };
        } else {
            translate = function (x, y, scale) {
                return 'translate(' + x + 'px,' + y + 'px) scale(' + scale + ')';
            };
        }
        var Movable = Observable.extend({
            init: function (element) {
                var that = this;
                Observable.fn.init.call(that);
                that.element = $(element);
                that.element[0].style.webkitTransformOrigin = 'left top';
                that.x = 0;
                that.y = 0;
                that.scale = 1;
                that._saveCoordinates(translate(that.x, that.y, that.scale));
            },
            translateAxis: function (axis, by) {
                this[axis] += by;
                this.refresh();
            },
            scaleTo: function (scale) {
                this.scale = scale;
                this.refresh();
            },
            scaleWith: function (scaleDelta) {
                this.scale *= scaleDelta;
                this.refresh();
            },
            translate: function (coordinates) {
                this.x += coordinates.x;
                this.y += coordinates.y;
                this.refresh();
            },
            moveAxis: function (axis, value) {
                this[axis] = value;
                this.refresh();
            },
            moveTo: function (coordinates) {
                extend(this, coordinates);
                this.refresh();
            },
            refresh: function () {
                var that = this, x = that.x, y = that.y, newCoordinates;
                if (that.round) {
                    x = Math.round(x);
                    y = Math.round(y);
                }
                newCoordinates = translate(x, y, that.scale);
                if (newCoordinates != that.coordinates) {
                    if (kendo.support.browser.msie && kendo.support.browser.version < 10) {
                        that.element[0].style.position = 'absolute';
                        that.element[0].style.left = that.x + 'px';
                        that.element[0].style.top = that.y + 'px';
                    } else {
                        that.element[0].style[TRANSFORM_STYLE] = newCoordinates;
                    }
                    that._saveCoordinates(newCoordinates);
                    that.trigger(CHANGE);
                }
            },
            _saveCoordinates: function (coordinates) {
                this.coordinates = coordinates;
            }
        });
        function destroyDroppable(collection, widget) {
            var groupName = widget.options.group, droppables = collection[groupName], i;
            Widget.fn.destroy.call(widget);
            if (droppables.length > 1) {
                for (i = 0; i < droppables.length; i++) {
                    if (droppables[i] == widget) {
                        droppables.splice(i, 1);
                        break;
                    }
                }
            } else {
                droppables.length = 0;
                delete collection[groupName];
            }
        }
        var DropTarget = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                var group = that.options.group;
                if (!(group in dropTargets)) {
                    dropTargets[group] = [that];
                } else {
                    dropTargets[group].push(that);
                }
            },
            events: [
                DRAGENTER,
                DRAGLEAVE,
                DROP
            ],
            options: {
                name: 'DropTarget',
                group: 'default'
            },
            destroy: function () {
                destroyDroppable(dropTargets, this);
            },
            _trigger: function (eventName, e) {
                var that = this, draggable = draggables[that.options.group];
                if (draggable) {
                    return that.trigger(eventName, extend({}, e.event, {
                        draggable: draggable,
                        dropTarget: e.dropTarget
                    }));
                }
            },
            _over: function (e) {
                this._trigger(DRAGENTER, e);
            },
            _out: function (e) {
                this._trigger(DRAGLEAVE, e);
            },
            _drop: function (e) {
                var that = this, draggable = draggables[that.options.group];
                if (draggable) {
                    draggable.dropped = !that._trigger(DROP, e);
                }
            }
        });
        DropTarget.destroyGroup = function (groupName) {
            var group = dropTargets[groupName] || dropAreas[groupName], i;
            if (group) {
                for (i = 0; i < group.length; i++) {
                    Widget.fn.destroy.call(group[i]);
                }
                group.length = 0;
                delete dropTargets[groupName];
                delete dropAreas[groupName];
            }
        };
        DropTarget._cache = dropTargets;
        var DropTargetArea = DropTarget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                var group = that.options.group;
                if (!(group in dropAreas)) {
                    dropAreas[group] = [that];
                } else {
                    dropAreas[group].push(that);
                }
            },
            destroy: function () {
                destroyDroppable(dropAreas, this);
            },
            options: {
                name: 'DropTargetArea',
                group: 'default',
                filter: null
            }
        });
        var Draggable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._activated = false;
                that.userEvents = new UserEvents(that.element, {
                    global: true,
                    allowSelection: true,
                    filter: that.options.filter,
                    threshold: that.options.distance,
                    start: proxy(that._start, that),
                    hold: proxy(that._hold, that),
                    move: proxy(that._drag, that),
                    end: proxy(that._end, that),
                    cancel: proxy(that._cancel, that),
                    select: proxy(that._select, that)
                });
                that._afterEndHandler = proxy(that._afterEnd, that);
                that._captureEscape = proxy(that._captureEscape, that);
            },
            events: [
                HOLD,
                DRAGSTART,
                DRAG,
                DRAGEND,
                DRAGCANCEL,
                HINTDESTROYED
            ],
            options: {
                name: 'Draggable',
                distance: kendo.support.touch ? 0 : 5,
                group: 'default',
                cursorOffset: null,
                axis: null,
                container: null,
                filter: null,
                ignore: null,
                holdToDrag: false,
                autoScroll: false,
                dropped: false
            },
            cancelHold: function () {
                this._activated = false;
            },
            _captureEscape: function (e) {
                var that = this;
                if (e.keyCode === kendo.keys.ESC) {
                    that._trigger(DRAGCANCEL, { event: e });
                    that.userEvents.cancel();
                }
            },
            _updateHint: function (e) {
                var that = this, coordinates, options = that.options, boundaries = that.boundaries, axis = options.axis, cursorOffset = that.options.cursorOffset;
                if (cursorOffset) {
                    coordinates = {
                        left: e.x.location + cursorOffset.left,
                        top: e.y.location + cursorOffset.top
                    };
                } else {
                    that.hintOffset.left += e.x.delta;
                    that.hintOffset.top += e.y.delta;
                    coordinates = $.extend({}, that.hintOffset);
                }
                if (boundaries) {
                    coordinates.top = within(coordinates.top, boundaries.y);
                    coordinates.left = within(coordinates.left, boundaries.x);
                }
                if (axis === 'x') {
                    delete coordinates.top;
                } else if (axis === 'y') {
                    delete coordinates.left;
                }
                that.hint.css(coordinates);
            },
            _shouldIgnoreTarget: function (target) {
                var ignoreSelector = this.options.ignore;
                return ignoreSelector && $(target).is(ignoreSelector);
            },
            _select: function (e) {
                if (!this._shouldIgnoreTarget(e.event.target)) {
                    e.preventDefault();
                }
            },
            _start: function (e) {
                var that = this, options = that.options, container = options.container, hint = options.hint;
                if (this._shouldIgnoreTarget(e.touch.initialTouch) || options.holdToDrag && !that._activated) {
                    that.userEvents.cancel();
                    return;
                }
                that.currentTarget = e.target;
                that.currentTargetOffset = getOffset(that.currentTarget);
                if (hint) {
                    if (that.hint) {
                        that.hint.stop(true, true).remove();
                    }
                    that.hint = kendo.isFunction(hint) ? $(hint.call(that, that.currentTarget)) : hint;
                    var offset = getOffset(that.currentTarget);
                    that.hintOffset = offset;
                    that.hint.css({
                        position: 'absolute',
                        zIndex: 20000,
                        left: offset.left,
                        top: offset.top
                    }).appendTo(document.body);
                    that.angular('compile', function () {
                        that.hint.removeAttr('ng-repeat');
                        var scopeTarget = $(e.target);
                        while (!scopeTarget.data('$$kendoScope') && scopeTarget.length) {
                            scopeTarget = scopeTarget.parent();
                        }
                        return {
                            elements: that.hint.get(),
                            scopeFrom: scopeTarget.data('$$kendoScope')
                        };
                    });
                }
                draggables[options.group] = that;
                that.dropped = false;
                if (container) {
                    that.boundaries = containerBoundaries(container, that.hint);
                }
                $(document).on(KEYUP, that._captureEscape);
                if (that._trigger(DRAGSTART, e)) {
                    that.userEvents.cancel();
                    that._afterEnd();
                }
                that.userEvents.capture();
            },
            _hold: function (e) {
                this.currentTarget = e.target;
                if (this._trigger(HOLD, e)) {
                    this.userEvents.cancel();
                } else {
                    this._activated = true;
                }
            },
            _drag: function (e) {
                e.preventDefault();
                var cursorElement = this._elementUnderCursor(e);
                if (this.options.autoScroll && this._cursorElement !== cursorElement) {
                    this._scrollableParent = findScrollableParent(cursorElement);
                    this._cursorElement = cursorElement;
                }
                this._lastEvent = e;
                this._processMovement(e, cursorElement);
                if (this.options.autoScroll) {
                    if (this._scrollableParent[0]) {
                        var velocity = autoScrollVelocity(e.x.location, e.y.location, scrollableViewPort(this._scrollableParent));
                        this._scrollCompenstation = $.extend({}, this.hintOffset);
                        this._scrollVelocity = velocity;
                        if (velocity.y === 0 && velocity.x === 0) {
                            clearInterval(this._scrollInterval);
                            this._scrollInterval = null;
                        } else if (!this._scrollInterval) {
                            this._scrollInterval = setInterval($.proxy(this, '_autoScroll'), 50);
                        }
                    }
                }
                if (this.hint) {
                    this._updateHint(e);
                }
            },
            _processMovement: function (e, cursorElement) {
                this._withDropTarget(cursorElement, function (target, targetElement) {
                    if (!target) {
                        if (lastDropTarget) {
                            lastDropTarget._trigger(DRAGLEAVE, extend(e, { dropTarget: $(lastDropTarget.targetElement) }));
                            lastDropTarget = null;
                        }
                        return;
                    }
                    if (lastDropTarget) {
                        if (targetElement === lastDropTarget.targetElement) {
                            return;
                        }
                        lastDropTarget._trigger(DRAGLEAVE, extend(e, { dropTarget: $(lastDropTarget.targetElement) }));
                    }
                    target._trigger(DRAGENTER, extend(e, { dropTarget: $(targetElement) }));
                    lastDropTarget = extend(target, { targetElement: targetElement });
                });
                this._trigger(DRAG, extend(e, {
                    dropTarget: lastDropTarget,
                    elementUnderCursor: cursorElement
                }));
            },
            _autoScroll: function () {
                var parent = this._scrollableParent[0], velocity = this._scrollVelocity, compensation = this._scrollCompenstation;
                if (!parent) {
                    return;
                }
                var cursorElement = this._elementUnderCursor(this._lastEvent);
                this._processMovement(this._lastEvent, cursorElement);
                var yIsScrollable, xIsScrollable;
                var isRootNode = parent === scrollableRoot()[0];
                if (isRootNode) {
                    yIsScrollable = document.body.scrollHeight > $window.height();
                    xIsScrollable = document.body.scrollWidth > $window.width();
                } else {
                    yIsScrollable = parent.offsetHeight <= parent.scrollHeight;
                    xIsScrollable = parent.offsetWidth <= parent.scrollWidth;
                }
                var yDelta = parent.scrollTop + velocity.y;
                var yInBounds = yIsScrollable && yDelta > 0 && yDelta < parent.scrollHeight;
                var xDelta = parent.scrollLeft + velocity.x;
                var xInBounds = xIsScrollable && xDelta > 0 && xDelta < parent.scrollWidth;
                if (yInBounds) {
                    parent.scrollTop += velocity.y;
                }
                if (xInBounds) {
                    parent.scrollLeft += velocity.x;
                }
                if (this.hint && isRootNode && (xInBounds || yInBounds)) {
                    if (yInBounds) {
                        compensation.top += velocity.y;
                    }
                    if (xInBounds) {
                        compensation.left += velocity.x;
                    }
                    this.hint.css(compensation);
                }
            },
            _end: function (e) {
                this._withDropTarget(this._elementUnderCursor(e), function (target, targetElement) {
                    if (target) {
                        target._drop(extend({}, e, { dropTarget: $(targetElement) }));
                        lastDropTarget = null;
                    }
                });
                this._cancel(this._trigger(DRAGEND, e));
            },
            _cancel: function (isDefaultPrevented) {
                var that = this;
                that._scrollableParent = null;
                this._cursorElement = null;
                clearInterval(this._scrollInterval);
                that._activated = false;
                if (that.hint && !that.dropped) {
                    setTimeout(function () {
                        that.hint.stop(true, true);
                        if (isDefaultPrevented) {
                            that._afterEndHandler();
                        } else {
                            that.hint.animate(that.currentTargetOffset, 'fast', that._afterEndHandler);
                        }
                    }, 0);
                } else {
                    that._afterEnd();
                }
            },
            _trigger: function (eventName, e) {
                var that = this;
                return that.trigger(eventName, extend({}, e.event, {
                    x: e.x,
                    y: e.y,
                    currentTarget: that.currentTarget,
                    initialTarget: e.touch ? e.touch.initialTouch : null,
                    dropTarget: e.dropTarget,
                    elementUnderCursor: e.elementUnderCursor
                }));
            },
            _elementUnderCursor: function (e) {
                var target = elementUnderCursor(e), hint = this.hint;
                if (hint && contains(hint[0], target)) {
                    hint.hide();
                    target = elementUnderCursor(e);
                    if (!target) {
                        target = elementUnderCursor(e);
                    }
                    hint.show();
                }
                return target;
            },
            _withDropTarget: function (element, callback) {
                var result, group = this.options.group, targets = dropTargets[group], areas = dropAreas[group];
                if (targets && targets.length || areas && areas.length) {
                    result = checkTarget(element, targets, areas);
                    if (result) {
                        callback(result.target, result.targetElement);
                    } else {
                        callback();
                    }
                }
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that._afterEnd();
                that.userEvents.destroy();
                this._scrollableParent = null;
                this._cursorElement = null;
                clearInterval(this._scrollInterval);
                that.currentTarget = null;
            },
            _afterEnd: function () {
                var that = this;
                if (that.hint) {
                    that.hint.remove();
                }
                delete draggables[that.options.group];
                that.trigger('destroy');
                that.trigger(HINTDESTROYED);
                $(document).off(KEYUP, that._captureEscape);
            }
        });
        kendo.ui.plugin(DropTarget);
        kendo.ui.plugin(DropTargetArea);
        kendo.ui.plugin(Draggable);
        kendo.TapCapture = TapCapture;
        kendo.containerBoundaries = containerBoundaries;
        extend(kendo.ui, {
            Pane: Pane,
            PaneDimensions: PaneDimensions,
            Movable: Movable
        });
        function scrollableViewPort(element) {
            var root = scrollableRoot()[0], offset, top, left;
            if (element[0] === root) {
                top = root.scrollTop;
                left = root.scrollLeft;
                return {
                    top: top,
                    left: left,
                    bottom: top + $window.height(),
                    right: left + $window.width()
                };
            } else {
                offset = element.offset();
                offset.bottom = offset.top + element.height();
                offset.right = offset.left + element.width();
                return offset;
            }
        }
        function scrollableRoot() {
            return $(kendo.support.browser.chrome ? document.body : document.documentElement);
        }
        function findScrollableParent(element) {
            var root = scrollableRoot();
            if (!element || element === document.body || element === document.documentElement) {
                return root;
            }
            var parent = $(element)[0];
            while (parent && !kendo.isScrollable(parent) && parent !== document.body) {
                parent = parent.parentNode;
            }
            if (parent === document.body) {
                return root;
            }
            return $(parent);
        }
        function autoScrollVelocity(mouseX, mouseY, rect) {
            var velocity = {
                x: 0,
                y: 0
            };
            var AUTO_SCROLL_AREA = 50;
            if (mouseX - rect.left < AUTO_SCROLL_AREA) {
                velocity.x = -(AUTO_SCROLL_AREA - (mouseX - rect.left));
            } else if (rect.right - mouseX < AUTO_SCROLL_AREA) {
                velocity.x = AUTO_SCROLL_AREA - (rect.right - mouseX);
            }
            if (mouseY - rect.top < AUTO_SCROLL_AREA) {
                velocity.y = -(AUTO_SCROLL_AREA - (mouseY - rect.top));
            } else if (rect.bottom - mouseY < AUTO_SCROLL_AREA) {
                velocity.y = AUTO_SCROLL_AREA - (rect.bottom - mouseY);
            }
            return velocity;
        }
        kendo.ui.Draggable.utils = {
            autoScrollVelocity: autoScrollVelocity,
            scrollableViewPort: scrollableViewPort,
            findScrollableParent: findScrollableParent
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.scroller', [
        'kendo.fx',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.scroller',
        name: 'Scroller',
        category: 'mobile',
        description: 'The Kendo Mobile Scroller widget enables touch friendly kinetic scrolling for the contents of a given DOM element.',
        depends: [
            'fx',
            'draganddrop'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, fx = kendo.effects, ui = mobile.ui, proxy = $.proxy, extend = $.extend, Widget = ui.Widget, Class = kendo.Class, Movable = kendo.ui.Movable, Pane = kendo.ui.Pane, PaneDimensions = kendo.ui.PaneDimensions, Transition = fx.Transition, Animation = fx.Animation, abs = Math.abs, SNAPBACK_DURATION = 500, SCROLLBAR_OPACITY = 0.7, FRICTION = 0.96, VELOCITY_MULTIPLIER = 10, MAX_VELOCITY = 55, OUT_OF_BOUNDS_FRICTION = 0.5, ANIMATED_SCROLLER_PRECISION = 5, RELEASECLASS = 'km-scroller-release', REFRESHCLASS = 'km-scroller-refresh', PULL = 'pull', CHANGE = 'change', RESIZE = 'resize', SCROLL = 'scroll', MOUSE_WHEEL_ID = 2;
        var ZoomSnapBack = Animation.extend({
            init: function (options) {
                var that = this;
                Animation.fn.init.call(that);
                extend(that, options);
                that.userEvents.bind('gestureend', proxy(that.start, that));
                that.tapCapture.bind('press', proxy(that.cancel, that));
            },
            enabled: function () {
                return this.movable.scale < this.dimensions.minScale;
            },
            done: function () {
                return this.dimensions.minScale - this.movable.scale < 0.01;
            },
            tick: function () {
                var movable = this.movable;
                movable.scaleWith(1.1);
                this.dimensions.rescale(movable.scale);
            },
            onEnd: function () {
                var movable = this.movable;
                movable.scaleTo(this.dimensions.minScale);
                this.dimensions.rescale(movable.scale);
            }
        });
        var DragInertia = Animation.extend({
            init: function (options) {
                var that = this;
                Animation.fn.init.call(that);
                extend(that, options, {
                    transition: new Transition({
                        axis: options.axis,
                        movable: options.movable,
                        onEnd: function () {
                            that._end();
                        }
                    })
                });
                that.tapCapture.bind('press', function () {
                    that.cancel();
                });
                that.userEvents.bind('end', proxy(that.start, that));
                that.userEvents.bind('gestureend', proxy(that.start, that));
                that.userEvents.bind('tap', proxy(that.onEnd, that));
            },
            onCancel: function () {
                this.transition.cancel();
            },
            freeze: function (location) {
                var that = this;
                that.cancel();
                that._moveTo(location);
            },
            onEnd: function () {
                var that = this;
                if (that.paneAxis.outOfBounds()) {
                    that._snapBack();
                } else {
                    that._end();
                }
            },
            done: function () {
                return abs(this.velocity) < 1;
            },
            start: function (e) {
                var that = this, velocity;
                if (!that.dimension.enabled) {
                    return;
                }
                if (that.paneAxis.outOfBounds()) {
                    that._snapBack();
                } else {
                    velocity = e.touch.id === MOUSE_WHEEL_ID ? 0 : e.touch[that.axis].velocity;
                    that.velocity = Math.max(Math.min(velocity * that.velocityMultiplier, MAX_VELOCITY), -MAX_VELOCITY);
                    that.tapCapture.captureNext();
                    Animation.fn.start.call(that);
                }
            },
            tick: function () {
                var that = this, dimension = that.dimension, friction = that.paneAxis.outOfBounds() ? OUT_OF_BOUNDS_FRICTION : that.friction, delta = that.velocity *= friction, location = that.movable[that.axis] + delta;
                if (!that.elastic && dimension.outOfBounds(location)) {
                    location = Math.max(Math.min(location, dimension.max), dimension.min);
                    that.velocity = 0;
                }
                that.movable.moveAxis(that.axis, location);
            },
            _end: function () {
                this.tapCapture.cancelCapture();
                this.end();
            },
            _snapBack: function () {
                var that = this, dimension = that.dimension, snapBack = that.movable[that.axis] > dimension.max ? dimension.max : dimension.min;
                that._moveTo(snapBack);
            },
            _moveTo: function (location) {
                this.transition.moveTo({
                    location: location,
                    duration: SNAPBACK_DURATION,
                    ease: Transition.easeOutExpo
                });
            }
        });
        var AnimatedScroller = Animation.extend({
            init: function (options) {
                var that = this;
                kendo.effects.Animation.fn.init.call(this);
                extend(that, options, {
                    origin: {},
                    destination: {},
                    offset: {}
                });
            },
            tick: function () {
                this._updateCoordinates();
                this.moveTo(this.origin);
            },
            done: function () {
                return abs(this.offset.y) < ANIMATED_SCROLLER_PRECISION && abs(this.offset.x) < ANIMATED_SCROLLER_PRECISION;
            },
            onEnd: function () {
                this.moveTo(this.destination);
                if (this.callback) {
                    this.callback.call();
                }
            },
            setCoordinates: function (from, to) {
                this.offset = {};
                this.origin = from;
                this.destination = to;
            },
            setCallback: function (callback) {
                if (callback && kendo.isFunction(callback)) {
                    this.callback = callback;
                } else {
                    callback = undefined;
                }
            },
            _updateCoordinates: function () {
                this.offset = {
                    x: (this.destination.x - this.origin.x) / 4,
                    y: (this.destination.y - this.origin.y) / 4
                };
                this.origin = {
                    y: this.origin.y + this.offset.y,
                    x: this.origin.x + this.offset.x
                };
            }
        });
        var ScrollBar = Class.extend({
            init: function (options) {
                var that = this, horizontal = options.axis === 'x', element = $('<div class="km-touch-scrollbar km-' + (horizontal ? 'horizontal' : 'vertical') + '-scrollbar" />');
                extend(that, options, {
                    element: element,
                    elementSize: 0,
                    movable: new Movable(element),
                    scrollMovable: options.movable,
                    alwaysVisible: options.alwaysVisible,
                    size: horizontal ? 'width' : 'height'
                });
                that.scrollMovable.bind(CHANGE, proxy(that.refresh, that));
                that.container.append(element);
                if (options.alwaysVisible) {
                    that.show();
                }
            },
            refresh: function () {
                var that = this, axis = that.axis, dimension = that.dimension, paneSize = dimension.size, scrollMovable = that.scrollMovable, sizeRatio = paneSize / dimension.total, position = Math.round(-scrollMovable[axis] * sizeRatio), size = Math.round(paneSize * sizeRatio);
                if (sizeRatio >= 1) {
                    this.element.css('display', 'none');
                } else {
                    this.element.css('display', '');
                }
                if (position + size > paneSize) {
                    size = paneSize - position;
                } else if (position < 0) {
                    size += position;
                    position = 0;
                }
                if (that.elementSize != size) {
                    that.element.css(that.size, size + 'px');
                    that.elementSize = size;
                }
                that.movable.moveAxis(axis, position);
            },
            show: function () {
                this.element.css({
                    opacity: SCROLLBAR_OPACITY,
                    visibility: 'visible'
                });
            },
            hide: function () {
                if (!this.alwaysVisible) {
                    this.element.css({ opacity: 0 });
                }
            }
        });
        var Scroller = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                that._native = that.options.useNative && kendo.support.hasNativeScrolling;
                if (that._native) {
                    element.addClass('km-native-scroller').prepend('<div class="km-scroll-header"/>');
                    extend(that, {
                        scrollElement: element,
                        fixedContainer: element.children().first()
                    });
                    return;
                }
                element.css('overflow', 'hidden').addClass('km-scroll-wrapper').wrapInner('<div class="km-scroll-container"/>').prepend('<div class="km-scroll-header"/>');
                var inner = element.children().eq(1), tapCapture = new kendo.TapCapture(element), movable = new Movable(inner), dimensions = new PaneDimensions({
                        element: inner,
                        container: element,
                        forcedEnabled: that.options.zoom
                    }), avoidScrolling = this.options.avoidScrolling, userEvents = new kendo.UserEvents(element, {
                        touchAction: 'pan-y',
                        fastTap: true,
                        allowSelection: true,
                        preventDragEvent: true,
                        captureUpIfMoved: true,
                        multiTouch: that.options.zoom,
                        start: function (e) {
                            dimensions.refresh();
                            var velocityX = abs(e.x.velocity), velocityY = abs(e.y.velocity), horizontalSwipe = velocityX * 2 >= velocityY, originatedFromFixedContainer = $.contains(that.fixedContainer[0], e.event.target), verticalSwipe = velocityY * 2 >= velocityX;
                            if (!originatedFromFixedContainer && !avoidScrolling(e) && that.enabled && (dimensions.x.enabled && horizontalSwipe || dimensions.y.enabled && verticalSwipe)) {
                                userEvents.capture();
                            } else {
                                userEvents.cancel();
                            }
                        }
                    }), pane = new Pane({
                        movable: movable,
                        dimensions: dimensions,
                        userEvents: userEvents,
                        elastic: that.options.elastic
                    }), zoomSnapBack = new ZoomSnapBack({
                        movable: movable,
                        dimensions: dimensions,
                        userEvents: userEvents,
                        tapCapture: tapCapture
                    }), animatedScroller = new AnimatedScroller({
                        moveTo: function (coordinates) {
                            that.scrollTo(coordinates.x, coordinates.y);
                        }
                    });
                movable.bind(CHANGE, function () {
                    that.scrollTop = -movable.y;
                    that.scrollLeft = -movable.x;
                    that.trigger(SCROLL, {
                        scrollTop: that.scrollTop,
                        scrollLeft: that.scrollLeft
                    });
                });
                if (that.options.mousewheelScrolling) {
                    element.on('DOMMouseScroll mousewheel', proxy(this, '_wheelScroll'));
                }
                extend(that, {
                    movable: movable,
                    dimensions: dimensions,
                    zoomSnapBack: zoomSnapBack,
                    animatedScroller: animatedScroller,
                    userEvents: userEvents,
                    pane: pane,
                    tapCapture: tapCapture,
                    pulled: false,
                    enabled: true,
                    scrollElement: inner,
                    scrollTop: 0,
                    scrollLeft: 0,
                    fixedContainer: element.children().first()
                });
                that._initAxis('x');
                that._initAxis('y');
                that._wheelEnd = function () {
                    that._wheel = false;
                    that.userEvents.end(0, that._wheelY);
                };
                dimensions.refresh();
                if (that.options.pullToRefresh) {
                    that._initPullToRefresh();
                }
            },
            _wheelScroll: function (e) {
                if (!this._wheel) {
                    this._wheel = true;
                    this._wheelY = 0;
                    this.userEvents.press(0, this._wheelY);
                }
                clearTimeout(this._wheelTimeout);
                this._wheelTimeout = setTimeout(this._wheelEnd, 50);
                var delta = kendo.wheelDeltaY(e);
                if (delta) {
                    this._wheelY += delta;
                    this.userEvents.move(0, this._wheelY);
                }
                e.preventDefault();
            },
            makeVirtual: function () {
                this.dimensions.y.makeVirtual();
            },
            virtualSize: function (min, max) {
                this.dimensions.y.virtualSize(min, max);
            },
            height: function () {
                return this.dimensions.y.size;
            },
            scrollHeight: function () {
                return this.scrollElement[0].scrollHeight;
            },
            scrollWidth: function () {
                return this.scrollElement[0].scrollWidth;
            },
            options: {
                name: 'Scroller',
                zoom: false,
                pullOffset: 140,
                visibleScrollHints: false,
                elastic: true,
                useNative: false,
                mousewheelScrolling: true,
                avoidScrolling: function () {
                    return false;
                },
                pullToRefresh: false,
                messages: {
                    pullTemplate: 'Pull to refresh',
                    releaseTemplate: 'Release to refresh',
                    refreshTemplate: 'Refreshing'
                }
            },
            events: [
                PULL,
                SCROLL,
                RESIZE
            ],
            _resize: function () {
                if (!this._native) {
                    this.contentResized();
                }
            },
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                if (options.pullToRefresh) {
                    that._initPullToRefresh();
                }
            },
            reset: function () {
                if (this._native) {
                    this.scrollElement.scrollTop(0);
                } else {
                    this.movable.moveTo({
                        x: 0,
                        y: 0
                    });
                    this._scale(1);
                }
            },
            contentResized: function () {
                this.dimensions.refresh();
                if (this.pane.x.outOfBounds()) {
                    this.movable.moveAxis('x', this.dimensions.x.min);
                }
                if (this.pane.y.outOfBounds()) {
                    this.movable.moveAxis('y', this.dimensions.y.min);
                }
            },
            zoomOut: function () {
                var dimensions = this.dimensions;
                dimensions.refresh();
                this._scale(dimensions.fitScale);
                this.movable.moveTo(dimensions.centerCoordinates());
            },
            enable: function () {
                this.enabled = true;
            },
            disable: function () {
                this.enabled = false;
            },
            scrollTo: function (x, y) {
                if (this._native) {
                    this.scrollElement.scrollLeft(abs(x));
                    this.scrollElement.scrollTop(abs(y));
                } else {
                    this.dimensions.refresh();
                    this.movable.moveTo({
                        x: x,
                        y: y
                    });
                }
            },
            animatedScrollTo: function (x, y, callback) {
                var from, to;
                if (this._native) {
                    this.scrollTo(x, y);
                } else {
                    from = {
                        x: this.movable.x,
                        y: this.movable.y
                    };
                    to = {
                        x: x,
                        y: y
                    };
                    this.animatedScroller.setCoordinates(from, to);
                    this.animatedScroller.setCallback(callback);
                    this.animatedScroller.start();
                }
            },
            pullHandled: function () {
                var that = this;
                that.refreshHint.removeClass(REFRESHCLASS);
                that.hintContainer.html(that.pullTemplate({}));
                that.yinertia.onEnd();
                that.xinertia.onEnd();
                that.userEvents.cancel();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this.userEvents) {
                    this.userEvents.destroy();
                }
            },
            _scale: function (scale) {
                this.dimensions.rescale(scale);
                this.movable.scaleTo(scale);
            },
            _initPullToRefresh: function () {
                var that = this;
                that.dimensions.y.forceEnabled();
                that.pullTemplate = kendo.template(that.options.messages.pullTemplate);
                that.releaseTemplate = kendo.template(that.options.messages.releaseTemplate);
                that.refreshTemplate = kendo.template(that.options.messages.refreshTemplate);
                that.scrollElement.prepend('<span class="km-scroller-pull"><span class="km-icon"></span><span class="km-loading-left"></span><span class="km-loading-right"></span><span class="km-template">' + that.pullTemplate({}) + '</span></span>');
                that.refreshHint = that.scrollElement.children().first();
                that.hintContainer = that.refreshHint.children('.km-template');
                that.pane.y.bind('change', proxy(that._paneChange, that));
                that.userEvents.bind('end', proxy(that._dragEnd, that));
            },
            _dragEnd: function () {
                var that = this;
                if (!that.pulled) {
                    return;
                }
                that.pulled = false;
                that.refreshHint.removeClass(RELEASECLASS).addClass(REFRESHCLASS);
                that.hintContainer.html(that.refreshTemplate({}));
                that.yinertia.freeze(that.options.pullOffset / 2);
                that.trigger('pull');
            },
            _paneChange: function () {
                var that = this;
                if (that.movable.y / OUT_OF_BOUNDS_FRICTION > that.options.pullOffset) {
                    if (!that.pulled) {
                        that.pulled = true;
                        that.refreshHint.removeClass(REFRESHCLASS).addClass(RELEASECLASS);
                        that.hintContainer.html(that.releaseTemplate({}));
                    }
                } else if (that.pulled) {
                    that.pulled = false;
                    that.refreshHint.removeClass(RELEASECLASS);
                    that.hintContainer.html(that.pullTemplate({}));
                }
            },
            _initAxis: function (axis) {
                var that = this, movable = that.movable, dimension = that.dimensions[axis], tapCapture = that.tapCapture, paneAxis = that.pane[axis], scrollBar = new ScrollBar({
                        axis: axis,
                        movable: movable,
                        dimension: dimension,
                        container: that.element,
                        alwaysVisible: that.options.visibleScrollHints
                    });
                dimension.bind(CHANGE, function () {
                    scrollBar.refresh();
                });
                paneAxis.bind(CHANGE, function () {
                    scrollBar.show();
                });
                that[axis + 'inertia'] = new DragInertia({
                    axis: axis,
                    paneAxis: paneAxis,
                    movable: movable,
                    tapCapture: tapCapture,
                    userEvents: that.userEvents,
                    dimension: dimension,
                    elastic: that.options.elastic,
                    friction: that.options.friction || FRICTION,
                    velocityMultiplier: that.options.velocityMultiplier || VELOCITY_MULTIPLIER,
                    end: function () {
                        scrollBar.hide();
                        that.trigger('scrollEnd', {
                            axis: axis,
                            scrollTop: that.scrollTop,
                            scrollLeft: that.scrollLeft
                        });
                    }
                });
            }
        });
        ui.plugin(Scroller);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.groupable', [
        'kendo.core',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'groupable',
        name: 'Groupable',
        category: 'framework',
        depends: [
            'core',
            'draganddrop'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, outerWidth = kendo._outerWidth, proxy = $.proxy, isRtl = false, NS = '.kendoGroupable', CHANGE = 'change', indicatorTmpl = kendo.template('<div class="k-group-indicator" data-#=data.ns#field="${data.field}" data-#=data.ns#title="${data.title || ""}" data-#=data.ns#dir="${data.dir || "asc"}">' + '<a href="\\#" class="k-link">' + '<span class="k-icon k-i-sort-${(data.dir || "asc") == "asc" ? "asc-sm" : "desc-sm"}" title="(sorted ${(data.dir || "asc") == "asc" ? "ascending": "descending"})"></span>' + '${data.title ? data.title: data.field}' + '</a>' + '<a class="k-button k-button-icon k-bare">' + '<span class="k-icon k-i-close"></span>' + '</a>' + '</div>', { useWithBlock: false }), hint = function (target) {
                var title = target.attr(kendo.attr('title'));
                if (title) {
                    title = kendo.htmlEncode(title);
                }
                return $('<div class="k-header k-drag-clue" />').css({
                    width: target.width(),
                    paddingLeft: target.css('paddingLeft'),
                    paddingRight: target.css('paddingRight'),
                    lineHeight: target.height() + 'px',
                    paddingTop: target.css('paddingTop'),
                    paddingBottom: target.css('paddingBottom')
                }).html(title || target.attr(kendo.attr('field'))).prepend('<span class="k-icon k-drag-status k-i-cancel" />');
            }, dropCue = $('<div class="k-grouping-dropclue"/>');
        function dropCueOffsetTop(element) {
            return element.position().top + 3;
        }
        var Groupable = Widget.extend({
            init: function (element, options) {
                var that = this, group = kendo.guid(), intializePositions = proxy(that._intializePositions, that), draggable, horizontalCuePosition, dropCuePositions = that._dropCuePositions = [];
                Widget.fn.init.call(that, element, options);
                isRtl = kendo.support.isRtl(element);
                horizontalCuePosition = isRtl ? 'right' : 'left';
                that.draggable = draggable = that.options.draggable || new kendo.ui.Draggable(that.element, {
                    filter: that.options.draggableElements,
                    hint: hint,
                    group: group
                });
                that.groupContainer = $(that.options.groupContainer, that.element).kendoDropTarget({
                    group: draggable.options.group,
                    dragenter: function (e) {
                        if (that._canDrag(e.draggable.currentTarget)) {
                            e.draggable.hint.find('.k-drag-status').removeClass('k-i-cancel').addClass('k-i-plus');
                            dropCue.css('top', dropCueOffsetTop(that.groupContainer)).css(horizontalCuePosition, 0).appendTo(that.groupContainer);
                        }
                    },
                    dragleave: function (e) {
                        e.draggable.hint.find('.k-drag-status').removeClass('k-i-plus').addClass('k-i-cancel');
                        dropCue.remove();
                    },
                    drop: function (e) {
                        var targetElement = e.draggable.currentTarget, field = targetElement.attr(kendo.attr('field')), title = targetElement.attr(kendo.attr('title')), sourceIndicator = that.indicator(field), dropCuePositions = that._dropCuePositions, lastCuePosition = dropCuePositions[dropCuePositions.length - 1], position;
                        if (!targetElement.hasClass('k-group-indicator') && !that._canDrag(targetElement)) {
                            return;
                        }
                        if (lastCuePosition) {
                            position = that._dropCuePosition(kendo.getOffset(dropCue).left + parseInt(lastCuePosition.element.css('marginLeft'), 10) * (isRtl ? -1 : 1) + parseInt(lastCuePosition.element.css('marginRight'), 10));
                            if (position && that._canDrop($(sourceIndicator), position.element, position.left)) {
                                if (position.before) {
                                    position.element.before(sourceIndicator || that.buildIndicator(field, title));
                                } else {
                                    position.element.after(sourceIndicator || that.buildIndicator(field, title));
                                }
                                that._change();
                            }
                        } else {
                            that.groupContainer.append(that.buildIndicator(field, title));
                            that._change();
                        }
                    }
                }).kendoDraggable({
                    filter: 'div.k-group-indicator',
                    hint: hint,
                    group: draggable.options.group,
                    dragcancel: proxy(that._dragCancel, that),
                    dragstart: function (e) {
                        var element = e.currentTarget, marginLeft = parseInt(element.css('marginLeft'), 10), elementPosition = element.position(), left = isRtl ? elementPosition.left - marginLeft : elementPosition.left + outerWidth(element);
                        intializePositions();
                        dropCue.css({
                            top: dropCueOffsetTop(that.groupContainer),
                            left: left
                        }).appendTo(that.groupContainer);
                        this.hint.find('.k-drag-status').removeClass('k-i-cancel').addClass('k-i-plus');
                    },
                    dragend: function () {
                        that._dragEnd(this);
                    },
                    drag: proxy(that._drag, that)
                }).on('click' + NS, '.k-button', function (e) {
                    e.preventDefault();
                    that._removeIndicator($(this).parent());
                }).on('click' + NS, '.k-link', function (e) {
                    var current = $(this).parent(), newIndicator = that.buildIndicator(current.attr(kendo.attr('field')), current.attr(kendo.attr('title')), current.attr(kendo.attr('dir')) == 'asc' ? 'desc' : 'asc');
                    current.before(newIndicator).remove();
                    that._change();
                    e.preventDefault();
                });
                draggable.bind([
                    'dragend',
                    'dragcancel',
                    'dragstart',
                    'drag'
                ], {
                    dragend: function () {
                        that._dragEnd(this);
                    },
                    dragcancel: proxy(that._dragCancel, that),
                    dragstart: function (e) {
                        var element, marginRight, left;
                        if (!that.options.allowDrag && !that._canDrag(e.currentTarget)) {
                            e.preventDefault();
                            return;
                        }
                        intializePositions();
                        if (dropCuePositions.length) {
                            element = dropCuePositions[dropCuePositions.length - 1].element;
                            marginRight = parseInt(element.css('marginRight'), 10);
                            left = element.position().left + outerWidth(element) + marginRight;
                        } else {
                            left = 0;
                        }
                    },
                    drag: proxy(that._drag, that)
                });
                that.dataSource = that.options.dataSource;
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                }
                if (that.dataSource) {
                    that.dataSource.bind('change', that._refreshHandler);
                    that.refresh();
                }
            },
            refresh: function () {
                var that = this, dataSource = that.dataSource;
                if (that.groupContainer) {
                    that.groupContainer.empty().append($.map(dataSource.group() || [], function (item) {
                        var fieldName = item.field;
                        var attr = kendo.attr('field');
                        var element = that.element.find(that.options.filter).filter(function () {
                            return $(this).attr(attr) === fieldName;
                        });
                        return that.buildIndicator(item.field, element.attr(kendo.attr('title')), item.dir);
                    }).join(''));
                }
                that._invalidateGroupContainer();
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.groupContainer.off(NS);
                if (that.groupContainer.data('kendoDropTarget')) {
                    that.groupContainer.data('kendoDropTarget').destroy();
                }
                if (that.groupContainer.data('kendoDraggable')) {
                    that.groupContainer.data('kendoDraggable').destroy();
                }
                if (!that.options.draggable) {
                    that.draggable.destroy();
                }
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind('change', that._refreshHandler);
                    that._refreshHandler = null;
                }
                that.groupContainer = that.element = that.draggable = null;
            },
            events: ['change'],
            options: {
                name: 'Groupable',
                filter: 'th',
                draggableElements: 'th',
                messages: { empty: 'Drag a column header and drop it here to group by that column' }
            },
            indicator: function (field) {
                var indicators = $('.k-group-indicator', this.groupContainer);
                return $.grep(indicators, function (item) {
                    return $(item).attr(kendo.attr('field')) === field;
                })[0];
            },
            buildIndicator: function (field, title, dir) {
                return indicatorTmpl({
                    field: field.replace(/"/g, '\''),
                    dir: dir,
                    title: title,
                    ns: kendo.ns
                });
            },
            descriptors: function () {
                var that = this, indicators = $('.k-group-indicator', that.groupContainer), aggregates, names, field, idx, length;
                aggregates = that.element.find(that.options.filter).map(function () {
                    var cell = $(this), aggregate = cell.attr(kendo.attr('aggregates')), member = cell.attr(kendo.attr('field'));
                    if (aggregate && aggregate !== '') {
                        names = aggregate.split(',');
                        aggregate = [];
                        for (idx = 0, length = names.length; idx < length; idx++) {
                            aggregate.push({
                                field: member,
                                aggregate: names[idx]
                            });
                        }
                    }
                    return aggregate;
                }).toArray();
                return $.map(indicators, function (item) {
                    item = $(item);
                    field = item.attr(kendo.attr('field'));
                    return {
                        field: field,
                        dir: item.attr(kendo.attr('dir')),
                        aggregates: aggregates || []
                    };
                });
            },
            _removeIndicator: function (indicator) {
                var that = this;
                indicator.remove();
                that._invalidateGroupContainer();
                that._change();
            },
            _change: function () {
                var that = this;
                if (that.dataSource) {
                    var descriptors = that.descriptors();
                    if (that.trigger('change', { groups: descriptors })) {
                        that.refresh();
                        return;
                    }
                    that.dataSource.group(descriptors);
                }
            },
            _dropCuePosition: function (position) {
                var dropCuePositions = this._dropCuePositions;
                if (!dropCue.is(':visible') || dropCuePositions.length === 0) {
                    return;
                }
                position = Math.ceil(position);
                var lastCuePosition = dropCuePositions[dropCuePositions.length - 1], left = lastCuePosition.left, right = lastCuePosition.right, marginLeft = parseInt(lastCuePosition.element.css('marginLeft'), 10), marginRight = parseInt(lastCuePosition.element.css('marginRight'), 10);
                if (position >= right && !isRtl || position < left && isRtl) {
                    position = {
                        left: lastCuePosition.element.position().left + (!isRtl ? outerWidth(lastCuePosition.element) + marginRight : -marginLeft),
                        element: lastCuePosition.element,
                        before: false
                    };
                } else {
                    position = $.grep(dropCuePositions, function (item) {
                        return item.left <= position && position <= item.right || isRtl && position > item.right;
                    })[0];
                    if (position) {
                        position = {
                            left: isRtl ? position.element.position().left + outerWidth(position.element) + marginRight : position.element.position().left - marginLeft,
                            element: position.element,
                            before: true
                        };
                    }
                }
                return position;
            },
            _drag: function (event) {
                var position = this._dropCuePosition(event.x.location);
                if (position) {
                    dropCue.css({
                        left: position.left,
                        right: 'auto'
                    });
                }
            },
            _canDrag: function (element) {
                var field = element.attr(kendo.attr('field'));
                return element.attr(kendo.attr('groupable')) != 'false' && field && (element.hasClass('k-group-indicator') || !this.indicator(field));
            },
            _canDrop: function (source, target, position) {
                var next = source.next(), result = source[0] !== target[0] && (!next[0] || target[0] !== next[0] || (!isRtl && position > next.position().left || isRtl && position < next.position().left));
                return result;
            },
            _dragEnd: function (draggable) {
                var that = this, field = draggable.currentTarget.attr(kendo.attr('field')), sourceIndicator = that.indicator(field);
                if (draggable !== that.options.draggable && !draggable.dropped && sourceIndicator) {
                    that._removeIndicator($(sourceIndicator));
                }
                that._dragCancel();
            },
            _dragCancel: function () {
                dropCue.remove();
                this._dropCuePositions = [];
            },
            _intializePositions: function () {
                var that = this, indicators = $('.k-group-indicator', that.groupContainer), left;
                that._dropCuePositions = $.map(indicators, function (item) {
                    item = $(item);
                    left = kendo.getOffset(item).left;
                    return {
                        left: parseInt(left, 10),
                        right: parseInt(left + outerWidth(item), 10),
                        element: item
                    };
                });
            },
            _invalidateGroupContainer: function () {
                var groupContainer = this.groupContainer;
                if (groupContainer && groupContainer.is(':empty')) {
                    groupContainer.html(this.options.messages.empty);
                }
            }
        });
        kendo.ui.plugin(Groupable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.reorderable', [
        'kendo.core',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'reorderable',
        name: 'Reorderable',
        category: 'framework',
        depends: [
            'core',
            'draganddrop'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, getOffset = kendo.getOffset, Widget = kendo.ui.Widget, CHANGE = 'change', KREORDERABLE = 'k-reorderable';
        function toggleHintClass(hint, denied) {
            hint = $(hint);
            if (denied) {
                hint.find('.k-drag-status').removeClass('k-i-plus').addClass('k-i-cancel');
            } else {
                hint.find('.k-drag-status').removeClass('k-i-cancel').addClass('k-i-plus');
            }
        }
        var Reorderable = Widget.extend({
            init: function (element, options) {
                var that = this, draggable, group = kendo.guid() + '-reorderable';
                Widget.fn.init.call(that, element, options);
                element = that.element.addClass(KREORDERABLE);
                options = that.options;
                that.draggable = draggable = options.draggable || new kendo.ui.Draggable(element, {
                    group: group,
                    autoScroll: true,
                    filter: options.filter,
                    hint: options.hint
                });
                that.reorderDropCue = $('<div class="k-reorder-cue"><div class="k-icon k-i-arrow-60-down"></div><div class="k-icon k-i-arrow-60-up"></div></div>');
                element.find(draggable.options.filter).kendoDropTarget({
                    group: draggable.options.group,
                    dragenter: function (e) {
                        if (!that._draggable) {
                            return;
                        }
                        var dropTarget = this.element, offset;
                        var denied = !that._dropTargetAllowed(dropTarget) || that._isLastDraggable();
                        toggleHintClass(e.draggable.hint, denied);
                        if (!denied) {
                            offset = getOffset(dropTarget);
                            var left = offset.left;
                            if (options.inSameContainer && !options.inSameContainer({
                                    source: dropTarget,
                                    target: that._draggable,
                                    sourceIndex: that._index(dropTarget),
                                    targetIndex: that._index(that._draggable)
                                })) {
                                that._dropTarget = dropTarget;
                            } else {
                                if (that._index(dropTarget) > that._index(that._draggable)) {
                                    left += outerWidth(dropTarget);
                                }
                            }
                            that.reorderDropCue.css({
                                height: outerHeight(dropTarget),
                                top: offset.top,
                                left: left
                            }).appendTo(document.body);
                        }
                    },
                    dragleave: function (e) {
                        toggleHintClass(e.draggable.hint, true);
                        that.reorderDropCue.remove();
                        that._dropTarget = null;
                    },
                    drop: function () {
                        that._dropTarget = null;
                        if (!that._draggable) {
                            return;
                        }
                        var dropTarget = this.element;
                        var draggable = that._draggable;
                        if (that._dropTargetAllowed(dropTarget) && !that._isLastDraggable()) {
                            that.trigger(CHANGE, {
                                element: that._draggable,
                                target: dropTarget,
                                oldIndex: that._index(draggable),
                                newIndex: that._index(dropTarget),
                                position: getOffset(that.reorderDropCue).left > getOffset(dropTarget).left ? 'after' : 'before'
                            });
                        }
                    }
                });
                draggable.bind([
                    'dragcancel',
                    'dragend',
                    'dragstart',
                    'drag'
                ], {
                    dragcancel: function () {
                        that.reorderDropCue.remove();
                        that._draggable = null;
                        that._elements = null;
                    },
                    dragend: function () {
                        that.reorderDropCue.remove();
                        that._draggable = null;
                        that._elements = null;
                    },
                    dragstart: function (e) {
                        that._draggable = e.currentTarget;
                        that._elements = that.element.find(that.draggable.options.filter);
                    },
                    drag: function (e) {
                        if (!that._dropTarget || this.hint.find('.k-drag-status').hasClass('k-i-cancel')) {
                            return;
                        }
                        var dropStartOffset = getOffset(that._dropTarget).left;
                        var width = outerWidth(that._dropTarget);
                        if (e.pageX > dropStartOffset + width / 2) {
                            that.reorderDropCue.css({ left: dropStartOffset + width });
                        } else {
                            that.reorderDropCue.css({ left: dropStartOffset });
                        }
                    }
                });
            },
            options: {
                name: 'Reorderable',
                filter: '*'
            },
            events: [CHANGE],
            _isLastDraggable: function () {
                var inSameContainer = this.options.inSameContainer, draggable = this._draggable[0], elements = this._elements.get(), found = false, item;
                if (!inSameContainer) {
                    return false;
                }
                while (!found && elements.length > 0) {
                    item = elements.pop();
                    found = draggable !== item && inSameContainer({
                        source: draggable,
                        target: item,
                        sourceIndex: this._index(draggable),
                        targetIndex: this._index(item)
                    });
                }
                return !found;
            },
            _dropTargetAllowed: function (dropTarget) {
                var inSameContainer = this.options.inSameContainer, dragOverContainers = this.options.dragOverContainers, draggable = this._draggable;
                if (draggable[0] === dropTarget[0]) {
                    return false;
                }
                if (!inSameContainer || !dragOverContainers) {
                    return true;
                }
                if (inSameContainer({
                        source: draggable,
                        target: dropTarget,
                        sourceIndex: this._index(draggable),
                        targetIndex: this._index(dropTarget)
                    })) {
                    return true;
                }
                return dragOverContainers(this._index(draggable), this._index(dropTarget));
            },
            _index: function (element) {
                return this._elements.index(element);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.element.find(that.draggable.options.filter).each(function () {
                    var item = $(this);
                    if (item.data('kendoDropTarget')) {
                        item.data('kendoDropTarget').destroy();
                    }
                });
                if (that.draggable) {
                    that.draggable.destroy();
                    that.draggable.element = that.draggable = null;
                }
                that.elements = that.reorderDropCue = that._elements = that._draggable = null;
            }
        });
        kendo.ui.plugin(Reorderable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.resizable', [
        'kendo.core',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'resizable',
        name: 'Resizable',
        category: 'framework',
        depends: [
            'core',
            'draganddrop'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, proxy = $.proxy, isFunction = kendo.isFunction, extend = $.extend, HORIZONTAL = 'horizontal', VERTICAL = 'vertical', START = 'start', RESIZE = 'resize', RESIZEEND = 'resizeend';
        var Resizable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.orientation = that.options.orientation.toLowerCase() != VERTICAL ? HORIZONTAL : VERTICAL;
                that._positionMouse = that.orientation == HORIZONTAL ? 'x' : 'y';
                that._position = that.orientation == HORIZONTAL ? 'left' : 'top';
                that._sizingDom = that.orientation == HORIZONTAL ? 'outerWidth' : 'outerHeight';
                that.draggable = new ui.Draggable(options.draggableElement || element, {
                    distance: 1,
                    filter: options.handle,
                    drag: proxy(that._resize, that),
                    dragcancel: proxy(that._cancel, that),
                    dragstart: proxy(that._start, that),
                    dragend: proxy(that._stop, that)
                });
                that.userEvents = that.draggable.userEvents;
            },
            events: [
                RESIZE,
                RESIZEEND,
                START
            ],
            options: {
                name: 'Resizable',
                orientation: HORIZONTAL
            },
            resize: function () {
            },
            _max: function (e) {
                var that = this, hintSize = that.hint ? that.hint[that._sizingDom]() : 0, size = that.options.max;
                return isFunction(size) ? size(e) : size !== undefined ? that._initialElementPosition + size - hintSize : size;
            },
            _min: function (e) {
                var that = this, size = that.options.min;
                return isFunction(size) ? size(e) : size !== undefined ? that._initialElementPosition + size : size;
            },
            _start: function (e) {
                var that = this, hint = that.options.hint, el = $(e.currentTarget);
                that._initialElementPosition = el.position()[that._position];
                that._initialMousePosition = e[that._positionMouse].startLocation;
                if (hint) {
                    that.hint = isFunction(hint) ? $(hint(el)) : hint;
                    that.hint.css({ position: 'absolute' }).css(that._position, that._initialElementPosition).appendTo(that.element);
                }
                that.trigger(START, e);
                that._maxPosition = that._max(e);
                that._minPosition = that._min(e);
                $(document.body).css('cursor', el.css('cursor'));
            },
            _resize: function (e) {
                var that = this, maxPosition = that._maxPosition, minPosition = that._minPosition, currentPosition = that._initialElementPosition + (e[that._positionMouse].location - that._initialMousePosition), position;
                position = minPosition !== undefined ? Math.max(minPosition, currentPosition) : currentPosition;
                that.position = position = maxPosition !== undefined ? Math.min(maxPosition, position) : position;
                if (that.hint) {
                    that.hint.toggleClass(that.options.invalidClass || '', position == maxPosition || position == minPosition).css(that._position, position);
                }
                that.resizing = true;
                that.trigger(RESIZE, extend(e, { position: position }));
            },
            _stop: function (e) {
                var that = this;
                if (that.hint) {
                    that.hint.remove();
                }
                that.resizing = false;
                that.trigger(RESIZEEND, extend(e, { position: that.position }));
                $(document.body).css('cursor', '');
            },
            _cancel: function (e) {
                var that = this;
                if (that.hint) {
                    that.position = undefined;
                    that.hint.css(that._position, that._initialElementPosition);
                    that._stop(e);
                }
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                if (that.draggable) {
                    that.draggable.destroy();
                }
            },
            press: function (target) {
                if (!target) {
                    return;
                }
                var position = target.position(), that = this;
                that.userEvents.press(position.left, position.top, target[0]);
                that.targetPosition = position;
                that.target = target;
            },
            move: function (delta) {
                var that = this, orientation = that._position, position = that.targetPosition, current = that.position;
                if (current === undefined) {
                    current = position[orientation];
                }
                position[orientation] = current + delta;
                that.userEvents.move(position.left, position.top);
            },
            end: function () {
                this.userEvents.end();
                this.target = this.position = undefined;
            }
        });
        kendo.ui.plugin(Resizable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.sortable', ['kendo.draganddrop'], f);
}(function () {
    var __meta__ = {
        id: 'sortable',
        name: 'Sortable',
        category: 'framework',
        depends: ['draganddrop']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, START = 'start', BEFORE_MOVE = 'beforeMove', MOVE = 'move', END = 'end', CHANGE = 'change', CANCEL = 'cancel', ACTION_SORT = 'sort', ACTION_REMOVE = 'remove', ACTION_RECEIVE = 'receive', DEFAULT_FILTER = '>*', MISSING_INDEX = -1;
        function containsOrEqualTo(parent, child) {
            try {
                return $.contains(parent, child) || parent == child;
            } catch (e) {
                return false;
            }
        }
        function defaultHint(element) {
            return element.clone();
        }
        function defaultPlaceholder(element) {
            return element.clone().removeAttr('id').css('visibility', 'hidden');
        }
        var Sortable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                if (!that.options.placeholder) {
                    that.options.placeholder = defaultPlaceholder;
                }
                if (!that.options.hint) {
                    that.options.hint = defaultHint;
                }
                that.draggable = that._createDraggable();
            },
            events: [
                START,
                BEFORE_MOVE,
                MOVE,
                END,
                CHANGE,
                CANCEL
            ],
            options: {
                name: 'Sortable',
                hint: null,
                placeholder: null,
                filter: DEFAULT_FILTER,
                holdToDrag: false,
                disabled: null,
                container: null,
                connectWith: null,
                handler: null,
                cursorOffset: null,
                axis: null,
                ignore: null,
                autoScroll: false,
                cursor: 'auto',
                moveOnDragEnter: false
            },
            destroy: function () {
                this.draggable.destroy();
                Widget.fn.destroy.call(this);
            },
            _createDraggable: function () {
                var that = this, element = that.element, options = that.options;
                return new kendo.ui.Draggable(element, {
                    filter: options.filter,
                    hint: kendo.isFunction(options.hint) ? options.hint : $(options.hint),
                    holdToDrag: options.holdToDrag,
                    container: options.container ? $(options.container) : null,
                    cursorOffset: options.cursorOffset,
                    axis: options.axis,
                    ignore: options.ignore,
                    autoScroll: options.autoScroll,
                    dragstart: $.proxy(that._dragstart, that),
                    dragcancel: $.proxy(that._dragcancel, that),
                    drag: $.proxy(that._drag, that),
                    dragend: $.proxy(that._dragend, that)
                });
            },
            _dragstart: function (e) {
                var draggedElement = this.draggedElement = e.currentTarget, disabled = this.options.disabled, handler = this.options.handler, _placeholder = this.options.placeholder, placeholder = this.placeholder = kendo.isFunction(_placeholder) ? $(_placeholder.call(this, draggedElement)) : $(_placeholder);
                if (disabled && draggedElement.is(disabled)) {
                    e.preventDefault();
                } else if (handler && !$(e.initialTarget).is(handler)) {
                    e.preventDefault();
                } else {
                    if (this.trigger(START, {
                            item: draggedElement,
                            draggableEvent: e
                        })) {
                        e.preventDefault();
                    } else {
                        draggedElement.css('display', 'none');
                        draggedElement.before(placeholder);
                        this._setCursor();
                    }
                }
            },
            _dragcancel: function () {
                this._cancel();
                this.trigger(CANCEL, { item: this.draggedElement });
                this._resetCursor();
            },
            _drag: function (e) {
                var draggedElement = this.draggedElement, target = this._findTarget(e), targetCenter, cursorOffset = {
                        left: e.x.location,
                        top: e.y.location
                    }, offsetDelta, axisDelta = {
                        x: e.x.delta,
                        y: e.y.delta
                    }, direction, sibling, getSibling, axis = this.options.axis, moveOnDragEnter = this.options.moveOnDragEnter, eventData = {
                        item: draggedElement,
                        list: this,
                        draggableEvent: e
                    };
                if (axis === 'x' || axis === 'y') {
                    this._movementByAxis(axis, cursorOffset, axisDelta[axis], eventData);
                    return;
                }
                if (target) {
                    targetCenter = this._getElementCenter(target.element);
                    offsetDelta = {
                        left: Math.round(cursorOffset.left - targetCenter.left),
                        top: Math.round(cursorOffset.top - targetCenter.top)
                    };
                    $.extend(eventData, { target: target.element });
                    if (target.appendToBottom) {
                        this._movePlaceholder(target, null, eventData);
                        return;
                    }
                    if (target.appendAfterHidden) {
                        this._movePlaceholder(target, 'next', eventData);
                    }
                    if (this._isFloating(target.element)) {
                        if (axisDelta.x < 0 && moveOnDragEnter || !moveOnDragEnter && offsetDelta.left < 0) {
                            direction = 'prev';
                        } else if (axisDelta.x > 0 && moveOnDragEnter || !moveOnDragEnter && offsetDelta.left > 0) {
                            direction = 'next';
                        }
                    } else {
                        if (axisDelta.y < 0 && moveOnDragEnter || !moveOnDragEnter && offsetDelta.top < 0) {
                            direction = 'prev';
                        } else if (axisDelta.y > 0 && moveOnDragEnter || !moveOnDragEnter && offsetDelta.top > 0) {
                            direction = 'next';
                        }
                    }
                    if (direction) {
                        getSibling = direction === 'prev' ? jQuery.fn.prev : jQuery.fn.next;
                        sibling = getSibling.call(target.element);
                        while (sibling.length && !sibling.is(':visible')) {
                            sibling = getSibling.call(sibling);
                        }
                        if (sibling[0] != this.placeholder[0]) {
                            this._movePlaceholder(target, direction, eventData);
                        }
                    }
                }
            },
            _dragend: function (e) {
                var placeholder = this.placeholder, draggedElement = this.draggedElement, draggedIndex = this.indexOf(draggedElement), placeholderIndex = this.indexOf(placeholder), connectWith = this.options.connectWith, connectedList, isDefaultPrevented, eventData, connectedListEventData;
                this._resetCursor();
                eventData = {
                    action: ACTION_SORT,
                    item: draggedElement,
                    oldIndex: draggedIndex,
                    newIndex: placeholderIndex,
                    draggableEvent: e
                };
                if (placeholderIndex >= 0) {
                    isDefaultPrevented = this.trigger(END, eventData);
                } else {
                    connectedList = placeholder.parents(connectWith).getKendoSortable();
                    eventData.action = ACTION_REMOVE;
                    connectedListEventData = $.extend({}, eventData, {
                        action: ACTION_RECEIVE,
                        oldIndex: MISSING_INDEX,
                        newIndex: connectedList.indexOf(placeholder)
                    });
                    isDefaultPrevented = !(!this.trigger(END, eventData) && !connectedList.trigger(END, connectedListEventData));
                }
                if (isDefaultPrevented || placeholderIndex === draggedIndex) {
                    this._cancel();
                    return;
                }
                placeholder.replaceWith(draggedElement);
                draggedElement.show();
                this.draggable.dropped = true;
                eventData = {
                    action: this.indexOf(draggedElement) != MISSING_INDEX ? ACTION_SORT : ACTION_REMOVE,
                    item: draggedElement,
                    oldIndex: draggedIndex,
                    newIndex: this.indexOf(draggedElement),
                    draggableEvent: e
                };
                this.trigger(CHANGE, eventData);
                if (connectedList) {
                    connectedListEventData = $.extend({}, eventData, {
                        action: ACTION_RECEIVE,
                        oldIndex: MISSING_INDEX,
                        newIndex: connectedList.indexOf(draggedElement)
                    });
                    connectedList.trigger(CHANGE, connectedListEventData);
                }
            },
            _findTarget: function (e) {
                var element = this._findElementUnderCursor(e), items, connectWith = this.options.connectWith, node;
                if ($.contains(this.element[0], element)) {
                    items = this.items();
                    node = items.filter(element)[0] || items.has(element)[0];
                    return node ? {
                        element: $(node),
                        sortable: this
                    } : null;
                } else if (this.element[0] == element && this._isEmpty()) {
                    return {
                        element: this.element,
                        sortable: this,
                        appendToBottom: true
                    };
                } else if (this.element[0] == element && this._isLastHidden()) {
                    node = this.items().eq(0);
                    return {
                        element: node,
                        sortable: this,
                        appendAfterHidden: true
                    };
                } else if (connectWith) {
                    return this._searchConnectedTargets(element, e);
                }
            },
            _findElementUnderCursor: function (e) {
                var elementUnderCursor = kendo.elementUnderCursor(e), draggable = e.sender;
                if (containsOrEqualTo(draggable.hint[0], elementUnderCursor)) {
                    draggable.hint.hide();
                    elementUnderCursor = kendo.elementUnderCursor(e);
                    if (!elementUnderCursor) {
                        elementUnderCursor = kendo.elementUnderCursor(e);
                    }
                    draggable.hint.show();
                }
                return elementUnderCursor;
            },
            _searchConnectedTargets: function (element, e) {
                var connected = $(this.options.connectWith), sortableInstance, items, node;
                for (var i = 0; i < connected.length; i++) {
                    sortableInstance = connected.eq(i).getKendoSortable();
                    if ($.contains(connected[i], element)) {
                        if (sortableInstance) {
                            items = sortableInstance.items();
                            node = items.filter(element)[0] || items.has(element)[0];
                            if (node) {
                                sortableInstance.placeholder = this.placeholder;
                                return {
                                    element: $(node),
                                    sortable: sortableInstance
                                };
                            } else {
                                return null;
                            }
                        }
                    } else if (connected[i] == element) {
                        if (sortableInstance && sortableInstance._isEmpty()) {
                            return {
                                element: connected.eq(i),
                                sortable: sortableInstance,
                                appendToBottom: true
                            };
                        } else if (this._isCursorAfterLast(sortableInstance, e)) {
                            node = sortableInstance.items().last();
                            return {
                                element: node,
                                sortable: sortableInstance
                            };
                        }
                    }
                }
            },
            _isCursorAfterLast: function (sortable, e) {
                var lastItem = sortable.items().last(), cursorOffset = {
                        left: e.x.location,
                        top: e.y.location
                    }, lastItemOffset, delta;
                lastItemOffset = kendo.getOffset(lastItem);
                lastItemOffset.top += outerHeight(lastItem);
                lastItemOffset.left += outerWidth(lastItem);
                if (this._isFloating(lastItem)) {
                    delta = lastItemOffset.left - cursorOffset.left;
                } else {
                    delta = lastItemOffset.top - cursorOffset.top;
                }
                return delta < 0 ? true : false;
            },
            _movementByAxis: function (axis, cursorOffset, delta, eventData) {
                var cursorPosition = axis === 'x' ? cursorOffset.left : cursorOffset.top, target = delta < 0 ? this.placeholder.prev() : this.placeholder.next(), targetCenter;
                if (target.length && !target.is(':visible')) {
                    target = delta < 0 ? target.prev() : target.next();
                }
                $.extend(eventData, { target: target });
                targetCenter = this._getElementCenter(target);
                if (targetCenter) {
                    targetCenter = axis === 'x' ? targetCenter.left : targetCenter.top;
                }
                if (target.length && delta < 0 && cursorPosition - targetCenter < 0) {
                    this._movePlaceholder({
                        element: target,
                        sortable: this
                    }, 'prev', eventData);
                } else if (target.length && delta > 0 && cursorPosition - targetCenter > 0) {
                    this._movePlaceholder({
                        element: target,
                        sortable: this
                    }, 'next', eventData);
                }
            },
            _movePlaceholder: function (target, direction, eventData) {
                var placeholder = this.placeholder;
                if (!target.sortable.trigger(BEFORE_MOVE, eventData)) {
                    if (!direction) {
                        target.element.append(placeholder);
                    } else if (direction === 'prev') {
                        target.element.before(placeholder);
                    } else if (direction === 'next') {
                        target.element.after(placeholder);
                    }
                    target.sortable.trigger(MOVE, eventData);
                }
            },
            _setCursor: function () {
                var cursor = this.options.cursor, body;
                if (cursor && cursor !== 'auto') {
                    body = $(document.body);
                    this._originalCursorType = body.css('cursor');
                    body.css({ 'cursor': cursor });
                    if (!this._cursorStylesheet) {
                        this._cursorStylesheet = $('<style>* { cursor: ' + cursor + ' !important; }</style>');
                    }
                    this._cursorStylesheet.appendTo(body);
                }
            },
            _resetCursor: function () {
                if (this._originalCursorType) {
                    $(document.body).css('cursor', this._originalCursorType);
                    this._originalCursorType = null;
                    this._cursorStylesheet.remove();
                }
            },
            _getElementCenter: function (element) {
                var center = element.length ? kendo.getOffset(element) : null;
                if (center) {
                    center.top += outerHeight(element) / 2;
                    center.left += outerWidth(element) / 2;
                }
                return center;
            },
            _isFloating: function (item) {
                return /left|right/.test(item.css('float')) || /inline|table-cell/.test(item.css('display'));
            },
            _cancel: function () {
                this.draggedElement.show();
                this.placeholder.remove();
            },
            _items: function () {
                var filter = this.options.filter, items;
                if (filter) {
                    items = this.element.find(filter);
                } else {
                    items = this.element.children();
                }
                return items;
            },
            indexOf: function (element) {
                var items = this._items(), placeholder = this.placeholder, draggedElement = this.draggedElement;
                if (placeholder && element[0] == placeholder[0]) {
                    return items.not(draggedElement).index(element);
                } else {
                    return items.not(placeholder).index(element);
                }
            },
            items: function () {
                var placeholder = this.placeholder, items = this._items();
                if (placeholder) {
                    items = items.not(placeholder);
                }
                return items;
            },
            _isEmpty: function () {
                return !this.items().length;
            },
            _isLastHidden: function () {
                return this.items().length === 1 && this.items().is(':hidden');
            }
        });
        kendo.ui.plugin(Sortable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.selectable', [
        'kendo.core',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'selectable',
        name: 'Selectable',
        category: 'framework',
        depends: [
            'core',
            'userevents'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, proxy = $.proxy, abs = Math.abs, ARIASELECTED = 'aria-selected', SELECTED = 'k-state-selected', ACTIVE = 'k-state-selecting', SELECTABLE = 'k-selectable', CHANGE = 'change', NS = '.kendoSelectable', UNSELECTING = 'k-state-unselecting', INPUTSELECTOR = 'input,a,textarea,.k-multiselect-wrap,select,button,.k-button>span,.k-button>img,span.k-icon.k-i-arrow-60-down,span.k-icon.k-i-arrow-60-up', msie = kendo.support.browser.msie, supportEventDelegation = false;
        (function ($) {
            (function () {
                $('<div class="parent"><span /></div>').on('click', '>*', function () {
                    supportEventDelegation = true;
                }).find('span').click().end().off();
            }());
        }($));
        var Selectable = Widget.extend({
            init: function (element, options) {
                var that = this, multiple;
                Widget.fn.init.call(that, element, options);
                that._marquee = $('<div class=\'k-marquee\'><div class=\'k-marquee-color\'></div></div>');
                that._lastActive = null;
                that.element.addClass(SELECTABLE);
                that.relatedTarget = that.options.relatedTarget;
                multiple = that.options.multiple;
                if (this.options.aria && multiple) {
                    that.element.attr('aria-multiselectable', true);
                }
                that.userEvents = new kendo.UserEvents(that.element, {
                    global: true,
                    allowSelection: true,
                    filter: (!supportEventDelegation ? '.' + SELECTABLE + ' ' : '') + that.options.filter,
                    tap: proxy(that._tap, that)
                });
                if (multiple) {
                    that.userEvents.bind('start', proxy(that._start, that)).bind('move', proxy(that._move, that)).bind('end', proxy(that._end, that)).bind('select', proxy(that._select, that));
                }
            },
            events: [CHANGE],
            options: {
                name: 'Selectable',
                filter: '>*',
                multiple: false,
                relatedTarget: $.noop
            },
            _isElement: function (target) {
                var elements = this.element;
                var idx, length = elements.length, result = false;
                target = target[0];
                for (idx = 0; idx < length; idx++) {
                    if (elements[idx] === target) {
                        result = true;
                        break;
                    }
                }
                return result;
            },
            _tap: function (e) {
                var target = $(e.target), that = this, ctrlKey = e.event.ctrlKey || e.event.metaKey, multiple = that.options.multiple, shiftKey = multiple && e.event.shiftKey, selected, whichCode = e.event.which, buttonCode = e.event.button;
                if (!that._isElement(target.closest('.' + SELECTABLE)) || whichCode && whichCode == 3 || buttonCode && buttonCode == 2) {
                    return;
                }
                if (!this._allowSelection(e.event.target)) {
                    return;
                }
                selected = target.hasClass(SELECTED);
                if (!multiple || !ctrlKey) {
                    that.clear();
                }
                target = target.add(that.relatedTarget(target));
                if (shiftKey) {
                    that.selectRange(that._firstSelectee(), target);
                } else {
                    if (selected && ctrlKey) {
                        that._unselect(target);
                        that._notify(CHANGE);
                    } else {
                        that.value(target);
                    }
                    that._lastActive = that._downTarget = target;
                }
            },
            _start: function (e) {
                var that = this, target = $(e.target), selected = target.hasClass(SELECTED), currentElement, ctrlKey = e.event.ctrlKey || e.event.metaKey;
                if (!this._allowSelection(e.event.target)) {
                    return;
                }
                that._downTarget = target;
                if (!that._isElement(target.closest('.' + SELECTABLE))) {
                    that.userEvents.cancel();
                    return;
                }
                if (that.options.useAllItems) {
                    that._items = that.element.find(that.options.filter);
                } else {
                    currentElement = target.closest(that.element);
                    that._items = currentElement.find(that.options.filter);
                }
                e.sender.capture();
                that._marquee.appendTo(document.body).css({
                    left: e.x.client + 1,
                    top: e.y.client + 1,
                    width: 0,
                    height: 0
                });
                if (!ctrlKey) {
                    that.clear();
                }
                target = target.add(that.relatedTarget(target));
                if (selected) {
                    that._selectElement(target, true);
                    if (ctrlKey) {
                        target.addClass(UNSELECTING);
                    }
                }
            },
            _move: function (e) {
                var that = this, position = {
                        left: e.x.startLocation > e.x.location ? e.x.location : e.x.startLocation,
                        top: e.y.startLocation > e.y.location ? e.y.location : e.y.startLocation,
                        width: abs(e.x.initialDelta),
                        height: abs(e.y.initialDelta)
                    };
                that._marquee.css(position);
                that._invalidateSelectables(position, e.event.ctrlKey || e.event.metaKey);
                e.preventDefault();
            },
            _end: function () {
                var that = this;
                that._marquee.remove();
                that._unselect(that.element.find(that.options.filter + '.' + UNSELECTING)).removeClass(UNSELECTING);
                var target = that.element.find(that.options.filter + '.' + ACTIVE);
                target = target.add(that.relatedTarget(target));
                that.value(target);
                that._lastActive = that._downTarget;
                that._items = null;
            },
            _invalidateSelectables: function (position, ctrlKey) {
                var idx, length, target = this._downTarget[0], items = this._items, related, toSelect;
                for (idx = 0, length = items.length; idx < length; idx++) {
                    toSelect = items.eq(idx);
                    related = toSelect.add(this.relatedTarget(toSelect));
                    if (collision(toSelect, position)) {
                        if (toSelect.hasClass(SELECTED)) {
                            if (ctrlKey && target !== toSelect[0]) {
                                related.removeClass(SELECTED).addClass(UNSELECTING);
                            }
                        } else if (!toSelect.hasClass(ACTIVE) && !toSelect.hasClass(UNSELECTING)) {
                            related.addClass(ACTIVE);
                        }
                    } else {
                        if (toSelect.hasClass(ACTIVE)) {
                            related.removeClass(ACTIVE);
                        } else if (ctrlKey && toSelect.hasClass(UNSELECTING)) {
                            related.removeClass(UNSELECTING).addClass(SELECTED);
                        }
                    }
                }
            },
            value: function (val) {
                var that = this, selectElement = proxy(that._selectElement, that);
                if (val) {
                    val.each(function () {
                        selectElement(this);
                    });
                    that._notify(CHANGE);
                    return;
                }
                return that.element.find(that.options.filter + '.' + SELECTED);
            },
            _firstSelectee: function () {
                var that = this, selected;
                if (that._lastActive !== null) {
                    return that._lastActive;
                }
                selected = that.value();
                return selected.length > 0 ? selected[0] : that.element.find(that.options.filter)[0];
            },
            _selectElement: function (element, preventNotify) {
                var toSelect = $(element), isPrevented = !preventNotify && this._notify('select', { element: element });
                toSelect.removeClass(ACTIVE);
                if (!isPrevented) {
                    toSelect.addClass(SELECTED);
                    if (this.options.aria) {
                        toSelect.attr(ARIASELECTED, true);
                    }
                }
            },
            _notify: function (name, args) {
                args = args || {};
                return this.trigger(name, args);
            },
            _unselect: function (element) {
                element.removeClass(SELECTED);
                if (this.options.aria) {
                    element.attr(ARIASELECTED, false);
                }
                return element;
            },
            _select: function (e) {
                if (this._allowSelection(e.event.target)) {
                    if (!msie || msie && !$(kendo._activeElement()).is(INPUTSELECTOR)) {
                        e.preventDefault();
                    }
                }
            },
            _allowSelection: function (target) {
                if ($(target).is(INPUTSELECTOR)) {
                    this.userEvents.cancel();
                    this._downTarget = null;
                    return false;
                }
                return true;
            },
            resetTouchEvents: function () {
                this.userEvents.cancel();
            },
            clear: function () {
                var items = this.element.find(this.options.filter + '.' + SELECTED);
                this._unselect(items);
            },
            selectRange: function (start, end) {
                var that = this, idx, tmp, items;
                that.clear();
                if (that.element.length > 1) {
                    items = that.options.continuousItems();
                }
                if (!items || !items.length) {
                    items = that.element.find(that.options.filter);
                }
                start = $.inArray($(start)[0], items);
                end = $.inArray($(end)[0], items);
                if (start > end) {
                    tmp = start;
                    start = end;
                    end = tmp;
                }
                if (!that.options.useAllItems) {
                    end += that.element.length - 1;
                }
                for (idx = start; idx <= end; idx++) {
                    that._selectElement(items[idx]);
                }
                that._notify(CHANGE);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.element.off(NS);
                that.userEvents.destroy();
                that._marquee = that._lastActive = that.element = that.userEvents = null;
            }
        });
        Selectable.parseOptions = function (selectable) {
            var asLowerString = typeof selectable === 'string' && selectable.toLowerCase();
            return {
                multiple: asLowerString && asLowerString.indexOf('multiple') > -1,
                cell: asLowerString && asLowerString.indexOf('cell') > -1
            };
        };
        function collision(element, position) {
            if (!element.is(':visible')) {
                return false;
            }
            var elementPosition = kendo.getOffset(element), right = position.left + position.width, bottom = position.top + position.height;
            elementPosition.right = elementPosition.left + kendo._outerWidth(element);
            elementPosition.bottom = elementPosition.top + kendo._outerHeight(element);
            return !(elementPosition.left > right || elementPosition.right < position.left || elementPosition.top > bottom || elementPosition.bottom < position.top);
        }
        kendo.ui.plugin(Selectable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.button', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'button',
        name: 'Button',
        category: 'web',
        description: 'The Button widget displays styled buttons.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, proxy = $.proxy, keys = kendo.keys, CLICK = 'click', KBUTTON = 'k-button', KBUTTONICON = 'k-button-icon', KBUTTONICONTEXT = 'k-button-icontext', NS = '.kendoButton', DISABLED = 'disabled', DISABLEDSTATE = 'k-state-disabled', FOCUSEDSTATE = 'k-state-focused', SELECTEDSTATE = 'k-state-selected';
        var Button = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                element = that.wrapper = that.element;
                options = that.options;
                element.addClass(KBUTTON).attr('role', 'button');
                options.enable = options.enable && !element.attr(DISABLED);
                that.enable(options.enable);
                that._tabindex();
                that._graphics();
                element.on(CLICK + NS, proxy(that._click, that)).on('focus' + NS, proxy(that._focus, that)).on('blur' + NS, proxy(that._blur, that)).on('keydown' + NS, proxy(that._keydown, that)).on('keyup' + NS, proxy(that._keyup, that));
                kendo.notify(that);
            },
            destroy: function () {
                var that = this;
                that.wrapper.off(NS);
                Widget.fn.destroy.call(that);
            },
            events: [CLICK],
            options: {
                name: 'Button',
                icon: '',
                spriteCssClass: '',
                imageUrl: '',
                enable: true
            },
            _isNativeButton: function () {
                return this.element.prop('tagName').toLowerCase() == 'button';
            },
            _click: function (e) {
                if (this.options.enable) {
                    if (this.trigger(CLICK, { event: e })) {
                        e.preventDefault();
                    }
                }
            },
            _focus: function () {
                if (this.options.enable) {
                    this.element.addClass(FOCUSEDSTATE);
                }
            },
            _blur: function () {
                this.element.removeClass(FOCUSEDSTATE);
            },
            _keydown: function (e) {
                var that = this;
                if (!that._isNativeButton()) {
                    if (e.keyCode == keys.ENTER || e.keyCode == keys.SPACEBAR) {
                        if (e.keyCode == keys.SPACEBAR) {
                            e.preventDefault();
                            if (that.options.enable) {
                                that.element.addClass(SELECTEDSTATE);
                            }
                        }
                        that._click(e);
                    }
                }
            },
            _keyup: function () {
                this.element.removeClass(SELECTEDSTATE);
            },
            _graphics: function () {
                var that = this, element = that.element, options = that.options, icon = options.icon, spriteCssClass = options.spriteCssClass, imageUrl = options.imageUrl, span, img, isEmpty;
                if (spriteCssClass || imageUrl || icon) {
                    isEmpty = true;
                    element.contents().filter(function () {
                        return !$(this).hasClass('k-sprite') && !$(this).hasClass('k-icon') && !$(this).hasClass('k-image');
                    }).each(function (idx, el) {
                        if (el.nodeType == 1 || el.nodeType == 3 && $.trim(el.nodeValue).length > 0) {
                            isEmpty = false;
                        }
                    });
                    if (isEmpty) {
                        element.addClass(KBUTTONICON);
                    } else {
                        element.addClass(KBUTTONICONTEXT);
                    }
                }
                if (icon) {
                    span = element.children('span.k-icon').first();
                    if (!span[0]) {
                        span = $('<span class="k-icon"></span>').prependTo(element);
                    }
                    span.addClass('k-i-' + icon);
                } else if (spriteCssClass) {
                    span = element.children('span.k-sprite').first();
                    if (!span[0]) {
                        span = $('<span class="k-sprite"></span>').prependTo(element);
                    }
                    span.addClass(spriteCssClass);
                } else if (imageUrl) {
                    img = element.children('img.k-image').first();
                    if (!img[0]) {
                        img = $('<img alt="icon" class="k-image" />').prependTo(element);
                    }
                    img.attr('src', imageUrl);
                }
            },
            enable: function (enable) {
                var that = this, element = that.element;
                if (enable === undefined) {
                    enable = true;
                }
                enable = !!enable;
                that.options.enable = enable;
                element.toggleClass(DISABLEDSTATE, !enable).attr('aria-disabled', !enable).attr(DISABLED, !enable);
                try {
                    element.blur();
                } catch (err) {
                }
            }
        });
        kendo.ui.plugin(Button);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pager', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'pager',
        name: 'Pager',
        category: 'framework',
        depends: ['data'],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, proxy = $.proxy, FIRST = '.k-i-seek-w', LAST = '.k-i-seek-e', PREV = '.k-i-arrow-w', NEXT = '.k-i-arrow-e', CHANGE = 'change', NS = '.kendoPager', CLICK = 'click', KEYDOWN = 'keydown', DISABLED = 'disabled', iconTemplate = kendo.template('<a href="\\#" aria-label="#=text#" title="#=text#" class="k-link k-pager-nav #= wrapClassName #"><span class="k-icon #= className #"></span></a>');
        function button(template, idx, text, numeric, title) {
            return template({
                idx: idx,
                text: text,
                ns: kendo.ns,
                numeric: numeric,
                title: title || ''
            });
        }
        function icon(className, text, wrapClassName) {
            return iconTemplate({
                className: className.substring(1),
                text: text,
                wrapClassName: wrapClassName || ''
            });
        }
        function update(element, selector, page, disabled) {
            element.find(selector).parent().attr(kendo.attr('page'), page).attr('tabindex', -1).toggleClass('k-state-disabled', disabled);
        }
        function first(element, page) {
            update(element, FIRST, 1, page <= 1);
        }
        function prev(element, page) {
            update(element, PREV, Math.max(1, page - 1), page <= 1);
        }
        function next(element, page, totalPages) {
            update(element, NEXT, Math.min(totalPages, page + 1), page >= totalPages);
        }
        function last(element, page, totalPages) {
            update(element, LAST, totalPages, page >= totalPages);
        }
        var Pager = Widget.extend({
            init: function (element, options) {
                var that = this, page, totalPages;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                that.dataSource = kendo.data.DataSource.create(options.dataSource);
                that.linkTemplate = kendo.template(that.options.linkTemplate);
                that.selectTemplate = kendo.template(that.options.selectTemplate);
                that.currentPageTemplate = kendo.template(that.options.currentPageTemplate);
                page = that.page();
                totalPages = that.totalPages();
                that._refreshHandler = proxy(that.refresh, that);
                that.dataSource.bind(CHANGE, that._refreshHandler);
                if (options.previousNext) {
                    if (!that.element.find(FIRST).length) {
                        that.element.append(icon(FIRST, options.messages.first, 'k-pager-first'));
                        first(that.element, page, totalPages);
                    }
                    if (!that.element.find(PREV).length) {
                        that.element.append(icon(PREV, options.messages.previous));
                        prev(that.element, page, totalPages);
                    }
                }
                if (options.numeric) {
                    that.list = that.element.find('.k-pager-numbers');
                    if (!that.list.length) {
                        that.list = $('<ul class="k-pager-numbers k-reset" />').appendTo(that.element);
                    }
                }
                if (options.input) {
                    if (!that.element.find('.k-pager-input').length) {
                        that.element.append('<span class="k-pager-input k-label">' + options.messages.page + '<input class="k-textbox">' + kendo.format(options.messages.of, totalPages) + '</span>');
                    }
                    that.element.on(KEYDOWN + NS, '.k-pager-input input', proxy(that._keydown, that));
                }
                if (options.previousNext) {
                    if (!that.element.find(NEXT).length) {
                        that.element.append(icon(NEXT, options.messages.next));
                        next(that.element, page, totalPages);
                    }
                    if (!that.element.find(LAST).length) {
                        that.element.append(icon(LAST, options.messages.last, 'k-pager-last'));
                        last(that.element, page, totalPages);
                    }
                }
                if (options.pageSizes) {
                    if (!that.element.find('.k-pager-sizes').length) {
                        var pageSizes = options.pageSizes.length ? options.pageSizes : [
                            'all',
                            5,
                            10,
                            20
                        ];
                        var pageItems = $.map(pageSizes, function (size) {
                            if (size.toLowerCase && size.toLowerCase() === 'all') {
                                return '<option value=\'all\'>' + options.messages.allPages + '</option>';
                            }
                            return '<option>' + size + '</option>';
                        });
                        $('<span class="k-pager-sizes k-label"><select/>' + options.messages.itemsPerPage + '</span>').appendTo(that.element).find('select').html(pageItems.join('')).end().appendTo(that.element);
                    }
                    that.element.find('.k-pager-sizes select').val(that.pageSize());
                    if (kendo.ui.DropDownList) {
                        that.element.find('.k-pager-sizes select').show().kendoDropDownList();
                    }
                    that.element.on(CHANGE + NS, '.k-pager-sizes select', proxy(that._change, that));
                }
                if (options.refresh) {
                    if (!that.element.find('.k-pager-refresh').length) {
                        that.element.append('<a href="#" class="k-pager-refresh k-link" title="' + options.messages.refresh + '" aria-label="' + options.messages.refresh + '"><span class="k-icon k-i-reload"></span></a>');
                    }
                    that.element.on(CLICK + NS, '.k-pager-refresh', proxy(that._refreshClick, that));
                }
                if (options.info) {
                    if (!that.element.find('.k-pager-info').length) {
                        that.element.append('<span class="k-pager-info k-label" />');
                    }
                }
                that.element.on(CLICK + NS, 'a', proxy(that._click, that)).addClass('k-pager-wrap k-widget k-floatwrap');
                that.element.on(CLICK + NS, '.k-current-page', proxy(that._toggleActive, that));
                if (options.autoBind) {
                    that.refresh();
                }
                kendo.notify(that);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.element.off(NS);
                that.dataSource.unbind(CHANGE, that._refreshHandler);
                that._refreshHandler = null;
                kendo.destroy(that.element);
                that.element = that.list = null;
            },
            events: [CHANGE],
            options: {
                name: 'Pager',
                selectTemplate: '<li><span class="k-state-selected">#=text#</span></li>',
                currentPageTemplate: '<li class="k-current-page"><span class="k-link k-pager-nav">#=text#</span></li>',
                linkTemplate: '<li><a tabindex="-1" href="\\#" class="k-link" data-#=ns#page="#=idx#" #if (title !== "") {# title="#=title#" #}#>#=text#</a></li>',
                buttonCount: 10,
                autoBind: true,
                numeric: true,
                info: true,
                input: false,
                previousNext: true,
                pageSizes: false,
                refresh: false,
                messages: {
                    allPages: 'All',
                    display: '{0} - {1} of {2} items',
                    empty: 'No items to display',
                    page: 'Page',
                    of: 'of {0}',
                    itemsPerPage: 'items per page',
                    first: 'Go to the first page',
                    previous: 'Go to the previous page',
                    next: 'Go to the next page',
                    last: 'Go to the last page',
                    refresh: 'Refresh',
                    morePages: 'More pages'
                }
            },
            setDataSource: function (dataSource) {
                var that = this;
                that.dataSource.unbind(CHANGE, that._refreshHandler);
                that.dataSource = that.options.dataSource = dataSource;
                dataSource.bind(CHANGE, that._refreshHandler);
                if (that.options.autoBind) {
                    dataSource.fetch();
                }
            },
            refresh: function (e) {
                var that = this, idx, end, start = 1, reminder, page = that.page(), html = '', options = that.options, pageSize = that.pageSize(), total = that.dataSource.total(), totalPages = that.totalPages(), linkTemplate = that.linkTemplate, buttonCount = options.buttonCount;
                if (e && e.action == 'itemchange') {
                    return;
                }
                if (options.numeric) {
                    if (page > buttonCount) {
                        reminder = page % buttonCount;
                        start = reminder === 0 ? page - buttonCount + 1 : page - reminder + 1;
                    }
                    end = Math.min(start + buttonCount - 1, totalPages);
                    if (start > 1) {
                        html += button(linkTemplate, start - 1, '...', false, options.messages.morePages);
                    }
                    for (idx = start; idx <= end; idx++) {
                        html += button(idx == page ? that.selectTemplate : linkTemplate, idx, idx, true);
                    }
                    if (end < totalPages) {
                        html += button(linkTemplate, idx, '...', false, options.messages.morePages);
                    }
                    if (html === '') {
                        html = that.selectTemplate({ text: 0 });
                    }
                    html = this.currentPageTemplate({ text: page }) + html;
                    that.list.removeClass('k-state-expanded').html(html);
                }
                if (options.info) {
                    if (total > 0) {
                        html = kendo.format(options.messages.display, Math.min((page - 1) * pageSize + 1, total), Math.min(page * pageSize, total), total);
                    } else {
                        html = options.messages.empty;
                    }
                    that.element.find('.k-pager-info').html(html);
                }
                if (options.input) {
                    that.element.find('.k-pager-input').html(that.options.messages.page + '<input class="k-textbox" aria-label="' + page + '">' + kendo.format(options.messages.of, totalPages)).find('input').val(page).attr(DISABLED, total < 1).toggleClass('k-state-disabled', total < 1);
                }
                if (options.previousNext) {
                    first(that.element, page, totalPages);
                    prev(that.element, page, totalPages);
                    next(that.element, page, totalPages);
                    last(that.element, page, totalPages);
                }
                if (options.pageSizes) {
                    var hasAll = that.element.find('.k-pager-sizes option[value=\'all\']').length > 0;
                    var selectAll = hasAll && pageSize === this.dataSource.total();
                    var text = pageSize;
                    if (selectAll) {
                        pageSize = 'all';
                        text = options.messages.allPages;
                    }
                    that.element.find('.k-pager-sizes select').val(pageSize).attr('aria-label', pageSize).filter('[' + kendo.attr('role') + '=dropdownlist]').kendoDropDownList('value', pageSize).kendoDropDownList('text', text);
                }
            },
            _keydown: function (e) {
                if (e.keyCode === kendo.keys.ENTER) {
                    var input = this.element.find('.k-pager-input').find('input'), page = parseInt(input.val(), 10);
                    if (isNaN(page) || page < 1 || page > this.totalPages()) {
                        page = this.page();
                    }
                    input.val(page);
                    this.page(page);
                }
            },
            _refreshClick: function (e) {
                e.preventDefault();
                this.dataSource.read();
            },
            _change: function (e) {
                var value = e.currentTarget.value;
                var pageSize = parseInt(value, 10);
                var dataSource = this.dataSource;
                if (!isNaN(pageSize)) {
                    dataSource.pageSize(pageSize);
                } else if ((value + '').toLowerCase() == 'all') {
                    dataSource.pageSize(dataSource.total());
                }
            },
            _toggleActive: function () {
                this.list.toggleClass('k-state-expanded');
            },
            _click: function (e) {
                var target = $(e.currentTarget);
                e.preventDefault();
                if (!target.is('.k-state-disabled')) {
                    this.page(target.attr(kendo.attr('page')));
                }
            },
            totalPages: function () {
                return Math.ceil((this.dataSource.total() || 0) / (this.pageSize() || 1));
            },
            pageSize: function () {
                return this.dataSource.pageSize() || this.dataSource.total();
            },
            page: function (page) {
                if (page !== undefined) {
                    if (this.trigger('pageChange', { index: page })) {
                        return;
                    }
                    this.dataSource.page(page);
                    this.trigger(CHANGE, { index: page });
                } else {
                    if (this.dataSource.total() > 0) {
                        return this.dataSource.page();
                    } else {
                        return 0;
                    }
                }
            }
        });
        ui.plugin(Pager);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.notification', [
        'kendo.core',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'notification',
        name: 'Notification',
        category: 'web',
        description: 'The Notification widget displays user alerts.',
        depends: [
            'core',
            'popup'
        ],
        features: [{
                id: 'notification-fx',
                name: 'Animation',
                description: 'Support for animation',
                depends: ['fx']
            }]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, proxy = $.proxy, extend = $.extend, setTimeout = window.setTimeout, CLICK = 'click', SHOW = 'show', HIDE = 'hide', KNOTIFICATION = 'k-notification', KICLOSE = '.k-notification-wrap .k-i-close', KHIDING = 'k-hiding', INFO = 'info', SUCCESS = 'success', WARNING = 'warning', ERROR = 'error', TOP = 'top', LEFT = 'left', BOTTOM = 'bottom', RIGHT = 'right', UP = 'up', NS = '.kendoNotification', WRAPPER = '<div class="k-widget k-notification"></div>', TEMPLATE = '<div class="k-notification-wrap">' + '<span class="k-icon k-i-#=typeIcon#" title="#=typeIcon#"></span>' + '#=content#' + '<span class="k-icon k-i-close" title="Hide"></span>' + '</div>', SAFE_TEMPLATE = TEMPLATE.replace('#=content#', '#:content#');
        var Notification = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                if (!options.appendTo || !$(options.appendTo).is(element)) {
                    that.element.hide();
                }
                that._compileTemplates(options.templates);
                that._guid = '_' + kendo.guid();
                that._isRtl = kendo.support.isRtl(element);
                that._compileStacking(options.stacking, options.position.top, options.position.left);
                kendo.notify(that);
            },
            events: [
                SHOW,
                HIDE
            ],
            options: {
                name: 'Notification',
                position: {
                    pinned: true,
                    top: null,
                    left: null,
                    bottom: 20,
                    right: 20
                },
                stacking: 'default',
                hideOnClick: true,
                button: false,
                allowHideAfter: 0,
                autoHideAfter: 5000,
                appendTo: null,
                width: null,
                height: null,
                templates: [],
                animation: {
                    open: {
                        effects: 'fade:in',
                        duration: 300
                    },
                    close: {
                        effects: 'fade:out',
                        duration: 600,
                        hide: true
                    }
                }
            },
            _compileTemplates: function (templates) {
                var that = this;
                var kendoTemplate = kendo.template;
                that._compiled = {};
                $.each(templates, function (key, value) {
                    that._compiled[value.type] = kendoTemplate(value.template || $('#' + value.templateId).html());
                });
                that._defaultCompiled = kendoTemplate(TEMPLATE);
                that._safeCompiled = kendoTemplate(SAFE_TEMPLATE);
            },
            _getCompiled: function (type, safe) {
                var defaultCompiled = safe ? this._safeCompiled : this._defaultCompiled;
                return type ? this._compiled[type] || defaultCompiled : defaultCompiled;
            },
            _compileStacking: function (stacking, top, left) {
                var that = this, paddings = {
                        paddingTop: 0,
                        paddingRight: 0,
                        paddingBottom: 0,
                        paddingLeft: 0
                    }, horizontalAlignment = left !== null ? LEFT : RIGHT, origin, position;
                switch (stacking) {
                case 'down':
                    origin = BOTTOM + ' ' + horizontalAlignment;
                    position = TOP + ' ' + horizontalAlignment;
                    delete paddings.paddingBottom;
                    break;
                case RIGHT:
                    origin = TOP + ' ' + RIGHT;
                    position = TOP + ' ' + LEFT;
                    delete paddings.paddingRight;
                    break;
                case LEFT:
                    origin = TOP + ' ' + LEFT;
                    position = TOP + ' ' + RIGHT;
                    delete paddings.paddingLeft;
                    break;
                case UP:
                    origin = TOP + ' ' + horizontalAlignment;
                    position = BOTTOM + ' ' + horizontalAlignment;
                    delete paddings.paddingTop;
                    break;
                default:
                    if (top !== null) {
                        origin = BOTTOM + ' ' + horizontalAlignment;
                        position = TOP + ' ' + horizontalAlignment;
                        delete paddings.paddingBottom;
                    } else {
                        origin = TOP + ' ' + horizontalAlignment;
                        position = BOTTOM + ' ' + horizontalAlignment;
                        delete paddings.paddingTop;
                    }
                    break;
                }
                that._popupOrigin = origin;
                that._popupPosition = position;
                that._popupPaddings = paddings;
            },
            _attachPopupEvents: function (options, popup) {
                var that = this, allowHideAfter = options.allowHideAfter, attachDelay = !isNaN(allowHideAfter) && allowHideAfter > 0, closeIcon;
                function attachClick(target) {
                    target.on(CLICK + NS, function () {
                        that._hidePopup(popup);
                    });
                }
                if (options.hideOnClick) {
                    popup.bind('activate', function () {
                        if (attachDelay) {
                            setTimeout(function () {
                                attachClick(popup.element);
                            }, allowHideAfter);
                        } else {
                            attachClick(popup.element);
                        }
                    });
                } else if (options.button) {
                    closeIcon = popup.element.find(KICLOSE);
                    if (attachDelay) {
                        setTimeout(function () {
                            attachClick(closeIcon);
                        }, allowHideAfter);
                    } else {
                        attachClick(closeIcon);
                    }
                }
            },
            _showPopup: function (wrapper, options) {
                var that = this, autoHideAfter = options.autoHideAfter, x = options.position.left, y = options.position.top, popup, openPopup;
                openPopup = $('.' + that._guid + ':not(.' + KHIDING + ')').last();
                popup = new kendo.ui.Popup(wrapper, {
                    anchor: openPopup[0] ? openPopup : document.body,
                    origin: that._popupOrigin,
                    position: that._popupPosition,
                    animation: options.animation,
                    modal: true,
                    collision: '',
                    isRtl: that._isRtl,
                    close: function () {
                        that._triggerHide(this.element);
                    },
                    deactivate: function (e) {
                        e.sender.element.off(NS);
                        e.sender.element.find(KICLOSE).off(NS);
                        e.sender.destroy();
                    }
                });
                that._attachPopupEvents(options, popup);
                if (openPopup[0]) {
                    popup.open();
                } else {
                    if (x === null) {
                        x = $(window).width() - wrapper.width() - options.position.right;
                    }
                    if (y === null) {
                        y = $(window).height() - wrapper.height() - options.position.bottom;
                    }
                    popup.open(x, y);
                }
                popup.wrapper.addClass(that._guid).css(extend({
                    margin: 0,
                    zIndex: 10050
                }, that._popupPaddings));
                if (options.position.pinned) {
                    popup.wrapper.css('position', 'fixed');
                    if (openPopup[0]) {
                        that._togglePin(popup.wrapper, true);
                    }
                } else if (!openPopup[0]) {
                    that._togglePin(popup.wrapper, false);
                }
                if (autoHideAfter > 0) {
                    setTimeout(function () {
                        that._hidePopup(popup);
                    }, autoHideAfter);
                }
            },
            _hidePopup: function (popup) {
                popup.wrapper.addClass(KHIDING);
                popup.close();
            },
            _togglePin: function (wrapper, pin) {
                var win = $(window), sign = pin ? -1 : 1;
                wrapper.css({
                    top: parseInt(wrapper.css(TOP), 10) + sign * win.scrollTop(),
                    left: parseInt(wrapper.css(LEFT), 10) + sign * win.scrollLeft()
                });
            },
            _attachStaticEvents: function (options, wrapper) {
                var that = this, allowHideAfter = options.allowHideAfter, attachDelay = !isNaN(allowHideAfter) && allowHideAfter > 0;
                function attachClick(target) {
                    target.on(CLICK + NS, proxy(that._hideStatic, that, wrapper));
                }
                if (options.hideOnClick) {
                    if (attachDelay) {
                        setTimeout(function () {
                            attachClick(wrapper);
                        }, allowHideAfter);
                    } else {
                        attachClick(wrapper);
                    }
                } else if (options.button) {
                    if (attachDelay) {
                        setTimeout(function () {
                            attachClick(wrapper.find(KICLOSE));
                        }, allowHideAfter);
                    } else {
                        attachClick(wrapper.find(KICLOSE));
                    }
                }
            },
            _showStatic: function (wrapper, options) {
                var that = this, autoHideAfter = options.autoHideAfter, animation = options.animation, insertionMethod = options.stacking == UP || options.stacking == LEFT ? 'prependTo' : 'appendTo';
                wrapper.addClass(that._guid)[insertionMethod](options.appendTo).hide().kendoAnimate(animation.open || false);
                that._attachStaticEvents(options, wrapper);
                if (autoHideAfter > 0) {
                    setTimeout(function () {
                        that._hideStatic(wrapper);
                    }, autoHideAfter);
                }
            },
            _hideStatic: function (wrapper) {
                wrapper.kendoAnimate(extend(this.options.animation.close || false, {
                    complete: function () {
                        wrapper.off(NS).find(KICLOSE).off(NS);
                        wrapper.remove();
                    }
                }));
                this._triggerHide(wrapper);
            },
            _triggerHide: function (element) {
                this.trigger(HIDE, { element: element });
                this.angular('cleanup', function () {
                    return { elements: element };
                });
            },
            show: function (content, type, safe) {
                var that = this, options = that.options, wrapper = $(WRAPPER), args, defaultArgs;
                if (!type) {
                    type = INFO;
                }
                if (content !== null && content !== undefined && content !== '') {
                    if (kendo.isFunction(content)) {
                        content = content();
                    }
                    defaultArgs = {
                        typeIcon: type,
                        content: ''
                    };
                    if ($.isPlainObject(content)) {
                        args = extend(defaultArgs, content);
                    } else {
                        args = extend(defaultArgs, { content: content });
                    }
                    wrapper.addClass(KNOTIFICATION + '-' + type).toggleClass(KNOTIFICATION + '-button', options.button).attr('data-role', 'alert').css({
                        width: options.width,
                        height: options.height
                    }).append(that._getCompiled(type, safe)(args));
                    that.angular('compile', function () {
                        return {
                            elements: wrapper,
                            data: [{ dataItem: args }]
                        };
                    });
                    if ($(options.appendTo)[0]) {
                        that._showStatic(wrapper, options);
                    } else {
                        that._showPopup(wrapper, options);
                    }
                    that.trigger(SHOW, { element: wrapper });
                }
                return that;
            },
            showText: function (content, type) {
                this.show(content, type, true);
            },
            info: function (content) {
                return this.show(content, INFO);
            },
            success: function (content) {
                return this.show(content, SUCCESS);
            },
            warning: function (content) {
                return this.show(content, WARNING);
            },
            error: function (content) {
                return this.show(content, ERROR);
            },
            hide: function () {
                var that = this, openedNotifications = that.getNotifications();
                if (that.options.appendTo) {
                    openedNotifications.each(function (idx, element) {
                        that._hideStatic($(element));
                    });
                } else {
                    openedNotifications.each(function (idx, element) {
                        var popup = $(element).data('kendoPopup');
                        if (popup) {
                            that._hidePopup(popup);
                        }
                    });
                }
                return that;
            },
            getNotifications: function () {
                var that = this, guidElements = $('.' + that._guid + ':not(.' + KHIDING + ')');
                if (that.options.appendTo) {
                    return guidElements;
                } else {
                    return guidElements.children('.' + KNOTIFICATION);
                }
            },
            setOptions: function (newOptions) {
                var that = this, options;
                Widget.fn.setOptions.call(that, newOptions);
                options = that.options;
                if (newOptions.templates !== undefined) {
                    that._compileTemplates(options.templates);
                }
                if (newOptions.stacking !== undefined || newOptions.position !== undefined) {
                    that._compileStacking(options.stacking, options.position.top, options.position.left);
                }
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.getNotifications().off(NS).find(KICLOSE).off(NS);
            }
        });
        kendo.ui.plugin(Notification);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.tooltip', [
        'kendo.core',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'tooltip',
        name: 'Tooltip',
        category: 'web',
        description: 'The Tooltip widget displays a popup hint for a given html element.',
        depends: [
            'core',
            'popup'
        ],
        features: [{
                id: 'tooltip-fx',
                name: 'Animation',
                description: 'Support for animation',
                depends: ['fx']
            }]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, Popup = kendo.ui.Popup, isFunction = kendo.isFunction, isPlainObject = $.isPlainObject, extend = $.extend, proxy = $.proxy, DOCUMENT = $(document), isLocalUrl = kendo.isLocalUrl, ARIAIDSUFFIX = '_tt_active', DESCRIBEDBY = 'aria-describedby', SHOW = 'show', HIDE = 'hide', ERROR = 'error', CONTENTLOAD = 'contentLoad', REQUESTSTART = 'requestStart', KCONTENTFRAME = 'k-content-frame', TEMPLATE = '<div role="tooltip" class="k-widget k-tooltip#if (!autoHide) {# k-tooltip-closable#}#">#if (!autoHide) {# <div class="k-tooltip-button"><a href="\\#" class="k-icon k-i-close" title="Close"></a></div> #}#' + '<div class="k-tooltip-content"></div>' + '#if (callout){ #<div class="k-callout k-callout-#=dir#"></div>#}#' + '</div>', IFRAMETEMPLATE = kendo.template('<iframe frameborder=\'0\' class=\'' + KCONTENTFRAME + '\' ' + 'src=\'#= content.url #\'>' + 'This page requires frames in order to show content' + '</iframe>'), NS = '.kendoTooltip', POSITIONS = {
                bottom: {
                    origin: 'bottom center',
                    position: 'top center'
                },
                top: {
                    origin: 'top center',
                    position: 'bottom center'
                },
                left: {
                    origin: 'center left',
                    position: 'center right',
                    collision: 'fit flip'
                },
                right: {
                    origin: 'center right',
                    position: 'center left',
                    collision: 'fit flip'
                },
                center: {
                    position: 'center center',
                    origin: 'center center'
                }
            }, REVERSE = {
                'top': 'bottom',
                'bottom': 'top',
                'left': 'right',
                'right': 'left',
                'center': 'center'
            }, DIRCLASSES = {
                bottom: 'n',
                top: 's',
                left: 'e',
                right: 'w',
                center: 'n'
            }, DIMENSIONS = {
                'horizontal': {
                    offset: 'top',
                    size: 'outerHeight'
                },
                'vertical': {
                    offset: 'left',
                    size: 'outerWidth'
                }
            }, DEFAULTCONTENT = function (e) {
                return e.target.data(kendo.ns + 'title');
            };
        function restoreTitle(element) {
            while (element.length) {
                restoreTitleAttributeForElement(element);
                element = element.parent();
            }
        }
        function restoreTitleAttributeForElement(element) {
            var title = element.data(kendo.ns + 'title');
            if (title) {
                element.attr('title', title);
                element.removeData(kendo.ns + 'title');
            }
        }
        function saveTitleAttributeForElement(element) {
            var title = element.attr('title');
            if (title) {
                element.data(kendo.ns + 'title', title);
                element.attr('title', '');
            }
        }
        function saveTitleAttributes(element) {
            while (element.length && !element.is('body')) {
                saveTitleAttributeForElement(element);
                element = element.parent();
            }
        }
        var Tooltip = Widget.extend({
            init: function (element, options) {
                var that = this, axis;
                Widget.fn.init.call(that, element, options);
                axis = that.options.position.match(/left|right/) ? 'horizontal' : 'vertical';
                that.dimensions = DIMENSIONS[axis];
                that._documentKeyDownHandler = proxy(that._documentKeyDown, that);
                that.element.on(that.options.showOn + NS, that.options.filter, proxy(that._showOn, that)).on('mouseenter' + NS, that.options.filter, proxy(that._mouseenter, that));
                if (this.options.autoHide) {
                    that.element.on('mouseleave' + NS, that.options.filter, proxy(that._mouseleave, that));
                }
            },
            options: {
                name: 'Tooltip',
                filter: '',
                content: DEFAULTCONTENT,
                showAfter: 100,
                callout: true,
                position: 'bottom',
                showOn: 'mouseenter',
                autoHide: true,
                width: null,
                height: null,
                animation: {
                    open: {
                        effects: 'fade:in',
                        duration: 0
                    },
                    close: {
                        effects: 'fade:out',
                        duration: 40,
                        hide: true
                    }
                }
            },
            events: [
                SHOW,
                HIDE,
                CONTENTLOAD,
                ERROR,
                REQUESTSTART
            ],
            _mouseenter: function (e) {
                saveTitleAttributes($(e.currentTarget));
            },
            _showOn: function (e) {
                var that = this;
                var currentTarget = $(e.currentTarget);
                if (that.options.showOn && that.options.showOn.match(/click|focus/)) {
                    that._show(currentTarget);
                } else {
                    clearTimeout(that.timeout);
                    that.timeout = setTimeout(function () {
                        that._show(currentTarget);
                    }, that.options.showAfter);
                }
            },
            _appendContent: function (target) {
                var that = this, contentOptions = that.options.content, element = that.content, showIframe = that.options.iframe, iframe;
                if (isPlainObject(contentOptions) && contentOptions.url) {
                    if (!('iframe' in that.options)) {
                        showIframe = !isLocalUrl(contentOptions.url);
                    }
                    that.trigger(REQUESTSTART, {
                        options: contentOptions,
                        target: target
                    });
                    if (!showIframe) {
                        element.empty();
                        kendo.ui.progress(element, true);
                        that._ajaxRequest(contentOptions);
                    } else {
                        element.hide();
                        iframe = element.find('.' + KCONTENTFRAME)[0];
                        if (iframe) {
                            iframe.src = contentOptions.url || iframe.src;
                        } else {
                            element.html(IFRAMETEMPLATE({ content: contentOptions }));
                        }
                        element.find('.' + KCONTENTFRAME).off('load' + NS).on('load' + NS, function () {
                            that.trigger(CONTENTLOAD);
                            element.show();
                        });
                    }
                } else if (contentOptions && isFunction(contentOptions)) {
                    contentOptions = contentOptions({
                        sender: this,
                        target: target
                    });
                    element.html(contentOptions || '');
                } else {
                    element.html(contentOptions);
                }
                that.angular('compile', function () {
                    return { elements: element };
                });
            },
            _ajaxRequest: function (options) {
                var that = this;
                jQuery.ajax(extend({
                    type: 'GET',
                    dataType: 'html',
                    cache: false,
                    error: function (xhr, status) {
                        kendo.ui.progress(that.content, false);
                        that.trigger(ERROR, {
                            status: status,
                            xhr: xhr
                        });
                    },
                    success: proxy(function (data) {
                        kendo.ui.progress(that.content, false);
                        that.content.html(data);
                        that.trigger(CONTENTLOAD);
                    }, that)
                }, options));
            },
            _documentKeyDown: function (e) {
                if (e.keyCode === kendo.keys.ESC) {
                    this.hide();
                }
            },
            refresh: function () {
                var that = this, popup = that.popup;
                if (popup && popup.options.anchor) {
                    that._appendContent(popup.options.anchor);
                }
            },
            hide: function () {
                if (this.popup) {
                    this.popup.close();
                }
            },
            show: function (target) {
                target = target || this.element;
                saveTitleAttributes(target);
                this._show(target);
            },
            _show: function (target) {
                var that = this, current = that.target();
                if (!that.popup) {
                    that._initPopup();
                }
                if (current && current[0] != target[0]) {
                    that.popup.close();
                    that.popup.element.kendoStop(true, true);
                }
                if (!current || current[0] != target[0]) {
                    that._appendContent(target);
                    that.popup.options.anchor = target;
                }
                that.popup.one('deactivate', function () {
                    restoreTitle(target);
                    target.removeAttr(DESCRIBEDBY);
                    this.element.removeAttr('id').attr('aria-hidden', true);
                    DOCUMENT.off('keydown' + NS, that._documentKeyDownHandler);
                });
                that.popup.open();
            },
            _initPopup: function () {
                var that = this, options = that.options, wrapper = $(kendo.template(TEMPLATE)({
                        callout: options.callout && options.position !== 'center',
                        dir: DIRCLASSES[options.position],
                        autoHide: options.autoHide
                    }));
                that.popup = new Popup(wrapper, extend({
                    activate: function () {
                        var anchor = this.options.anchor, ariaId = anchor[0].id || that.element[0].id;
                        if (ariaId) {
                            anchor.attr(DESCRIBEDBY, ariaId + ARIAIDSUFFIX);
                            this.element.attr('id', ariaId + ARIAIDSUFFIX);
                        }
                        if (options.callout) {
                            that._positionCallout();
                        }
                        this.element.removeAttr('aria-hidden');
                        DOCUMENT.on('keydown' + NS, that._documentKeyDownHandler);
                        that.trigger(SHOW);
                    },
                    close: function () {
                        that.trigger(HIDE);
                    },
                    copyAnchorStyles: false,
                    animation: options.animation
                }, POSITIONS[options.position]));
                wrapper.css({
                    width: options.width,
                    height: options.height
                });
                that.content = wrapper.find('.k-tooltip-content');
                that.arrow = wrapper.find('.k-callout');
                if (options.autoHide) {
                    wrapper.on('mouseleave' + NS, proxy(that._mouseleave, that));
                } else {
                    wrapper.on('click' + NS, '.k-tooltip-button', proxy(that._closeButtonClick, that));
                }
            },
            _closeButtonClick: function (e) {
                e.preventDefault();
                this.hide();
            },
            _mouseleave: function (e) {
                if (this.popup) {
                    var element = $(e.currentTarget), offset = element.offset(), pageX = e.pageX, pageY = e.pageY;
                    offset.right = offset.left + kendo._outerWidth(element);
                    offset.bottom = offset.top + kendo._outerHeight(element);
                    if (pageX > offset.left && pageX < offset.right && pageY > offset.top && pageY < offset.bottom) {
                        return;
                    }
                    this.popup.close();
                } else {
                    restoreTitle($(e.currentTarget));
                }
                clearTimeout(this.timeout);
            },
            _positionCallout: function () {
                var that = this, position = that.options.position, dimensions = that.dimensions, offset = dimensions.offset, popup = that.popup, anchor = popup.options.anchor, anchorOffset = $(anchor).offset(), arrowBorder = parseInt(that.arrow.css('border-top-width'), 10), elementOffset = $(popup.element).offset(), cssClass = DIRCLASSES[popup.flipped ? REVERSE[position] : position], offsetAmount = anchorOffset[offset] - elementOffset[offset] + $(anchor)[dimensions.size]() / 2 - arrowBorder;
                that.arrow.removeClass('k-callout-n k-callout-s k-callout-w k-callout-e').addClass('k-callout-' + cssClass).css(offset, offsetAmount);
            },
            target: function () {
                if (this.popup) {
                    return this.popup.options.anchor;
                }
                return null;
            },
            destroy: function () {
                var popup = this.popup;
                if (popup) {
                    popup.element.off(NS);
                    popup.destroy();
                }
                clearTimeout(this.timeout);
                this.element.off(NS);
                DOCUMENT.off('keydown' + NS, this._documentKeyDownHandler);
                Widget.fn.destroy.call(this);
            }
        });
        kendo.ui.plugin(Tooltip);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.list', [
        'kendo.data',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'list',
        name: 'List',
        category: 'framework',
        depends: [
            'data',
            'popup'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, Widget = ui.Widget, keys = kendo.keys, support = kendo.support, htmlEncode = kendo.htmlEncode, activeElement = kendo._activeElement, ObservableArray = kendo.data.ObservableArray, ID = 'id', CHANGE = 'change', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', LOADING = 'k-i-loading', HIDDENCLASS = 'k-hidden', GROUPHEADER = '.k-group-header', LABELIDPART = '_label', OPEN = 'open', CLOSE = 'close', CASCADE = 'cascade', SELECT = 'select', SELECTED = 'selected', REQUESTSTART = 'requestStart', REQUESTEND = 'requestEnd', WIDTH = 'width', extend = $.extend, proxy = $.proxy, isArray = $.isArray, browser = support.browser, isIE = browser.msie, isIE8 = isIE && browser.version < 9, quotRegExp = /"/g, alternativeNames = {
                'ComboBox': 'DropDownList',
                'DropDownList': 'ComboBox'
            };
        var List = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                var that = this, ns = that.ns, id;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                that._isSelect = element.is(SELECT);
                if (that._isSelect && that.element[0].length) {
                    if (!options.dataSource) {
                        options.dataTextField = options.dataTextField || 'text';
                        options.dataValueField = options.dataValueField || 'value';
                    }
                }
                that.ul = $('<ul unselectable="on" class="k-list k-reset"/>').attr({
                    tabIndex: -1,
                    'aria-hidden': true
                });
                that.list = $('<div class=\'k-list-container\'/>').append(that.ul).on('mousedown' + ns, proxy(that._listMousedown, that));
                id = element.attr(ID);
                if (id) {
                    that.list.attr(ID, id + '-list');
                    that.ul.attr(ID, id + '_listbox');
                }
                that._header();
                that._noData();
                that._footer();
                that._accessors();
                that._initValue();
            },
            options: {
                valuePrimitive: false,
                footerTemplate: '',
                headerTemplate: '',
                noDataTemplate: 'No data found.'
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                if (options && options.enable !== undefined) {
                    options.enabled = options.enable;
                }
                this._header();
                this._noData();
                this._footer();
                this._renderFooter();
                this._renderNoData();
            },
            focus: function () {
                this._focused.focus();
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            _listOptions: function (options) {
                var that = this;
                var currentOptions = that.options;
                var virtual = currentOptions.virtual;
                var listBoundHandler = proxy(that._listBound, that);
                virtual = typeof virtual === 'object' ? virtual : {};
                options = $.extend({
                    autoBind: false,
                    selectable: true,
                    dataSource: that.dataSource,
                    click: proxy(that._click, that),
                    change: proxy(that._listChange, that),
                    activate: proxy(that._activateItem, that),
                    deactivate: proxy(that._deactivateItem, that),
                    dataBinding: function () {
                        that.trigger('dataBinding');
                    },
                    dataBound: listBoundHandler,
                    height: currentOptions.height,
                    dataValueField: currentOptions.dataValueField,
                    dataTextField: currentOptions.dataTextField,
                    groupTemplate: currentOptions.groupTemplate,
                    fixedGroupTemplate: currentOptions.fixedGroupTemplate,
                    template: currentOptions.template
                }, options, virtual);
                if (!options.template) {
                    options.template = '#:' + kendo.expr(options.dataTextField, 'data') + '#';
                }
                if (currentOptions.$angular) {
                    options.$angular = currentOptions.$angular;
                }
                return options;
            },
            _initList: function () {
                var that = this;
                var listOptions = that._listOptions({ selectedItemChange: proxy(that._listChange, that) });
                if (!that.options.virtual) {
                    that.listView = new kendo.ui.StaticList(that.ul, listOptions);
                } else {
                    that.listView = new kendo.ui.VirtualList(that.ul, listOptions);
                }
                that.listView.bind('listBound', proxy(that._listBound, that));
                that._setListValue();
            },
            _setListValue: function (value) {
                value = value || this.options.value;
                if (value !== undefined) {
                    this.listView.value(value).done(proxy(this._updateSelectionState, this));
                }
            },
            _updateSelectionState: $.noop,
            _listMousedown: function (e) {
                if (!this.filterInput || this.filterInput[0] !== e.target) {
                    e.preventDefault();
                }
            },
            _isFilterEnabled: function () {
                var filter = this.options.filter;
                return filter && filter !== 'none';
            },
            _hideClear: function () {
                var that = this;
                if (that._clear) {
                    this._clear.addClass(HIDDENCLASS);
                }
            },
            _showClear: function () {
                var that = this;
                if (that._clear) {
                    this._clear.removeClass(HIDDENCLASS);
                }
            },
            _clearValue: function () {
                this._clearText();
                this._accessor('');
                this.listView.value([]);
                if (this._isFilterEnabled() && !this.options.enforceMinLength) {
                    this._filter({
                        word: '',
                        open: false
                    });
                }
                this._change();
            },
            _clearText: function () {
                this.text('');
            },
            _clearFilter: function () {
                if (!this.options.virtual) {
                    this.listView.bound(false);
                }
                this._filterSource();
            },
            _filterSource: function (filter, force) {
                var that = this;
                var options = that.options;
                var dataSource = that.dataSource;
                var expression = extend({}, dataSource.filter() || {});
                var resetPageSettings = filter || expression.filters && expression.filters.length && !filter;
                var removed = removeFiltersForField(expression, options.dataTextField);
                if ((filter || removed) && that.trigger('filtering', { filter: filter })) {
                    return;
                }
                var newExpression = {
                    filters: [],
                    logic: 'and'
                };
                if (isValidFilterExpr(filter)) {
                    newExpression.filters.push(filter);
                }
                if (isValidFilterExpr(expression)) {
                    if (newExpression.logic === expression.logic) {
                        newExpression.filters = newExpression.filters.concat(expression.filters);
                    } else {
                        newExpression.filters.push(expression);
                    }
                }
                if (that._cascading) {
                    this.listView.setDSFilter(newExpression);
                }
                var dataSourceState = extend({}, {
                    page: resetPageSettings ? 1 : dataSource.page(),
                    pageSize: resetPageSettings ? dataSource.options.pageSize : dataSource.pageSize(),
                    sort: dataSource.sort(),
                    filter: dataSource.filter(),
                    group: dataSource.group(),
                    aggregate: dataSource.aggregate()
                }, { filter: newExpression });
                dataSource[force ? 'read' : 'query'](dataSource._mergeState(dataSourceState));
            },
            _angularElement: function (element, action) {
                if (!element) {
                    return;
                }
                this.angular(action, function () {
                    return { elements: element };
                });
            },
            _noData: function () {
                var noData = $(this.noData);
                var template = this.options.noDataTemplate;
                this.angular('cleanup', function () {
                    return { elements: noData };
                });
                kendo.destroy(noData);
                noData.remove();
                if (!template) {
                    this.noData = null;
                    return;
                }
                this.noData = $('<div class="k-nodata" style="display:none"><div></div></div>').appendTo(this.list);
                this.noDataTemplate = typeof template !== 'function' ? kendo.template(template) : template;
            },
            _renderNoData: function () {
                var noData = this.noData;
                if (!noData) {
                    return;
                }
                this._angularElement(noData, 'cleanup');
                noData.children(':first').html(this.noDataTemplate({ instance: this }));
                this._angularElement(noData, 'compile');
            },
            _toggleNoData: function (show) {
                $(this.noData).toggle(show);
            },
            _toggleHeader: function (show) {
                var groupHeader = this.listView.content.prev(GROUPHEADER);
                groupHeader.toggle(show);
            },
            _footer: function () {
                var footer = $(this.footer);
                var template = this.options.footerTemplate;
                this._angularElement(footer, 'cleanup');
                kendo.destroy(footer);
                footer.remove();
                if (!template) {
                    this.footer = null;
                    return;
                }
                this.footer = $('<div class="k-footer"></div>').appendTo(this.list);
                this.footerTemplate = typeof template !== 'function' ? kendo.template(template) : template;
            },
            _renderFooter: function () {
                var footer = this.footer;
                if (!footer) {
                    return;
                }
                this._angularElement(footer, 'cleanup');
                footer.html(this.footerTemplate({ instance: this }));
                this._angularElement(footer, 'compile');
            },
            _header: function () {
                var header = $(this.header);
                var template = this.options.headerTemplate;
                this._angularElement(header, 'cleanup');
                kendo.destroy(header);
                header.remove();
                if (!template) {
                    this.header = null;
                    return;
                }
                var headerTemplate = typeof template !== 'function' ? kendo.template(template) : template;
                header = $(headerTemplate({}));
                this.header = header[0] ? header : null;
                this.list.prepend(header);
                this._angularElement(this.header, 'compile');
            },
            _allowOpening: function () {
                return this.options.noDataTemplate || this.dataSource.flatView().length;
            },
            _initValue: function () {
                var that = this, value = that.options.value;
                if (value !== null) {
                    that.element.val(value);
                } else {
                    value = that._accessor();
                    that.options.value = value;
                }
                that._old = value;
            },
            _ignoreCase: function () {
                var that = this, model = that.dataSource.reader.model, field;
                if (model && model.fields) {
                    field = model.fields[that.options.dataTextField];
                    if (field && field.type && field.type !== 'string') {
                        that.options.ignoreCase = false;
                    }
                }
            },
            _focus: function (candidate) {
                return this.listView.focus(candidate);
            },
            _filter: function (options) {
                var that = this;
                var widgetOptions = that.options;
                var ignoreCase = widgetOptions.ignoreCase;
                var field = widgetOptions.dataTextField;
                var expression = {
                    value: ignoreCase ? options.word.toLowerCase() : options.word,
                    field: field,
                    operator: widgetOptions.filter,
                    ignoreCase: ignoreCase
                };
                that._open = options.open;
                that._filterSource(expression);
            },
            search: function (word) {
                var options = this.options;
                word = typeof word === 'string' ? word : this._inputValue();
                clearTimeout(this._typingTimeout);
                if (!options.enforceMinLength && !word.length || word.length >= options.minLength) {
                    this._state = 'filter';
                    if (!this._isFilterEnabled()) {
                        this._searchByWord(word);
                    } else {
                        this._filter({
                            word: word,
                            open: true
                        });
                    }
                }
            },
            current: function (candidate) {
                return this._focus(candidate);
            },
            items: function () {
                return this.ul[0].children;
            },
            destroy: function () {
                var that = this;
                var ns = that.ns;
                Widget.fn.destroy.call(that);
                that._unbindDataSource();
                that.listView.destroy();
                that.list.off(ns);
                that.popup.destroy();
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
            },
            dataItem: function (index) {
                var that = this;
                if (index === undefined) {
                    return that.listView.selectedDataItems()[0];
                }
                if (typeof index !== 'number') {
                    if (that.options.virtual) {
                        return that.dataSource.getByUid($(index).data('uid'));
                    }
                    index = $(that.items()).index(index);
                }
                return that.dataSource.flatView()[index];
            },
            _activateItem: function () {
                var current = this.listView.focus();
                if (current) {
                    this._focused.add(this.filterInput).attr('aria-activedescendant', current.attr('id'));
                }
            },
            _deactivateItem: function () {
                this._focused.add(this.filterInput).removeAttr('aria-activedescendant');
            },
            _accessors: function () {
                var that = this;
                var element = that.element;
                var options = that.options;
                var getter = kendo.getter;
                var textField = element.attr(kendo.attr('text-field'));
                var valueField = element.attr(kendo.attr('value-field'));
                if (!options.dataTextField && textField) {
                    options.dataTextField = textField;
                }
                if (!options.dataValueField && valueField) {
                    options.dataValueField = valueField;
                }
                that._text = getter(options.dataTextField);
                that._value = getter(options.dataValueField);
            },
            _aria: function (id) {
                var that = this, options = that.options, element = that._focused.add(that.filterInput);
                if (options.suggest !== undefined) {
                    element.attr('aria-autocomplete', options.suggest ? 'both' : 'list');
                }
                id = id ? id + ' ' + that.ul[0].id : that.ul[0].id;
                element.attr('aria-owns', id);
                that.ul.attr('aria-live', !that._isFilterEnabled() ? 'off' : 'polite');
                that._ariaLabel();
            },
            _ariaLabel: function () {
                var that = this;
                var focusedElm = that._focused;
                var inputElm = that.element;
                var inputId = inputElm.attr('id');
                var labelElm = $('label[for=\'' + inputId + '\']');
                var ariaLabel = inputElm.attr('aria-label');
                var ariaLabelledBy = inputElm.attr('aria-labelledby');
                if (focusedElm === inputElm) {
                    return;
                }
                if (ariaLabel) {
                    focusedElm.attr('aria-label', ariaLabel);
                } else if (ariaLabelledBy) {
                    focusedElm.attr('aria-labelledby', ariaLabelledBy);
                } else if (labelElm.length) {
                    var labelId = labelElm.attr('id') || that._generateLabelId(labelElm, inputId);
                    focusedElm.attr('aria-labelledby', labelId);
                }
            },
            _generateLabelId: function (label, inputId) {
                var labelId = inputId + LABELIDPART;
                label.attr('id', labelId);
                return labelId;
            },
            _blur: function () {
                var that = this;
                that._change();
                that.close();
            },
            _change: function () {
                var that = this;
                var index = that.selectedIndex;
                var optionValue = that.options.value;
                var value = that.value();
                var trigger;
                if (that._isSelect && !that.listView.bound() && optionValue) {
                    value = optionValue;
                }
                if (value !== unifyType(that._old, typeof value)) {
                    trigger = true;
                } else if (index !== undefined && index !== that._oldIndex) {
                    trigger = true;
                }
                if (trigger) {
                    that._old = value;
                    that._oldIndex = index;
                    if (!that._typing) {
                        that.element.trigger(CHANGE);
                    }
                    that.trigger(CHANGE);
                }
                that.typing = false;
            },
            _data: function () {
                return this.dataSource.view();
            },
            _enable: function () {
                var that = this, options = that.options, disabled = that.element.is('[disabled]');
                if (options.enable !== undefined) {
                    options.enabled = options.enable;
                }
                if (!options.enabled || disabled) {
                    that.enable(false);
                } else {
                    that.readonly(that.element.is('[readonly]'));
                }
            },
            _dataValue: function (dataItem) {
                var value = this._value(dataItem);
                if (value === undefined) {
                    value = this._text(dataItem);
                }
                return value;
            },
            _offsetHeight: function () {
                var offsetHeight = 0;
                var siblings = this.listView.content.prevAll(':visible');
                siblings.each(function () {
                    var element = $(this);
                    offsetHeight += outerHeight(element);
                });
                return offsetHeight;
            },
            _height: function (length) {
                var that = this;
                var list = that.list;
                var height = that.options.height;
                var visible = that.popup.visible();
                var offsetTop;
                var popups;
                var footerHeight;
                if (length || that.options.noDataTemplate) {
                    popups = list.add(list.parent('.k-animation-container')).show();
                    if (!list.is(':visible')) {
                        popups.hide();
                        return;
                    }
                    height = that.listView.content[0].scrollHeight > height ? height : 'auto';
                    popups.height(height);
                    if (height !== 'auto') {
                        offsetTop = that._offsetHeight();
                        footerHeight = outerHeight($(that.footer)) || 0;
                        height = height - offsetTop - footerHeight;
                    }
                    that.listView.content.height(height);
                    if (!visible) {
                        popups.hide();
                    }
                }
                return height;
            },
            _adjustListWidth: function () {
                var list = this.list, width = list[0].style.width, wrapper = this.wrapper, computedStyle, computedWidth;
                if (!list.data(WIDTH) && width) {
                    return;
                }
                computedStyle = window.getComputedStyle ? window.getComputedStyle(wrapper[0], null) : 0;
                computedWidth = parseFloat(computedStyle && computedStyle.width) || outerWidth(wrapper);
                if (computedStyle && browser.msie) {
                    computedWidth += parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
                }
                if (list.css('box-sizing') !== 'border-box') {
                    width = computedWidth - (outerWidth(list) - list.width());
                } else {
                    width = computedWidth;
                }
                list.css({
                    fontFamily: wrapper.css('font-family'),
                    width: this.options.autoWidth ? 'auto' : width,
                    minWidth: width
                }).data(WIDTH, width);
                return true;
            },
            _openHandler: function (e) {
                this._adjustListWidth();
                if (this.trigger(OPEN)) {
                    e.preventDefault();
                } else {
                    this._focused.attr('aria-expanded', true);
                    this.ul.attr('aria-hidden', false);
                }
            },
            _closeHandler: function (e) {
                if (this.trigger(CLOSE)) {
                    e.preventDefault();
                } else {
                    this._focused.attr('aria-expanded', false);
                    this.ul.attr('aria-hidden', true);
                }
            },
            _focusItem: function () {
                var listView = this.listView;
                var noFocusedItem = !listView.focus();
                var index = last(listView.select());
                if (index === undefined && this.options.highlightFirst && noFocusedItem) {
                    index = 0;
                }
                if (index !== undefined) {
                    listView.focus(index);
                } else if (noFocusedItem) {
                    listView.scrollToIndex(0);
                }
            },
            _calculateGroupPadding: function (height) {
                var li = this.ul.children('.k-first:first');
                var groupHeader = this.listView.content.prev(GROUPHEADER);
                var padding = 0;
                if (groupHeader[0] && groupHeader[0].style.display !== 'none') {
                    if (height !== 'auto') {
                        padding = kendo.support.scrollbar();
                    }
                    padding += parseFloat(li.css('border-right-width'), 10) + parseFloat(li.children('.k-group').css('padding-right'), 10);
                    groupHeader.css('padding-right', padding);
                }
            },
            _calculatePopupHeight: function (force) {
                var height = this._height(this.dataSource.flatView().length || force);
                this._calculateGroupPadding(height);
            },
            _resizePopup: function (force) {
                if (this.options.virtual) {
                    return;
                }
                if (!this.popup.element.is(':visible')) {
                    this.popup.one('open', function (force) {
                        return proxy(function () {
                            this._calculatePopupHeight(force);
                        }, this);
                    }.call(this, force));
                } else {
                    this._calculatePopupHeight(force);
                }
            },
            _popup: function () {
                var that = this;
                that.popup = new ui.Popup(that.list, extend({}, that.options.popup, {
                    anchor: that.wrapper,
                    open: proxy(that._openHandler, that),
                    close: proxy(that._closeHandler, that),
                    animation: that.options.animation,
                    isRtl: support.isRtl(that.wrapper)
                }));
            },
            _makeUnselectable: function () {
                if (isIE8) {
                    this.list.find('*').not('.k-textbox').attr('unselectable', 'on');
                }
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _toggle: function (open, preventFocus) {
                var that = this;
                var touchEnabled = support.mobileOS && (support.touch || support.MSPointers || support.pointers);
                open = open !== undefined ? open : !that.popup.visible();
                if (!preventFocus && !touchEnabled && that._focused[0] !== activeElement()) {
                    that._prevent = true;
                    that._focused.focus();
                    that._prevent = false;
                }
                that[open ? OPEN : CLOSE]();
            },
            _triggerCascade: function () {
                var that = this;
                if (!that._cascadeTriggered || that._old !== that.value() || that._oldIndex !== that.selectedIndex) {
                    that._cascadeTriggered = true;
                    that.trigger(CASCADE, { userTriggered: that._userTriggered });
                }
            },
            _triggerChange: function () {
                if (this._valueBeforeCascade !== this.value()) {
                    this.trigger(CHANGE);
                }
            },
            _unbindDataSource: function () {
                var that = this;
                that.dataSource.unbind(REQUESTSTART, that._requestStartHandler).unbind(REQUESTEND, that._requestEndHandler).unbind('error', that._errorHandler);
            },
            requireValueMapper: function (options, value) {
                var hasValue = (options.value instanceof Array ? options.value.length : options.value) || (value instanceof Array ? value.length : value);
                if (hasValue && options.virtual && typeof options.virtual.valueMapper !== 'function') {
                    throw new Error('ValueMapper is not provided while the value is being set. See http://docs.telerik.com/kendo-ui/controls/editors/combobox/virtualization#the-valuemapper-function');
                }
            }
        });
        function unifyType(value, type) {
            if (value !== undefined && value !== '' && value !== null) {
                if (type === 'boolean') {
                    value = Boolean(value);
                } else if (type === 'number') {
                    value = Number(value);
                } else if (type === 'string') {
                    value = value.toString();
                }
            }
            return value;
        }
        extend(List, {
            inArray: function (node, parentNode) {
                var idx, length, siblings = parentNode.children;
                if (!node || node.parentNode !== parentNode) {
                    return -1;
                }
                for (idx = 0, length = siblings.length; idx < length; idx++) {
                    if (node === siblings[idx]) {
                        return idx;
                    }
                }
                return -1;
            },
            unifyType: unifyType
        });
        kendo.ui.List = List;
        ui.Select = List.extend({
            init: function (element, options) {
                List.fn.init.call(this, element, options);
                this._initial = this.element.val();
            },
            setDataSource: function (dataSource) {
                var that = this;
                var parent;
                that.options.dataSource = dataSource;
                that._dataSource();
                if (that.listView.bound()) {
                    that._initialIndex = null;
                }
                that.listView.setDataSource(that.dataSource);
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
                parent = that._parentWidget();
                if (parent) {
                    that._cascadeSelect(parent);
                }
            },
            close: function () {
                this.popup.close();
            },
            select: function (candidate) {
                var that = this;
                if (candidate === undefined) {
                    return that.selectedIndex;
                } else {
                    return that._select(candidate).done(function () {
                        that._old = that._accessor();
                        that._oldIndex = that.selectedIndex;
                    });
                }
            },
            _accessor: function (value, idx) {
                return this[this._isSelect ? '_accessorSelect' : '_accessorInput'](value, idx);
            },
            _accessorInput: function (value) {
                var element = this.element[0];
                if (value === undefined) {
                    return element.value;
                } else {
                    if (value === null) {
                        value = '';
                    }
                    element.value = value;
                }
            },
            _accessorSelect: function (value, idx) {
                var element = this.element[0];
                var hasValue;
                if (value === undefined) {
                    return getSelectedOption(element).value || '';
                }
                getSelectedOption(element).selected = false;
                if (idx === undefined) {
                    idx = -1;
                }
                hasValue = value !== null && value !== '';
                if (hasValue && idx == -1) {
                    this._custom(value);
                } else {
                    if (value) {
                        element.value = value;
                    } else {
                        element.selectedIndex = idx;
                    }
                }
            },
            _custom: function (value) {
                var that = this;
                var element = that.element;
                var custom = that._customOption;
                if (!custom) {
                    custom = $('<option/>');
                    that._customOption = custom;
                    element.append(custom);
                }
                custom.text(value);
                custom[0].selected = true;
            },
            _hideBusy: function () {
                var that = this;
                clearTimeout(that._busy);
                that._arrowIcon.removeClass(LOADING);
                that._focused.attr('aria-busy', false);
                that._busy = null;
                that._showClear();
            },
            _showBusy: function () {
                var that = this;
                that._request = true;
                if (that._busy) {
                    return;
                }
                that._busy = setTimeout(function () {
                    if (that._arrowIcon) {
                        that._focused.attr('aria-busy', true);
                        that._arrowIcon.addClass(LOADING);
                        that._hideClear();
                    }
                }, 100);
            },
            _requestEnd: function () {
                this._request = false;
                this._hideBusy();
            },
            _dataSource: function () {
                var that = this, element = that.element, options = that.options, dataSource = options.dataSource || {}, idx;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                if (that._isSelect) {
                    idx = element[0].selectedIndex;
                    if (idx > -1) {
                        options.index = idx;
                    }
                    dataSource.select = element;
                    dataSource.fields = [
                        { field: options.dataTextField },
                        { field: options.dataValueField }
                    ];
                }
                if (that.dataSource) {
                    that._unbindDataSource();
                } else {
                    that._requestStartHandler = proxy(that._showBusy, that);
                    that._requestEndHandler = proxy(that._requestEnd, that);
                    that._errorHandler = proxy(that._hideBusy, that);
                }
                that.dataSource = kendo.data.DataSource.create(dataSource).bind(REQUESTSTART, that._requestStartHandler).bind(REQUESTEND, that._requestEndHandler).bind('error', that._errorHandler);
            },
            _firstItem: function () {
                this.listView.focusFirst();
            },
            _lastItem: function () {
                this.listView.focusLast();
            },
            _nextItem: function () {
                this.listView.focusNext();
            },
            _prevItem: function () {
                this.listView.focusPrev();
            },
            _move: function (e) {
                var that = this;
                var listView = that.listView;
                var key = e.keyCode;
                var down = key === keys.DOWN;
                var dataItem;
                var pressed;
                var current;
                if (key === keys.UP || down) {
                    if (e.altKey) {
                        that.toggle(down);
                    } else {
                        if (!listView.bound()) {
                            if (!that._fetch) {
                                that.dataSource.one(CHANGE, function () {
                                    that._fetch = false;
                                    that._move(e);
                                });
                                that._fetch = true;
                                that._filterSource();
                            }
                            e.preventDefault();
                            return true;
                        }
                        current = that._focus();
                        if (!that._fetch && (!current || current.hasClass('k-state-selected'))) {
                            if (down) {
                                that._nextItem();
                                if (!that._focus()) {
                                    that._lastItem();
                                }
                            } else {
                                that._prevItem();
                                if (!that._focus()) {
                                    that._firstItem();
                                }
                            }
                        }
                        dataItem = listView.dataItemByIndex(listView.getElementIndex(that._focus()));
                        if (that.trigger(SELECT, {
                                dataItem: dataItem,
                                item: that._focus()
                            })) {
                            that._focus(current);
                            return;
                        }
                        that._select(that._focus(), true).done(function () {
                            if (!that.popup.visible()) {
                                that._blur();
                            }
                        });
                    }
                    e.preventDefault();
                    pressed = true;
                } else if (key === keys.ENTER || key === keys.TAB) {
                    if (that.popup.visible()) {
                        e.preventDefault();
                    }
                    current = that._focus();
                    dataItem = that.dataItem();
                    if (!that.popup.visible() && (!dataItem || that.text() !== that._text(dataItem))) {
                        current = null;
                    }
                    var activeFilter = that.filterInput && that.filterInput[0] === activeElement();
                    if (current) {
                        dataItem = listView.dataItemByIndex(listView.getElementIndex(current));
                        var shouldTrigger = true;
                        if (dataItem) {
                            shouldTrigger = that._value(dataItem) !== List.unifyType(that.value(), typeof that._value(dataItem));
                        }
                        if (shouldTrigger && that.trigger(SELECT, {
                                dataItem: dataItem,
                                item: current
                            })) {
                            return;
                        }
                        that._select(current);
                    } else if (that.input) {
                        that._accessor(that.input.val());
                        that.listView.value(that.input.val());
                    }
                    if (that._focusElement) {
                        that._focusElement(that.wrapper);
                    }
                    if (activeFilter && key === keys.TAB) {
                        that.wrapper.focusout();
                    } else {
                        that._blur();
                    }
                    that.close();
                    pressed = true;
                } else if (key === keys.ESC) {
                    if (that.popup.visible()) {
                        e.preventDefault();
                    }
                    that.close();
                    pressed = true;
                } else if (that.popup.visible() && (key === keys.PAGEDOWN || key === keys.PAGEUP)) {
                    e.preventDefault();
                    var direction = key === keys.PAGEDOWN ? 1 : -1;
                    listView.scrollWith(direction * listView.screenHeight());
                    pressed = true;
                }
                return pressed;
            },
            _fetchData: function () {
                var that = this;
                var hasItems = !!that.dataSource.view().length;
                if (that._request || that.options.cascadeFrom) {
                    return;
                }
                if (!that.listView.bound() && !that._fetch && !hasItems) {
                    that._fetch = true;
                    that.dataSource.fetch().done(function () {
                        that._fetch = false;
                    });
                }
            },
            _options: function (data, optionLabel, value) {
                var that = this, element = that.element, htmlElement = element[0], length = data.length, options = '', option, dataItem, dataText, dataValue, idx = 0;
                if (optionLabel) {
                    options = optionLabel;
                }
                for (; idx < length; idx++) {
                    option = '<option';
                    dataItem = data[idx];
                    dataText = that._text(dataItem);
                    dataValue = that._value(dataItem);
                    if (dataValue !== undefined) {
                        dataValue += '';
                        if (dataValue.indexOf('"') !== -1) {
                            dataValue = dataValue.replace(quotRegExp, '&quot;');
                        }
                        option += ' value="' + dataValue + '"';
                    }
                    option += '>';
                    if (dataText !== undefined) {
                        option += htmlEncode(dataText);
                    }
                    option += '</option>';
                    options += option;
                }
                element.html(options);
                if (value !== undefined) {
                    htmlElement.value = value;
                    if (htmlElement.value && !value) {
                        htmlElement.selectedIndex = -1;
                    }
                }
                if (htmlElement.selectedIndex !== -1) {
                    option = getSelectedOption(htmlElement);
                    if (option) {
                        option.setAttribute(SELECTED, SELECTED);
                    }
                }
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(that._initial);
                        });
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _parentWidget: function () {
                var name = this.options.name;
                if (!this.options.cascadeFrom) {
                    return;
                }
                var parentElement = $('#' + this.options.cascadeFrom);
                var parent = parentElement.data('kendo' + name);
                if (!parent) {
                    parent = parentElement.data('kendo' + alternativeNames[name]);
                }
                return parent;
            },
            _cascade: function () {
                var that = this;
                var options = that.options;
                var cascade = options.cascadeFrom;
                var parent;
                if (cascade) {
                    parent = that._parentWidget();
                    if (!parent) {
                        return;
                    }
                    that._cascadeHandlerProxy = proxy(that._cascadeHandler, that);
                    that._cascadeFilterRequests = [];
                    options.autoBind = false;
                    parent.bind('set', function () {
                        that.one('set', function (e) {
                            that._selectedValue = e.value;
                        });
                    });
                    parent.first(CASCADE, that._cascadeHandlerProxy);
                    if (parent.listView.bound()) {
                        that._toggleCascadeOnFocus();
                        that._cascadeSelect(parent);
                    } else {
                        parent.one('dataBound', function () {
                            that._toggleCascadeOnFocus();
                        });
                        if (!parent.value()) {
                            that.enable(false);
                        }
                    }
                }
            },
            _toggleCascadeOnFocus: function () {
                var that = this;
                var parent = that._parentWidget();
                var focusout = isIE ? 'blur' : 'focusout';
                parent._focused.add(parent.filterInput).bind('focus', function () {
                    parent.unbind(CASCADE, that._cascadeHandlerProxy);
                    parent.first(CHANGE, that._cascadeHandlerProxy);
                });
                parent._focused.add(parent.filterInput).bind(focusout, function () {
                    parent.unbind(CHANGE, that._cascadeHandlerProxy);
                    parent.first(CASCADE, that._cascadeHandlerProxy);
                });
            },
            _cascadeHandler: function (e) {
                var parent = this._parentWidget();
                var valueBeforeCascade = this.value();
                this._userTriggered = e.userTriggered;
                if (this.listView.bound()) {
                    this._clearSelection(parent, true);
                }
                this._cascadeSelect(parent, valueBeforeCascade);
            },
            _cascadeChange: function (parent) {
                var that = this;
                var value = that._accessor() || that._selectedValue;
                if (!that._cascadeFilterRequests.length) {
                    that._selectedValue = null;
                }
                if (that._userTriggered) {
                    that._clearSelection(parent, true);
                } else if (value) {
                    if (value !== that.listView.value()[0]) {
                        that.value(value);
                    }
                    if (!that.dataSource.view()[0] || that.selectedIndex === -1) {
                        that._clearSelection(parent, true);
                    }
                } else if (that.dataSource.flatView().length) {
                    that.select(that.options.index);
                }
                that.enable();
                that._triggerCascade();
                that._triggerChange();
                that._userTriggered = false;
            },
            _cascadeSelect: function (parent, valueBeforeCascade) {
                var that = this;
                var dataItem = parent.dataItem();
                var filterValue = dataItem ? parent._value(dataItem) : null;
                var valueField = that.options.cascadeFromField || parent.options.dataValueField;
                var expressions;
                that._valueBeforeCascade = valueBeforeCascade !== undefined ? valueBeforeCascade : that.value();
                if (filterValue || filterValue === 0) {
                    expressions = that.dataSource.filter() || {};
                    removeFiltersForField(expressions, valueField);
                    var handler = function () {
                        var currentHandler = that._cascadeFilterRequests.shift();
                        if (currentHandler) {
                            that.unbind('dataBound', currentHandler);
                        }
                        currentHandler = that._cascadeFilterRequests[0];
                        if (currentHandler) {
                            that.first('dataBound', currentHandler);
                        }
                        that._cascadeChange(parent);
                    };
                    that._cascadeFilterRequests.push(handler);
                    if (that._cascadeFilterRequests.length === 1) {
                        that.first('dataBound', handler);
                    }
                    that._cascading = true;
                    that._filterSource({
                        field: valueField,
                        operator: 'eq',
                        value: filterValue
                    });
                    that._cascading = false;
                } else {
                    that.enable(false);
                    that._clearSelection(parent);
                    that._triggerCascade();
                    that._triggerChange();
                    that._userTriggered = false;
                }
            }
        });
        var STATIC_LIST_NS = '.StaticList';
        var StaticList = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.element.attr('role', 'listbox').on('click' + STATIC_LIST_NS, 'li', proxy(this._click, this)).on('mouseenter' + STATIC_LIST_NS, 'li', function () {
                    $(this).addClass(HOVER);
                }).on('mouseleave' + STATIC_LIST_NS, 'li', function () {
                    $(this).removeClass(HOVER);
                });
                this.content = this.element.wrap('<div class=\'k-list-scroller\' unselectable=\'on\'></div>').parent();
                this.header = this.content.before('<div class="k-group-header" style="display:none"></div>').prev();
                this.bound(false);
                this._optionID = kendo.guid();
                this._selectedIndices = [];
                this._view = [];
                this._dataItems = [];
                this._values = [];
                var value = this.options.value;
                if (value) {
                    this._values = $.isArray(value) ? value.slice(0) : [value];
                }
                this._getter();
                this._templates();
                this.setDataSource(this.options.dataSource);
                this._onScroll = proxy(function () {
                    var that = this;
                    clearTimeout(that._scrollId);
                    that._scrollId = setTimeout(function () {
                        that._renderHeader();
                    }, 50);
                }, this);
            },
            options: {
                name: 'StaticList',
                dataValueField: null,
                valuePrimitive: false,
                selectable: true,
                template: null,
                groupTemplate: null,
                fixedGroupTemplate: null
            },
            events: [
                'click',
                CHANGE,
                'activate',
                'deactivate',
                'dataBinding',
                'dataBound',
                'selectedItemChange'
            ],
            setDataSource: function (source) {
                var that = this;
                var dataSource = source || {};
                var value;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                dataSource = kendo.data.DataSource.create(dataSource);
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    value = that.value();
                    that.value([]);
                    that.bound(false);
                    that.value(value);
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                }
                that.setDSFilter(dataSource.filter());
                that.dataSource = dataSource.bind(CHANGE, that._refreshHandler);
                that._fixedHeader();
            },
            skip: function () {
                return this.dataSource.skip();
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._getter();
                this._templates();
                this._render();
            },
            destroy: function () {
                this.element.off(STATIC_LIST_NS);
                if (this._refreshHandler) {
                    this.dataSource.unbind(CHANGE, this._refreshHandler);
                }
                clearTimeout(this._scrollId);
                Widget.fn.destroy.call(this);
            },
            dataItemByIndex: function (index) {
                return this.dataSource.flatView()[index];
            },
            screenHeight: function () {
                return this.content[0].clientHeight;
            },
            scrollToIndex: function (index) {
                var item = this.element[0].children[index];
                if (item) {
                    this.scroll(item);
                }
            },
            scrollWith: function (value) {
                this.content.scrollTop(this.content.scrollTop() + value);
            },
            scroll: function (item) {
                if (!item) {
                    return;
                }
                if (item[0]) {
                    item = item[0];
                }
                var content = this.content[0], itemOffsetTop = item.offsetTop, itemOffsetHeight = item.offsetHeight, contentScrollTop = content.scrollTop, contentOffsetHeight = content.clientHeight, bottomDistance = itemOffsetTop + itemOffsetHeight;
                if (contentScrollTop > itemOffsetTop) {
                    contentScrollTop = itemOffsetTop;
                } else if (bottomDistance > contentScrollTop + contentOffsetHeight) {
                    contentScrollTop = bottomDistance - contentOffsetHeight;
                }
                content.scrollTop = contentScrollTop;
            },
            selectedDataItems: function (dataItems) {
                if (dataItems === undefined) {
                    return this._dataItems.slice();
                }
                this._dataItems = dataItems;
                this._values = this._getValues(dataItems);
            },
            _getValues: function (dataItems) {
                var getter = this._valueGetter;
                return $.map(dataItems, function (dataItem) {
                    return getter(dataItem);
                });
            },
            focusNext: function () {
                var current = this.focus();
                if (!current) {
                    current = 0;
                } else {
                    current = current.next();
                }
                this.focus(current);
            },
            focusPrev: function () {
                var current = this.focus();
                if (!current) {
                    current = this.element[0].children.length - 1;
                } else {
                    current = current.prev();
                }
                this.focus(current);
            },
            focusFirst: function () {
                this.focus(this.element[0].children[0]);
            },
            focusLast: function () {
                this.focus(last(this.element[0].children));
            },
            focus: function (candidate) {
                var that = this;
                var id = that._optionID;
                var hasCandidate;
                if (candidate === undefined) {
                    return that._current;
                }
                candidate = last(that._get(candidate));
                candidate = $(this.element[0].children[candidate]);
                if (that._current) {
                    that._current.removeClass(FOCUSED).removeAttr('aria-selected').removeAttr(ID);
                    that.trigger('deactivate');
                }
                hasCandidate = !!candidate[0];
                if (hasCandidate) {
                    candidate.addClass(FOCUSED);
                    that.scroll(candidate);
                    candidate.attr('id', id);
                }
                that._current = hasCandidate ? candidate : null;
                that.trigger('activate');
            },
            focusIndex: function () {
                return this.focus() ? this.focus().index() : undefined;
            },
            skipUpdate: function (skipUpdate) {
                this._skipUpdate = skipUpdate;
            },
            select: function (indices) {
                var that = this;
                var selectable = that.options.selectable;
                var singleSelection = selectable !== 'multiple' && selectable !== false;
                var selectedIndices = that._selectedIndices;
                var added = [];
                var removed = [];
                var result;
                if (indices === undefined) {
                    return selectedIndices.slice();
                }
                indices = that._get(indices);
                if (indices.length === 1 && indices[0] === -1) {
                    indices = [];
                }
                var deferred = $.Deferred().resolve();
                var filtered = that.isFiltered();
                if (filtered && !singleSelection && that._deselectFiltered(indices)) {
                    return deferred;
                }
                if (singleSelection && !filtered && $.inArray(last(indices), selectedIndices) !== -1) {
                    if (that._dataItems.length && that._view.length) {
                        that._dataItems = [that._view[selectedIndices[0]].item];
                    }
                    return deferred;
                }
                result = that._deselect(indices);
                removed = result.removed;
                indices = result.indices;
                if (indices.length) {
                    if (singleSelection) {
                        indices = [last(indices)];
                    }
                    added = that._select(indices);
                }
                if (added.length || removed.length) {
                    that._valueComparer = null;
                    that.trigger(CHANGE, {
                        added: added,
                        removed: removed
                    });
                }
                return deferred;
            },
            removeAt: function (position) {
                this._selectedIndices.splice(position, 1);
                this._values.splice(position, 1);
                this._valueComparer = null;
                return {
                    position: position,
                    dataItem: this._dataItems.splice(position, 1)[0]
                };
            },
            setValue: function (value) {
                value = $.isArray(value) || value instanceof ObservableArray ? value.slice(0) : [value];
                this._values = value;
                this._valueComparer = null;
            },
            value: function (value) {
                var that = this;
                var deferred = that._valueDeferred;
                var indices;
                if (value === undefined) {
                    return that._values.slice();
                }
                that.setValue(value);
                if (!deferred || deferred.state() === 'resolved') {
                    that._valueDeferred = deferred = $.Deferred();
                }
                if (that.bound()) {
                    indices = that._valueIndices(that._values);
                    if (that.options.selectable === 'multiple') {
                        that.select(-1);
                    }
                    that.select(indices);
                    deferred.resolve();
                }
                that._skipUpdate = false;
                return deferred;
            },
            items: function () {
                return this.element.children('.k-item');
            },
            _click: function (e) {
                if (!e.isDefaultPrevented()) {
                    if (!this.trigger('click', { item: $(e.currentTarget) })) {
                        this.select(e.currentTarget);
                    }
                }
            },
            _valueExpr: function (type, values) {
                var that = this;
                var idx = 0;
                var body;
                var comparer;
                var normalized = [];
                if (!that._valueComparer || that._valueType !== type) {
                    that._valueType = type;
                    for (; idx < values.length; idx++) {
                        normalized.push(unifyType(values[idx], type));
                    }
                    body = 'for (var idx = 0; idx < ' + normalized.length + '; idx++) {' + ' if (current === values[idx]) {' + '   return idx;' + ' }' + '} ' + 'return -1;';
                    comparer = new Function('current', 'values', body);
                    that._valueComparer = function (current) {
                        return comparer(current, normalized);
                    };
                }
                return that._valueComparer;
            },
            _dataItemPosition: function (dataItem, values) {
                var value = this._valueGetter(dataItem);
                var valueExpr = this._valueExpr(typeof value, values);
                return valueExpr(value);
            },
            _getter: function () {
                this._valueGetter = kendo.getter(this.options.dataValueField);
            },
            _deselect: function (indices) {
                var that = this;
                var children = that.element[0].children;
                var selectable = that.options.selectable;
                var selectedIndices = that._selectedIndices;
                var dataItems = that._dataItems;
                var values = that._values;
                var removed = [];
                var i = 0;
                var j;
                var index, selectedIndex;
                var removedIndices = 0;
                indices = indices.slice();
                if (selectable === true || !indices.length) {
                    for (; i < selectedIndices.length; i++) {
                        $(children[selectedIndices[i]]).removeClass('k-state-selected');
                        removed.push({
                            position: i,
                            dataItem: dataItems[i]
                        });
                    }
                    that._values = [];
                    that._dataItems = [];
                    that._selectedIndices = [];
                } else if (selectable === 'multiple') {
                    for (; i < indices.length; i++) {
                        index = indices[i];
                        if (!$(children[index]).hasClass('k-state-selected')) {
                            continue;
                        }
                        for (j = 0; j < selectedIndices.length; j++) {
                            selectedIndex = selectedIndices[j];
                            if (selectedIndex === index) {
                                $(children[selectedIndex]).removeClass('k-state-selected');
                                removed.push({
                                    position: j + removedIndices,
                                    dataItem: dataItems.splice(j, 1)[0]
                                });
                                selectedIndices.splice(j, 1);
                                indices.splice(i, 1);
                                values.splice(j, 1);
                                removedIndices += 1;
                                i -= 1;
                                j -= 1;
                                break;
                            }
                        }
                    }
                }
                return {
                    indices: indices,
                    removed: removed
                };
            },
            _deselectFiltered: function (indices) {
                var children = this.element[0].children;
                var dataItem, index, position;
                var removed = [];
                var idx = 0;
                for (; idx < indices.length; idx++) {
                    index = indices[idx];
                    dataItem = this._view[index].item;
                    position = this._dataItemPosition(dataItem, this._values);
                    if (position > -1) {
                        removed.push(this.removeAt(position));
                        $(children[index]).removeClass('k-state-selected');
                    }
                }
                if (removed.length) {
                    this.trigger(CHANGE, {
                        added: [],
                        removed: removed
                    });
                    return true;
                }
                return false;
            },
            _select: function (indices) {
                var that = this;
                var children = that.element[0].children;
                var data = that._view;
                var dataItem, index;
                var added = [];
                var idx = 0;
                if (last(indices) !== -1) {
                    that.focus(indices);
                }
                for (; idx < indices.length; idx++) {
                    index = indices[idx];
                    dataItem = data[index];
                    if (index === -1 || !dataItem) {
                        continue;
                    }
                    dataItem = dataItem.item;
                    that._selectedIndices.push(index);
                    that._dataItems.push(dataItem);
                    that._values.push(that._valueGetter(dataItem));
                    $(children[index]).addClass('k-state-selected').attr('aria-selected', true);
                    added.push({ dataItem: dataItem });
                }
                return added;
            },
            getElementIndex: function (element) {
                return $(element).data('offset-index');
            },
            _get: function (candidate) {
                if (typeof candidate === 'number') {
                    candidate = [candidate];
                } else if (!isArray(candidate)) {
                    candidate = this.getElementIndex(candidate);
                    candidate = [candidate !== undefined ? candidate : -1];
                }
                return candidate;
            },
            _template: function () {
                var that = this;
                var options = that.options;
                var template = options.template;
                if (!template) {
                    template = kendo.template('<li tabindex="-1" role="option" unselectable="on" class="k-item">${' + kendo.expr(options.dataTextField, 'data') + '}</li>', { useWithBlock: false });
                } else {
                    template = kendo.template(template);
                    template = function (data) {
                        return '<li tabindex="-1" role="option" unselectable="on" class="k-item">' + template(data) + '</li>';
                    };
                }
                return template;
            },
            _templates: function () {
                var template;
                var options = this.options;
                var templates = {
                    template: options.template,
                    groupTemplate: options.groupTemplate,
                    fixedGroupTemplate: options.fixedGroupTemplate
                };
                for (var key in templates) {
                    template = templates[key];
                    if (template && typeof template !== 'function') {
                        templates[key] = kendo.template(template);
                    }
                }
                this.templates = templates;
            },
            _normalizeIndices: function (indices) {
                var newIndices = [];
                var idx = 0;
                for (; idx < indices.length; idx++) {
                    if (indices[idx] !== undefined) {
                        newIndices.push(indices[idx]);
                    }
                }
                return newIndices;
            },
            _valueIndices: function (values, indices) {
                var data = this._view;
                var idx = 0;
                var index;
                indices = indices ? indices.slice() : [];
                if (!values.length) {
                    return [];
                }
                for (; idx < data.length; idx++) {
                    index = this._dataItemPosition(data[idx].item, values);
                    if (index !== -1) {
                        indices[index] = idx;
                    }
                }
                return this._normalizeIndices(indices);
            },
            _firstVisibleItem: function () {
                var element = this.element[0];
                var content = this.content[0];
                var scrollTop = content.scrollTop;
                var itemHeight = $(element.children[0]).height();
                var itemIndex = Math.floor(scrollTop / itemHeight) || 0;
                var item = element.children[itemIndex] || element.lastChild;
                var forward = item.offsetTop < scrollTop;
                while (item) {
                    if (forward) {
                        if (item.offsetTop + itemHeight > scrollTop || !item.nextSibling) {
                            break;
                        }
                        item = item.nextSibling;
                    } else {
                        if (item.offsetTop <= scrollTop || !item.previousSibling) {
                            break;
                        }
                        item = item.previousSibling;
                    }
                }
                return this._view[$(item).data('offset-index')];
            },
            _fixedHeader: function () {
                if (this.isGrouped() && this.templates.fixedGroupTemplate) {
                    this.header.show();
                    this.content.scroll(this._onScroll);
                } else {
                    this.header.hide();
                    this.content.off('scroll', this._onScroll);
                }
            },
            _renderHeader: function () {
                var template = this.templates.fixedGroupTemplate;
                if (!template) {
                    return;
                }
                var visibleItem = this._firstVisibleItem();
                if (visibleItem) {
                    this.header.html(template(visibleItem.group));
                }
            },
            _renderItem: function (context) {
                var item = '<li tabindex="-1" role="option" unselectable="on" class="k-item';
                var dataItem = context.item;
                var notFirstItem = context.index !== 0;
                var selected = context.selected;
                if (notFirstItem && context.newGroup) {
                    item += ' k-first';
                }
                if (selected) {
                    item += ' k-state-selected';
                }
                item += '"' + (selected ? ' aria-selected="true"' : '') + ' data-offset-index="' + context.index + '">';
                item += this.templates.template(dataItem);
                if (notFirstItem && context.newGroup) {
                    item += '<div class="k-group">' + this.templates.groupTemplate(context.group) + '</div>';
                }
                return item + '</li>';
            },
            _render: function () {
                var html = '';
                var i = 0;
                var idx = 0;
                var context;
                var dataContext = [];
                var view = this.dataSource.view();
                var values = this.value();
                var group, newGroup, j;
                var isGrouped = this.isGrouped();
                if (isGrouped) {
                    for (i = 0; i < view.length; i++) {
                        group = view[i];
                        newGroup = true;
                        for (j = 0; j < group.items.length; j++) {
                            context = {
                                selected: this._selected(group.items[j], values),
                                item: group.items[j],
                                group: group.value,
                                newGroup: newGroup,
                                index: idx
                            };
                            dataContext[idx] = context;
                            idx += 1;
                            html += this._renderItem(context);
                            newGroup = false;
                        }
                    }
                } else {
                    for (i = 0; i < view.length; i++) {
                        context = {
                            selected: this._selected(view[i], values),
                            item: view[i],
                            index: i
                        };
                        dataContext[i] = context;
                        html += this._renderItem(context);
                    }
                }
                this._view = dataContext;
                this.element[0].innerHTML = html;
                if (isGrouped && dataContext.length) {
                    this._renderHeader();
                }
            },
            _selected: function (dataItem, values) {
                var select = !this.isFiltered() || this.options.selectable === 'multiple';
                return select && this._dataItemPosition(dataItem, values) !== -1;
            },
            setDSFilter: function (filter) {
                this._lastDSFilter = extend({}, filter);
            },
            isFiltered: function () {
                if (!this._lastDSFilter) {
                    this.setDSFilter(this.dataSource.filter());
                }
                return !kendo.data.Query.compareFilters(this.dataSource.filter(), this._lastDSFilter);
            },
            refresh: function (e) {
                var that = this;
                var action = e && e.action;
                var skipUpdateOnBind = that.options.skipUpdateOnBind;
                var isItemChange = action === 'itemchange';
                var result;
                that.trigger('dataBinding');
                that._angularItems('cleanup');
                that._fixedHeader();
                that._render();
                that.bound(true);
                if (isItemChange || action === 'remove') {
                    result = mapChangedItems(that._dataItems, e.items);
                    if (result.changed.length) {
                        if (isItemChange) {
                            that.trigger('selectedItemChange', { items: result.changed });
                        } else {
                            that.value(that._getValues(result.unchanged));
                        }
                    }
                } else if (that.isFiltered() || that._skipUpdate) {
                    that.focus(0);
                    if (that._skipUpdate) {
                        that._skipUpdate = false;
                        that._selectedIndices = that._valueIndices(that._values, that._selectedIndices);
                    }
                } else if (!skipUpdateOnBind && (!action || action === 'add')) {
                    that.value(that._values);
                }
                if (that._valueDeferred) {
                    that._valueDeferred.resolve();
                }
                that._angularItems('compile');
                that.trigger('dataBound');
            },
            bound: function (bound) {
                if (bound === undefined) {
                    return this._bound;
                }
                this._bound = bound;
            },
            isGrouped: function () {
                return (this.dataSource.group() || []).length;
            }
        });
        ui.plugin(StaticList);
        function last(list) {
            return list[list.length - 1];
        }
        function getSelectedOption(select) {
            var index = select.selectedIndex;
            return index > -1 ? select.options[index] : {};
        }
        function mapChangedItems(selected, itemsToMatch) {
            var itemsLength = itemsToMatch.length;
            var selectedLength = selected.length;
            var dataItem;
            var found;
            var i, j;
            var changed = [];
            var unchanged = [];
            if (selectedLength) {
                for (i = 0; i < selectedLength; i++) {
                    dataItem = selected[i];
                    found = false;
                    for (j = 0; j < itemsLength; j++) {
                        if (dataItem === itemsToMatch[j]) {
                            found = true;
                            changed.push({
                                index: i,
                                item: dataItem
                            });
                            break;
                        }
                    }
                    if (!found) {
                        unchanged.push(dataItem);
                    }
                }
            }
            return {
                changed: changed,
                unchanged: unchanged
            };
        }
        function isValidFilterExpr(expression) {
            if (!expression || $.isEmptyObject(expression)) {
                return false;
            }
            if (expression.filters && !expression.filters.length) {
                return false;
            }
            return true;
        }
        function removeFiltersForField(expression, field) {
            var filters;
            var found = false;
            if (expression.filters) {
                filters = $.grep(expression.filters, function (filter) {
                    found = removeFiltersForField(filter, field);
                    if (filter.filters) {
                        return filter.filters.length;
                    } else {
                        return filter.field != field;
                    }
                });
                if (!found && expression.filters.length !== filters.length) {
                    found = true;
                }
                expression.filters = filters;
            }
            return found;
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.calendar', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'calendar',
        name: 'Calendar',
        category: 'web',
        description: 'The Calendar widget renders a graphical calendar that supports navigation and selection.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, ui = kendo.ui, Widget = ui.Widget, keys = kendo.keys, parse = kendo.parseDate, adjustDST = kendo.date.adjustDST, getDate = kendo.date.getDate, weekInYear = kendo.date.weekInYear, extractFormat = kendo._extractFormat, template = kendo.template, getCulture = kendo.getCulture, transitions = kendo.support.transitions, transitionOrigin = transitions ? transitions.css + 'transform-origin' : '', cellTemplate = template('<td#=data.cssClass# role="gridcell"><a tabindex="-1" class="k-link" href="\\#" data-#=data.ns#value="#=data.dateString#">#=data.value#</a></td>', { useWithBlock: false }), emptyCellTemplate = template('<td role="gridcell">&nbsp;</td>', { useWithBlock: false }), weekNumberTemplate = template('<td class="k-alt">#= data.weekNumber #</td>', { useWithBlock: false }), browser = kendo.support.browser, isIE8 = browser.msie && browser.version < 9, outerHeight = kendo._outerHeight, outerWidth = kendo._outerWidth, ns = '.kendoCalendar', CLICK = 'click' + ns, KEYDOWN_NS = 'keydown' + ns, ID = 'id', MIN = 'min', LEFT = 'left', SLIDE = 'slideIn', MONTH = 'month', CENTURY = 'century', CHANGE = 'change', NAVIGATE = 'navigate', VALUE = 'value', HOVER = 'k-state-hover', DISABLED = 'k-state-disabled', FOCUSED = 'k-state-focused', OTHERMONTH = 'k-other-month', OTHERMONTHCLASS = ' class="' + OTHERMONTH + '"', TODAY = 'k-nav-today', CELLSELECTOR = 'td:has(.k-link)', BLUR = 'blur' + ns, FOCUS = 'focus', FOCUS_WITH_NS = FOCUS + ns, MOUSEENTER = support.touch ? 'touchstart' : 'mouseenter', MOUSEENTER_WITH_NS = support.touch ? 'touchstart' + ns : 'mouseenter' + ns, MOUSELEAVE = support.touch ? 'touchend' + ns + ' touchmove' + ns : 'mouseleave' + ns, MS_PER_MINUTE = 60000, MS_PER_DAY = 86400000, PREVARROW = '_prevArrow', NEXTARROW = '_nextArrow', ARIA_DISABLED = 'aria-disabled', ARIA_SELECTED = 'aria-selected', ARIA_LABEL = 'aria-label', proxy = $.proxy, extend = $.extend, DATE = Date, views = {
                month: 0,
                year: 1,
                decade: 2,
                century: 3
            };
        var Calendar = Widget.extend({
            init: function (element, options) {
                var that = this, value, id;
                Widget.fn.init.call(that, element, options);
                element = that.wrapper = that.element;
                options = that.options;
                options.url = window.unescape(options.url);
                that.options.disableDates = getDisabledExpr(that.options.disableDates);
                that._templates();
                that._header();
                that._footer(that.footer);
                id = element.addClass('k-widget k-calendar ' + (options.weekNumber ? ' k-week-number' : '')).on(MOUSEENTER_WITH_NS + ' ' + MOUSELEAVE, CELLSELECTOR, mousetoggle).on(KEYDOWN_NS, 'table.k-content', proxy(that._move, that)).on(CLICK, CELLSELECTOR, function (e) {
                    var link = e.currentTarget.firstChild, value = that._toDateObject(link);
                    if (link.href.indexOf('#') != -1) {
                        e.preventDefault();
                    }
                    if (that._view.name == 'month' && that.options.disableDates(value)) {
                        return;
                    }
                    that._click($(link));
                }).on('mouseup' + ns, 'table.k-content, .k-footer', function () {
                    that._focusView(that.options.focusOnNav !== false);
                }).attr(ID);
                if (id) {
                    that._cellID = id + '_cell_selected';
                }
                normalize(options);
                value = parse(options.value, options.format, options.culture);
                that._index = views[options.start];
                that._current = new DATE(+restrictValue(value, options.min, options.max));
                that._addClassProxy = function () {
                    that._active = true;
                    if (that._cell.hasClass(DISABLED)) {
                        var todayString = that._view.toDateString(getToday());
                        that._cell = that._cellByDate(todayString);
                    }
                    that._cell.addClass(FOCUSED);
                };
                that._removeClassProxy = function () {
                    that._active = false;
                    that._cell.removeClass(FOCUSED);
                };
                that.value(value);
                kendo.notify(that);
            },
            options: {
                name: 'Calendar',
                value: null,
                min: new DATE(1900, 0, 1),
                max: new DATE(2099, 11, 31),
                dates: [],
                url: '',
                culture: '',
                footer: '',
                format: '',
                month: {},
                weekNumber: false,
                start: MONTH,
                depth: MONTH,
                animation: {
                    horizontal: {
                        effects: SLIDE,
                        reverse: true,
                        duration: 500,
                        divisor: 2
                    },
                    vertical: {
                        effects: 'zoomIn',
                        duration: 400
                    }
                },
                messages: { weekColumnHeader: '' }
            },
            events: [
                CHANGE,
                NAVIGATE
            ],
            setOptions: function (options) {
                var that = this;
                normalize(options);
                options.disableDates = getDisabledExpr(options.disableDates);
                Widget.fn.setOptions.call(that, options);
                that._templates();
                that._footer(that.footer);
                that._index = views[that.options.start];
                that.navigate();
            },
            destroy: function () {
                var that = this, today = that._today;
                that.element.off(ns);
                that._title.off(ns);
                that[PREVARROW].off(ns);
                that[NEXTARROW].off(ns);
                kendo.destroy(that._table);
                if (today) {
                    kendo.destroy(today.off(ns));
                }
                Widget.fn.destroy.call(that);
            },
            current: function () {
                return this._current;
            },
            view: function () {
                return this._view;
            },
            focus: function (table) {
                table = table || this._table;
                this._bindTable(table);
                table.focus();
            },
            min: function (value) {
                return this._option(MIN, value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            navigateToPast: function () {
                this._navigate(PREVARROW, -1);
            },
            navigateToFuture: function () {
                this._navigate(NEXTARROW, 1);
            },
            navigateUp: function () {
                var that = this, index = that._index;
                if (that._title.hasClass(DISABLED)) {
                    return;
                }
                that.navigate(that._current, ++index);
            },
            navigateDown: function (value) {
                var that = this, index = that._index, depth = that.options.depth;
                if (!value) {
                    return;
                }
                if (index === views[depth]) {
                    if (!isEqualDate(that._value, that._current) || !isEqualDate(that._value, value)) {
                        that.value(value);
                        that.trigger(CHANGE);
                    }
                    return;
                }
                that.navigate(value, --index);
            },
            navigate: function (value, view) {
                view = isNaN(view) ? views[view] : view;
                var that = this, options = that.options, culture = options.culture, min = options.min, max = options.max, title = that._title, from = that._table, old = that._oldTable, selectedValue = that._value, currentValue = that._current, future = value && +value > +currentValue, vertical = view !== undefined && view !== that._index, to, currentView, compare, disabled;
                if (!value) {
                    value = currentValue;
                }
                that._current = value = new DATE(+restrictValue(value, min, max));
                if (view === undefined) {
                    view = that._index;
                } else {
                    that._index = view;
                }
                that._view = currentView = calendar.views[view];
                compare = currentView.compare;
                disabled = view === views[CENTURY];
                title.toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
                disabled = compare(value, min) < 1;
                that[PREVARROW].toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
                disabled = compare(value, max) > -1;
                that[NEXTARROW].toggleClass(DISABLED, disabled).attr(ARIA_DISABLED, disabled);
                if (from && old && old.data('animating')) {
                    old.kendoStop(true, true);
                    from.kendoStop(true, true);
                }
                that._oldTable = from;
                if (!from || that._changeView) {
                    title.html(currentView.title(value, min, max, culture));
                    that._table = to = $(currentView.content(extend({
                        min: min,
                        max: max,
                        date: value,
                        url: options.url,
                        dates: options.dates,
                        format: options.format,
                        culture: culture,
                        disableDates: options.disableDates,
                        isWeekColumnVisible: options.weekNumber,
                        messages: options.messages
                    }, that[currentView.name])));
                    addClassToViewContainer(to, currentView.name);
                    makeUnselectable(to);
                    var replace = from && from.data('start') === to.data('start');
                    that._animate({
                        from: from,
                        to: to,
                        vertical: vertical,
                        future: future,
                        replace: replace
                    });
                    that.trigger(NAVIGATE);
                    that._focus(value);
                }
                if (view === views[options.depth] && selectedValue && !that.options.disableDates(selectedValue)) {
                    that._class('k-state-selected', selectedValue);
                }
                that._class(FOCUSED, value);
                if (!from && that._cell) {
                    that._cell.removeClass(FOCUSED);
                }
                that._changeView = true;
            },
            value: function (value) {
                var that = this, view = that._view, options = that.options, old = that._view, min = options.min, max = options.max;
                if (value === undefined) {
                    return that._value;
                }
                if (value === null) {
                    that._current = new Date(that._current.getFullYear(), that._current.getMonth(), that._current.getDate());
                }
                value = parse(value, options.format, options.culture);
                if (value !== null) {
                    value = new DATE(+value);
                    if (!isInRange(value, min, max)) {
                        value = null;
                    }
                }
                if (value === null || !that.options.disableDates(value)) {
                    that._value = value;
                } else if (that._value === undefined) {
                    that._value = null;
                }
                if (old && value === null && that._cell) {
                    that._cell.removeClass('k-state-selected');
                } else {
                    that._changeView = !value || view && view.compare(value, that._current) !== 0;
                    that.navigate(value);
                }
            },
            _move: function (e) {
                var that = this, options = that.options, key = e.keyCode, view = that._view, index = that._index, min = that.options.min, max = that.options.max, currentValue = new DATE(+that._current), isRtl = kendo.support.isRtl(that.wrapper), isDisabled = that.options.disableDates, value, prevent, method, temp;
                if (e.target === that._table[0]) {
                    that._active = true;
                }
                if (e.ctrlKey) {
                    if (key == keys.RIGHT && !isRtl || key == keys.LEFT && isRtl) {
                        that.navigateToFuture();
                        prevent = true;
                    } else if (key == keys.LEFT && !isRtl || key == keys.RIGHT && isRtl) {
                        that.navigateToPast();
                        prevent = true;
                    } else if (key == keys.UP) {
                        that.navigateUp();
                        prevent = true;
                    } else if (key == keys.DOWN) {
                        that._click($(that._cell[0].firstChild));
                        prevent = true;
                    }
                } else {
                    if (key == keys.RIGHT && !isRtl || key == keys.LEFT && isRtl) {
                        value = 1;
                        prevent = true;
                    } else if (key == keys.LEFT && !isRtl || key == keys.RIGHT && isRtl) {
                        value = -1;
                        prevent = true;
                    } else if (key == keys.UP) {
                        value = index === 0 ? -7 : -4;
                        prevent = true;
                    } else if (key == keys.DOWN) {
                        value = index === 0 ? 7 : 4;
                        prevent = true;
                    } else if (key == keys.ENTER) {
                        that._click($(that._cell[0].firstChild));
                        prevent = true;
                    } else if (key == keys.HOME || key == keys.END) {
                        method = key == keys.HOME ? 'first' : 'last';
                        temp = view[method](currentValue);
                        currentValue = new DATE(temp.getFullYear(), temp.getMonth(), temp.getDate(), currentValue.getHours(), currentValue.getMinutes(), currentValue.getSeconds(), currentValue.getMilliseconds());
                        prevent = true;
                    } else if (key == keys.PAGEUP) {
                        prevent = true;
                        that.navigateToPast();
                    } else if (key == keys.PAGEDOWN) {
                        prevent = true;
                        that.navigateToFuture();
                    }
                    if (value || method) {
                        if (!method) {
                            view.setDate(currentValue, value);
                        }
                        if (isDisabled(currentValue)) {
                            currentValue = that._nextNavigatable(currentValue, value);
                        }
                        min = getDate(min);
                        if (isInRange(currentValue, min, max)) {
                            that._focus(restrictValue(currentValue, options.min, options.max));
                        }
                    }
                }
                if (prevent) {
                    e.preventDefault();
                }
                return that._current;
            },
            _nextNavigatable: function (currentValue, value) {
                var that = this, disabled = true, view = that._view, min = that.options.min, max = that.options.max, isDisabled = that.options.disableDates, navigatableDate = new Date(currentValue.getTime());
                view.setDate(navigatableDate, -value);
                while (disabled) {
                    view.setDate(currentValue, value);
                    if (!isInRange(currentValue, min, max)) {
                        currentValue = navigatableDate;
                        break;
                    }
                    disabled = isDisabled(currentValue);
                }
                return currentValue;
            },
            _animate: function (options) {
                var that = this, from = options.from, to = options.to, active = that._active;
                if (!from) {
                    to.insertAfter(that.element[0].firstChild);
                    that._bindTable(to);
                } else if (from.parent().data('animating')) {
                    from.off(ns);
                    from.parent().kendoStop(true, true).remove();
                    from.remove();
                    to.insertAfter(that.element[0].firstChild);
                    that._focusView(active);
                } else if (!from.is(':visible') || that.options.animation === false || options.replace) {
                    to.insertAfter(from);
                    from.off(ns).remove();
                    that._focusView(active);
                } else {
                    that[options.vertical ? '_vertical' : '_horizontal'](from, to, options.future);
                }
            },
            _horizontal: function (from, to, future) {
                var that = this, active = that._active, horizontal = that.options.animation.horizontal, effects = horizontal.effects, viewWidth = outerWidth(from);
                if (effects && effects.indexOf(SLIDE) != -1) {
                    from.add(to).css({ width: viewWidth });
                    from.wrap('<div/>');
                    that._focusView(active, from);
                    from.parent().css({
                        position: 'relative',
                        width: viewWidth * 2,
                        'float': LEFT,
                        'margin-left': future ? 0 : -viewWidth
                    });
                    to[future ? 'insertAfter' : 'insertBefore'](from);
                    extend(horizontal, {
                        effects: SLIDE + ':' + (future ? 'right' : LEFT),
                        complete: function () {
                            from.off(ns).remove();
                            that._oldTable = null;
                            to.unwrap();
                            that._focusView(active);
                        }
                    });
                    from.parent().kendoStop(true, true).kendoAnimate(horizontal);
                }
            },
            _vertical: function (from, to) {
                var that = this, vertical = that.options.animation.vertical, effects = vertical.effects, active = that._active, cell, position;
                if (effects && effects.indexOf('zoom') != -1) {
                    to.css({
                        position: 'absolute',
                        top: outerHeight(from.prev()),
                        left: 0
                    }).insertBefore(from);
                    if (transitionOrigin) {
                        cell = that._cellByDate(that._view.toDateString(that._current));
                        position = cell.position();
                        position = position.left + parseInt(cell.width() / 2, 10) + 'px' + ' ' + (position.top + parseInt(cell.height() / 2, 10) + 'px');
                        to.css(transitionOrigin, position);
                    }
                    from.kendoStop(true, true).kendoAnimate({
                        effects: 'fadeOut',
                        duration: 600,
                        complete: function () {
                            from.off(ns).remove();
                            that._oldTable = null;
                            to.css({
                                position: 'static',
                                top: 0,
                                left: 0
                            });
                            that._focusView(active);
                        }
                    });
                    to.kendoStop(true, true).kendoAnimate(vertical);
                }
            },
            _cellByDate: function (value) {
                return this._table.find('td:not(.' + OTHERMONTH + ')').filter(function () {
                    return $(this.firstChild).attr(kendo.attr(VALUE)) === value;
                });
            },
            _class: function (className, date) {
                var that = this, id = that._cellID, cell = that._cell, value = that._view.toDateString(date), disabledDate;
                if (cell) {
                    cell.removeAttr(ARIA_SELECTED).removeAttr(ARIA_LABEL).removeAttr(ID);
                }
                if (date && that._view.name == 'month') {
                    disabledDate = that.options.disableDates(date);
                }
                cell = that._table.find('td:not(.' + OTHERMONTH + ')').removeClass(className).filter(function () {
                    return $(this.firstChild).attr(kendo.attr(VALUE)) === value;
                }).attr(ARIA_SELECTED, true);
                if (className === FOCUSED && !that._active && that.options.focusOnNav !== false || disabledDate) {
                    className = '';
                }
                cell.addClass(className);
                if (cell[0]) {
                    that._cell = cell;
                }
                if (id) {
                    cell.attr(ID, id);
                    that._table.removeAttr('aria-activedescendant').attr('aria-activedescendant', id);
                }
            },
            _bindTable: function (table) {
                table.on(FOCUS_WITH_NS, this._addClassProxy).on(BLUR, this._removeClassProxy);
            },
            _click: function (link) {
                var that = this, options = that.options, currentValue = new Date(+that._current), value = that._toDateObject(link);
                adjustDST(value, 0);
                if (that._view.name == 'month' && that.options.disableDates(value)) {
                    value = that._value;
                }
                that._view.setDate(currentValue, value);
                that.navigateDown(restrictValue(currentValue, options.min, options.max));
            },
            _focus: function (value) {
                var that = this, view = that._view;
                if (view.compare(value, that._current) !== 0) {
                    that.navigate(value);
                } else {
                    that._current = value;
                    that._class(FOCUSED, value);
                }
            },
            _focusView: function (active, table) {
                if (active) {
                    this.focus(table);
                }
            },
            _footer: function (template) {
                var that = this, today = getToday(), element = that.element, footer = element.find('.k-footer');
                if (!template) {
                    that._toggle(false);
                    footer.hide();
                    return;
                }
                if (!footer[0]) {
                    footer = $('<div class="k-footer"><a href="#" class="k-link k-nav-today"></a></div>').appendTo(element);
                }
                that._today = footer.show().find('.k-link').html(template(today)).attr('title', kendo.toString(today, 'D', that.options.culture));
                that._toggle();
            },
            _header: function () {
                var that = this, element = that.element, links;
                if (!element.find('.k-header')[0]) {
                    element.html('<div class="k-header">' + '<a href="#" role="button" class="k-link k-nav-prev" ' + ARIA_LABEL + '="Previous"><span class="k-icon k-i-arrow-60-left"></span></a>' + '<a href="#" role="button" aria-live="assertive" aria-atomic="true" class="k-link k-nav-fast"></a>' + '<a href="#" role="button" class="k-link k-nav-next" ' + ARIA_LABEL + '="Next"><span class="k-icon k-i-arrow-60-right"></span></a>' + '</div>');
                }
                links = element.find('.k-link').on(MOUSEENTER_WITH_NS + ' ' + MOUSELEAVE + ' ' + FOCUS_WITH_NS + ' ' + BLUR, mousetoggle).click(false);
                that._title = links.eq(1).on(CLICK, function () {
                    that._active = that.options.focusOnNav !== false;
                    that.navigateUp();
                });
                that[PREVARROW] = links.eq(0).on(CLICK, function () {
                    that._active = that.options.focusOnNav !== false;
                    that.navigateToPast();
                });
                that[NEXTARROW] = links.eq(2).on(CLICK, function () {
                    that._active = that.options.focusOnNav !== false;
                    that.navigateToFuture();
                });
            },
            _navigate: function (arrow, modifier) {
                var that = this, index = that._index + 1, currentValue = new DATE(+that._current);
                arrow = that[arrow];
                if (!arrow.hasClass(DISABLED)) {
                    if (index > 3) {
                        currentValue.setFullYear(currentValue.getFullYear() + 100 * modifier);
                    } else {
                        calendar.views[index].setDate(currentValue, modifier);
                    }
                    that.navigate(currentValue);
                }
            },
            _option: function (option, value) {
                var that = this, options = that.options, currentValue = that._value || that._current, isBigger;
                if (value === undefined) {
                    return options[option];
                }
                value = parse(value, options.format, options.culture);
                if (!value) {
                    return;
                }
                options[option] = new DATE(+value);
                if (option === MIN) {
                    isBigger = value > currentValue;
                } else {
                    isBigger = currentValue > value;
                }
                if (isBigger || isEqualMonth(currentValue, value)) {
                    if (isBigger) {
                        that._value = null;
                    }
                    that._changeView = true;
                }
                if (!that._changeView) {
                    that._changeView = !!(options.month.content || options.month.empty);
                }
                that.navigate(that._value);
                that._toggle();
            },
            _toggle: function (toggle) {
                var that = this, options = that.options, isTodayDisabled = that.options.disableDates(getToday()), link = that._today;
                if (toggle === undefined) {
                    toggle = isInRange(getToday(), options.min, options.max);
                }
                if (link) {
                    link.off(CLICK);
                    if (toggle && !isTodayDisabled) {
                        link.addClass(TODAY).removeClass(DISABLED).on(CLICK, proxy(that._todayClick, that));
                    } else {
                        link.removeClass(TODAY).addClass(DISABLED).on(CLICK, prevent);
                    }
                }
            },
            _todayClick: function (e) {
                var that = this, depth = views[that.options.depth], disabled = that.options.disableDates, today = getToday();
                e.preventDefault();
                if (disabled(today)) {
                    return;
                }
                if (that._view.compare(that._current, today) === 0 && that._index == depth) {
                    that._changeView = false;
                }
                that._value = today;
                that.navigate(today, depth);
                that.trigger(CHANGE);
            },
            _toDateObject: function (link) {
                var value = $(link).attr(kendo.attr(VALUE)).split('/');
                value = new DATE(value[0], value[1], value[2]);
                return value;
            },
            _templates: function () {
                var that = this, options = that.options, footer = options.footer, month = options.month, content = month.content, weekNumber = month.weekNumber, empty = month.empty;
                that.month = {
                    content: template('<td#=data.cssClass# role="gridcell"><a tabindex="-1" class="k-link#=data.linkClass#" href="#=data.url#" ' + kendo.attr('value') + '="#=data.dateString#" title="#=data.title#">' + (content || '#=data.value#') + '</a></td>', { useWithBlock: !!content }),
                    empty: template('<td role="gridcell">' + (empty || '&nbsp;') + '</td>', { useWithBlock: !!empty }),
                    weekNumber: template('<td class="k-alt">' + (weekNumber || '#= data.weekNumber #') + '</td>', { useWithBlock: !!weekNumber })
                };
                that.footer = footer !== false ? template(footer || '#= kendo.toString(data,"D","' + options.culture + '") #', { useWithBlock: false }) : null;
            }
        });
        ui.plugin(Calendar);
        var calendar = {
            firstDayOfMonth: function (date) {
                return new DATE(date.getFullYear(), date.getMonth(), 1);
            },
            firstVisibleDay: function (date, calendarInfo) {
                calendarInfo = calendarInfo || kendo.culture().calendar;
                var firstDay = calendarInfo.firstDay, firstVisibleDay = new DATE(date.getFullYear(), date.getMonth(), 0, date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
                while (firstVisibleDay.getDay() != firstDay) {
                    calendar.setTime(firstVisibleDay, -1 * MS_PER_DAY);
                }
                return firstVisibleDay;
            },
            setTime: function (date, time) {
                var tzOffsetBefore = date.getTimezoneOffset(), resultDATE = new DATE(date.getTime() + time), tzOffsetDiff = resultDATE.getTimezoneOffset() - tzOffsetBefore;
                date.setTime(resultDATE.getTime() + tzOffsetDiff * MS_PER_MINUTE);
            },
            views: [
                {
                    name: MONTH,
                    title: function (date, min, max, culture) {
                        return getCalendarInfo(culture).months.names[date.getMonth()] + ' ' + date.getFullYear();
                    },
                    content: function (options) {
                        var that = this, idx = 0, min = options.min, max = options.max, date = options.date, dates = options.dates, format = options.format, culture = options.culture, navigateUrl = options.url, isWeekColumnVisible = options.isWeekColumnVisible, hasUrl = navigateUrl && dates[0], currentCalendar = getCalendarInfo(culture), firstDayIdx = currentCalendar.firstDay, days = currentCalendar.days, names = shiftArray(days.names, firstDayIdx), shortNames = shiftArray(days.namesShort, firstDayIdx), start = calendar.firstVisibleDay(date, currentCalendar), firstDayOfMonth = that.first(date), lastDayOfMonth = that.last(date), toDateString = that.toDateString, today = new DATE(), html = '<table tabindex="0" role="grid" class="k-content" cellspacing="0" data-start="' + toDateString(start) + '"><thead><tr role="row">';
                        if (isWeekColumnVisible) {
                            html += '<th scope="col" class="k-alt">' + options.messages.weekColumnHeader + '</th>';
                        }
                        for (; idx < 7; idx++) {
                            html += '<th scope="col" title="' + names[idx] + '">' + shortNames[idx] + '</th>';
                        }
                        today = new DATE(today.getFullYear(), today.getMonth(), today.getDate());
                        adjustDST(today, 0);
                        today = +today;
                        return view({
                            cells: 42,
                            perRow: 7,
                            html: html += '</tr></thead><tbody><tr role="row">',
                            start: start,
                            isWeekColumnVisible: isWeekColumnVisible,
                            weekNumber: options.weekNumber,
                            min: new DATE(min.getFullYear(), min.getMonth(), min.getDate()),
                            max: new DATE(max.getFullYear(), max.getMonth(), max.getDate()),
                            content: options.content,
                            empty: options.empty,
                            setter: that.setDate,
                            disableDates: options.disableDates,
                            build: function (date, idx, disableDates) {
                                var cssClass = [], day = date.getDay(), linkClass = '', url = '#';
                                if (date < firstDayOfMonth || date > lastDayOfMonth) {
                                    cssClass.push(OTHERMONTH);
                                }
                                if (disableDates(date)) {
                                    cssClass.push(DISABLED);
                                }
                                if (+date === today) {
                                    cssClass.push('k-today');
                                }
                                if (day === 0 || day === 6) {
                                    cssClass.push('k-weekend');
                                }
                                if (hasUrl && inArray(+date, dates)) {
                                    url = navigateUrl.replace('{0}', kendo.toString(date, format, culture));
                                    linkClass = ' k-action-link';
                                }
                                return {
                                    date: date,
                                    dates: dates,
                                    ns: kendo.ns,
                                    title: kendo.toString(date, 'D', culture),
                                    value: date.getDate(),
                                    dateString: toDateString(date),
                                    cssClass: cssClass[0] ? ' class="' + cssClass.join(' ') + '"' : '',
                                    linkClass: linkClass,
                                    url: url
                                };
                            },
                            weekNumberBuild: function (date) {
                                return {
                                    weekNumber: weekInYear(date, kendo.culture().calendar.firstDay),
                                    currentDate: date
                                };
                            }
                        });
                    },
                    first: function (date) {
                        return calendar.firstDayOfMonth(date);
                    },
                    last: function (date) {
                        var last = new DATE(date.getFullYear(), date.getMonth() + 1, 0), first = calendar.firstDayOfMonth(date), timeOffset = Math.abs(last.getTimezoneOffset() - first.getTimezoneOffset());
                        if (timeOffset) {
                            last.setHours(first.getHours() + timeOffset / 60);
                        }
                        return last;
                    },
                    compare: function (date1, date2) {
                        var result, month1 = date1.getMonth(), year1 = date1.getFullYear(), month2 = date2.getMonth(), year2 = date2.getFullYear();
                        if (year1 > year2) {
                            result = 1;
                        } else if (year1 < year2) {
                            result = -1;
                        } else {
                            result = month1 == month2 ? 0 : month1 > month2 ? 1 : -1;
                        }
                        return result;
                    },
                    setDate: function (date, value) {
                        var hours = date.getHours();
                        if (value instanceof DATE) {
                            date.setFullYear(value.getFullYear(), value.getMonth(), value.getDate());
                        } else {
                            calendar.setTime(date, value * MS_PER_DAY);
                        }
                        adjustDST(date, hours);
                    },
                    toDateString: function (date) {
                        return date.getFullYear() + '/' + date.getMonth() + '/' + date.getDate();
                    }
                },
                {
                    name: 'year',
                    title: function (date) {
                        return date.getFullYear();
                    },
                    content: function (options) {
                        var namesAbbr = getCalendarInfo(options.culture).months.namesAbbr, toDateString = this.toDateString, min = options.min, max = options.max;
                        return view({
                            min: new DATE(min.getFullYear(), min.getMonth(), 1),
                            max: new DATE(max.getFullYear(), max.getMonth(), 1),
                            start: new DATE(options.date.getFullYear(), 0, 1),
                            setter: this.setDate,
                            build: function (date) {
                                return {
                                    value: namesAbbr[date.getMonth()],
                                    ns: kendo.ns,
                                    dateString: toDateString(date),
                                    cssClass: ''
                                };
                            }
                        });
                    },
                    first: function (date) {
                        return new DATE(date.getFullYear(), 0, date.getDate());
                    },
                    last: function (date) {
                        return new DATE(date.getFullYear(), 11, date.getDate());
                    },
                    compare: function (date1, date2) {
                        return compare(date1, date2);
                    },
                    setDate: function (date, value) {
                        var month, hours = date.getHours();
                        if (value instanceof DATE) {
                            month = value.getMonth();
                            date.setFullYear(value.getFullYear(), month, date.getDate());
                            if (month !== date.getMonth()) {
                                date.setDate(0);
                            }
                        } else {
                            month = date.getMonth() + value;
                            date.setMonth(month);
                            if (month > 11) {
                                month -= 12;
                            }
                            if (month > 0 && date.getMonth() != month) {
                                date.setDate(0);
                            }
                        }
                        adjustDST(date, hours);
                    },
                    toDateString: function (date) {
                        return date.getFullYear() + '/' + date.getMonth() + '/1';
                    }
                },
                {
                    name: 'decade',
                    title: function (date, min, max) {
                        return title(date, min, max, 10);
                    },
                    content: function (options) {
                        var year = options.date.getFullYear(), toDateString = this.toDateString;
                        return view({
                            start: new DATE(year - year % 10 - 1, 0, 1),
                            min: new DATE(options.min.getFullYear(), 0, 1),
                            max: new DATE(options.max.getFullYear(), 0, 1),
                            setter: this.setDate,
                            build: function (date, idx) {
                                return {
                                    value: date.getFullYear(),
                                    ns: kendo.ns,
                                    dateString: toDateString(date),
                                    cssClass: idx === 0 || idx == 11 ? OTHERMONTHCLASS : ''
                                };
                            }
                        });
                    },
                    first: function (date) {
                        var year = date.getFullYear();
                        return new DATE(year - year % 10, date.getMonth(), date.getDate());
                    },
                    last: function (date) {
                        var year = date.getFullYear();
                        return new DATE(year - year % 10 + 9, date.getMonth(), date.getDate());
                    },
                    compare: function (date1, date2) {
                        return compare(date1, date2, 10);
                    },
                    setDate: function (date, value) {
                        setDate(date, value, 1);
                    },
                    toDateString: function (date) {
                        return date.getFullYear() + '/0/1';
                    }
                },
                {
                    name: CENTURY,
                    title: function (date, min, max) {
                        return title(date, min, max, 100);
                    },
                    content: function (options) {
                        var year = options.date.getFullYear(), min = options.min.getFullYear(), max = options.max.getFullYear(), toDateString = this.toDateString, minYear = min, maxYear = max;
                        minYear = minYear - minYear % 10;
                        maxYear = maxYear - maxYear % 10;
                        if (maxYear - minYear < 10) {
                            maxYear = minYear + 9;
                        }
                        return view({
                            start: new DATE(year - year % 100 - 10, 0, 1),
                            min: new DATE(minYear, 0, 1),
                            max: new DATE(maxYear, 0, 1),
                            setter: this.setDate,
                            build: function (date, idx) {
                                var start = date.getFullYear(), end = start + 9;
                                if (start < min) {
                                    start = min;
                                }
                                if (end > max) {
                                    end = max;
                                }
                                return {
                                    ns: kendo.ns,
                                    value: start + ' - ' + end,
                                    dateString: toDateString(date),
                                    cssClass: idx === 0 || idx == 11 ? OTHERMONTHCLASS : ''
                                };
                            }
                        });
                    },
                    first: function (date) {
                        var year = date.getFullYear();
                        return new DATE(year - year % 100, date.getMonth(), date.getDate());
                    },
                    last: function (date) {
                        var year = date.getFullYear();
                        return new DATE(year - year % 100 + 99, date.getMonth(), date.getDate());
                    },
                    compare: function (date1, date2) {
                        return compare(date1, date2, 100);
                    },
                    setDate: function (date, value) {
                        setDate(date, value, 10);
                    },
                    toDateString: function (date) {
                        var year = date.getFullYear();
                        return year - year % 10 + '/0/1';
                    }
                }
            ]
        };
        function title(date, min, max, modular) {
            var start = date.getFullYear(), minYear = min.getFullYear(), maxYear = max.getFullYear(), end;
            start = start - start % modular;
            end = start + (modular - 1);
            if (start < minYear) {
                start = minYear;
            }
            if (end > maxYear) {
                end = maxYear;
            }
            return start + '-' + end;
        }
        function view(options) {
            var idx = 0, data, min = options.min, max = options.max, start = options.start, setter = options.setter, build = options.build, weekNumberBuild = options.weekNumberBuild, length = options.cells || 12, isWeekColumnVisible = options.isWeekColumnVisible, cellsPerRow = options.perRow || 4, weekNumber = options.weekNumber || weekNumberTemplate, content = options.content || cellTemplate, empty = options.empty || emptyCellTemplate, html = options.html || '<table tabindex="0" role="grid" class="k-content k-meta-view" cellspacing="0"><tbody><tr role="row">';
            if (isWeekColumnVisible) {
                html += weekNumber(weekNumberBuild(start));
            }
            for (; idx < length; idx++) {
                if (idx > 0 && idx % cellsPerRow === 0) {
                    html += '</tr><tr role="row">';
                    if (isWeekColumnVisible) {
                        html += weekNumber(weekNumberBuild(start));
                    }
                }
                start = new DATE(start.getFullYear(), start.getMonth(), start.getDate(), 0, 0, 0);
                adjustDST(start, 0);
                data = build(start, idx, options.disableDates);
                html += isInRange(start, min, max) ? content(data) : empty(data);
                setter(start, 1);
            }
            return html + '</tr></tbody></table>';
        }
        function compare(date1, date2, modifier) {
            var year1 = date1.getFullYear(), start = date2.getFullYear(), end = start, result = 0;
            if (modifier) {
                start = start - start % modifier;
                end = start - start % modifier + modifier - 1;
            }
            if (year1 > end) {
                result = 1;
            } else if (year1 < start) {
                result = -1;
            }
            return result;
        }
        function getToday() {
            var today = new DATE();
            return new DATE(today.getFullYear(), today.getMonth(), today.getDate());
        }
        function restrictValue(value, min, max) {
            var today = getToday();
            if (value) {
                today = new DATE(+value);
            }
            if (min > today) {
                today = new DATE(+min);
            } else if (max < today) {
                today = new DATE(+max);
            }
            return today;
        }
        function isInRange(date, min, max) {
            return +date >= +min && +date <= +max;
        }
        function shiftArray(array, idx) {
            return array.slice(idx).concat(array.slice(0, idx));
        }
        function setDate(date, value, multiplier) {
            value = value instanceof DATE ? value.getFullYear() : date.getFullYear() + multiplier * value;
            date.setFullYear(value);
        }
        function mousetoggle(e) {
            var disabled = $(this).hasClass('k-state-disabled');
            if (!disabled) {
                $(this).toggleClass(HOVER, MOUSEENTER.indexOf(e.type) > -1 || e.type == FOCUS);
            }
        }
        function prevent(e) {
            e.preventDefault();
        }
        function getCalendarInfo(culture) {
            return getCulture(culture).calendars.standard;
        }
        function normalize(options) {
            var start = views[options.start], depth = views[options.depth], culture = getCulture(options.culture);
            options.format = extractFormat(options.format || culture.calendars.standard.patterns.d);
            if (isNaN(start)) {
                start = 0;
                options.start = MONTH;
            }
            if (depth === undefined || depth > start) {
                options.depth = MONTH;
            }
            if (options.dates === null) {
                options.dates = [];
            }
        }
        function makeUnselectable(element) {
            if (isIE8) {
                element.find('*').attr('unselectable', 'on');
            }
        }
        function addClassToViewContainer(element, currentView) {
            element.addClass('k-' + currentView);
        }
        function inArray(date, dates) {
            for (var i = 0, length = dates.length; i < length; i++) {
                if (date === +dates[i]) {
                    return true;
                }
            }
            return false;
        }
        function isEqualDatePart(value1, value2) {
            if (value1) {
                return value1.getFullYear() === value2.getFullYear() && value1.getMonth() === value2.getMonth() && value1.getDate() === value2.getDate();
            }
            return false;
        }
        function isEqualMonth(value1, value2) {
            if (value1) {
                return value1.getFullYear() === value2.getFullYear() && value1.getMonth() === value2.getMonth();
            }
            return false;
        }
        function getDisabledExpr(option) {
            if (kendo.isFunction(option)) {
                return option;
            }
            if ($.isArray(option)) {
                return createDisabledExpr(option);
            }
            return $.noop;
        }
        function convertDatesArray(dates) {
            var result = [];
            for (var i = 0; i < dates.length; i++) {
                result.push(dates[i].setHours(0, 0, 0, 0));
            }
            return result;
        }
        function createDisabledExpr(dates) {
            var body, callback, disabledDates = [], days = [
                    'su',
                    'mo',
                    'tu',
                    'we',
                    'th',
                    'fr',
                    'sa'
                ], searchExpression = 'if (found) {' + ' return true ' + '} else {' + 'return false' + '}';
            if (dates[0] instanceof DATE) {
                disabledDates = convertDatesArray(dates);
                body = 'var found = date && $.inArray(date.setHours(0, 0, 0, 0),[' + disabledDates + ']) > -1;' + searchExpression;
            } else {
                for (var i = 0; i < dates.length; i++) {
                    var day = dates[i].slice(0, 2).toLowerCase();
                    var index = $.inArray(day, days);
                    if (index > -1) {
                        disabledDates.push(index);
                    }
                }
                body = 'var found = date && $.inArray(date.getDay(),[' + disabledDates + ']) > -1;' + searchExpression;
            }
            callback = new Function('date', body);
            return callback;
        }
        function isEqualDate(oldValue, newValue) {
            if (oldValue instanceof Date && newValue instanceof Date) {
                oldValue = oldValue.getTime();
                newValue = newValue.getTime();
            }
            return oldValue === newValue;
        }
        calendar.isEqualDatePart = isEqualDatePart;
        calendar.isEqualDate = isEqualDate;
        calendar.makeUnselectable = makeUnselectable;
        calendar.restrictValue = restrictValue;
        calendar.isInRange = isInRange;
        calendar.addClassToViewContainer = addClassToViewContainer;
        calendar.normalize = normalize;
        calendar.viewsEnum = views;
        calendar.disabled = getDisabledExpr;
        kendo.calendar = calendar;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.datepicker', [
        'kendo.calendar',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'datepicker',
        name: 'DatePicker',
        category: 'web',
        description: 'The DatePicker widget allows the user to select a date from a calendar or by direct input.',
        depends: [
            'calendar',
            'popup'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, parse = kendo.parseDate, keys = kendo.keys, template = kendo.template, activeElement = kendo._activeElement, DIV = '<div />', SPAN = '<span />', ns = '.kendoDatePicker', CLICK = 'click' + ns, OPEN = 'open', CLOSE = 'close', CHANGE = 'change', DISABLED = 'disabled', READONLY = 'readonly', DEFAULT = 'k-state-default', FOCUSED = 'k-state-focused', SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', HOVER = 'k-state-hover', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, MOUSEDOWN = 'mousedown' + ns, ID = 'id', MIN = 'min', MAX = 'max', MONTH = 'month', ARIA_DISABLED = 'aria-disabled', ARIA_EXPANDED = 'aria-expanded', ARIA_HIDDEN = 'aria-hidden', calendar = kendo.calendar, isInRange = calendar.isInRange, restrictValue = calendar.restrictValue, isEqualDatePart = calendar.isEqualDatePart, extend = $.extend, proxy = $.proxy, DATE = Date;
        function normalize(options) {
            var parseFormats = options.parseFormats, format = options.format;
            calendar.normalize(options);
            parseFormats = $.isArray(parseFormats) ? parseFormats : [parseFormats];
            if (!parseFormats.length) {
                parseFormats.push('yyyy-MM-dd');
            }
            if ($.inArray(format, parseFormats) === -1) {
                parseFormats.splice(0, 0, options.format);
            }
            options.parseFormats = parseFormats;
        }
        function preventDefault(e) {
            e.preventDefault();
        }
        var DateView = function (options) {
            var that = this, id, body = document.body, div = $(DIV).attr(ARIA_HIDDEN, 'true').addClass('k-calendar-container').appendTo(body);
            that.options = options = options || {};
            id = options.id;
            if (id) {
                id += '_dateview';
                div.attr(ID, id);
                that._dateViewID = id;
            }
            that.popup = new ui.Popup(div, extend(options.popup, options, {
                name: 'Popup',
                isRtl: kendo.support.isRtl(options.anchor)
            }));
            that.div = div;
            that.value(options.value);
        };
        DateView.prototype = {
            _calendar: function () {
                var that = this;
                var calendar = that.calendar;
                var options = that.options;
                var div;
                if (!calendar) {
                    div = $(DIV).attr(ID, kendo.guid()).appendTo(that.popup.element).on(MOUSEDOWN, preventDefault).on(CLICK, 'td:has(.k-link)', proxy(that._click, that));
                    that.calendar = calendar = new ui.Calendar(div);
                    that._setOptions(options);
                    kendo.calendar.makeUnselectable(calendar.element);
                    calendar.navigate(that._value || that._current, options.start);
                    that.value(that._value);
                }
            },
            _setOptions: function (options) {
                this.calendar.setOptions({
                    focusOnNav: false,
                    change: options.change,
                    culture: options.culture,
                    dates: options.dates,
                    depth: options.depth,
                    footer: options.footer,
                    format: options.format,
                    max: options.max,
                    min: options.min,
                    month: options.month,
                    weekNumber: options.weekNumber,
                    start: options.start,
                    disableDates: options.disableDates
                });
            },
            setOptions: function (options) {
                var old = this.options;
                var disableDates = options.disableDates;
                if (disableDates) {
                    options.disableDates = calendar.disabled(disableDates);
                }
                this.options = extend(old, options, {
                    change: old.change,
                    close: old.close,
                    open: old.open
                });
                if (this.calendar) {
                    this._setOptions(this.options);
                }
            },
            destroy: function () {
                this.popup.destroy();
            },
            open: function () {
                var that = this;
                that._calendar();
                that.popup.open();
            },
            close: function () {
                this.popup.close();
            },
            min: function (value) {
                this._option(MIN, value);
            },
            max: function (value) {
                this._option(MAX, value);
            },
            toggle: function () {
                var that = this;
                that[that.popup.visible() ? CLOSE : OPEN]();
            },
            move: function (e) {
                var that = this, key = e.keyCode, calendar = that.calendar, selectIsClicked = e.ctrlKey && key == keys.DOWN || key == keys.ENTER, handled = false;
                if (e.altKey) {
                    if (key == keys.DOWN) {
                        that.open();
                        e.preventDefault();
                        handled = true;
                    } else if (key == keys.UP) {
                        that.close();
                        e.preventDefault();
                        handled = true;
                    }
                } else if (that.popup.visible()) {
                    if (key == keys.ESC || selectIsClicked && calendar._cell.hasClass(SELECTED)) {
                        that.close();
                        e.preventDefault();
                        return true;
                    }
                    that._current = calendar._move(e);
                    handled = true;
                }
                return handled;
            },
            current: function (date) {
                this._current = date;
                this.calendar._focus(date);
            },
            value: function (value) {
                var that = this, calendar = that.calendar, options = that.options, disabledDate = options.disableDates;
                if (disabledDate && disabledDate(value)) {
                    value = null;
                }
                that._value = value;
                that._current = new DATE(+restrictValue(value, options.min, options.max));
                if (calendar) {
                    calendar.value(value);
                }
            },
            _click: function (e) {
                if (e.currentTarget.className.indexOf(SELECTED) !== -1) {
                    this.close();
                }
            },
            _option: function (option, value) {
                var that = this;
                var calendar = that.calendar;
                that.options[option] = value;
                if (calendar) {
                    calendar[option](value);
                }
            }
        };
        DateView.normalize = normalize;
        kendo.DateView = DateView;
        var DatePicker = Widget.extend({
            init: function (element, options) {
                var that = this, disabled, div;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.disableDates = kendo.calendar.disabled(options.disableDates);
                options.min = parse(element.attr('min')) || parse(options.min);
                options.max = parse(element.attr('max')) || parse(options.max);
                normalize(options);
                that._initialOptions = extend({}, options);
                that._wrapper();
                that.dateView = new DateView(extend({}, options, {
                    id: element.attr(ID),
                    anchor: that.wrapper,
                    change: function () {
                        that._change(this.value());
                        that.close();
                    },
                    close: function (e) {
                        if (that.trigger(CLOSE)) {
                            e.preventDefault();
                        } else {
                            element.attr(ARIA_EXPANDED, false);
                            div.attr(ARIA_HIDDEN, true);
                        }
                    },
                    open: function (e) {
                        var options = that.options, date;
                        if (that.trigger(OPEN)) {
                            e.preventDefault();
                        } else {
                            if (that.element.val() !== that._oldText) {
                                date = parse(element.val(), options.parseFormats, options.culture);
                                that.dateView[date ? 'current' : 'value'](date);
                            }
                            element.attr(ARIA_EXPANDED, true);
                            div.attr(ARIA_HIDDEN, false);
                            that._updateARIA(date);
                        }
                    }
                }));
                div = that.dateView.div;
                that._icon();
                try {
                    element[0].setAttribute('type', 'text');
                } catch (e) {
                    element[0].type = 'text';
                }
                element.addClass('k-input').attr({
                    role: 'combobox',
                    'aria-expanded': false,
                    'aria-owns': that.dateView._dateViewID
                });
                that._reset();
                that._template();
                disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                if (options.dateInput) {
                    that._dateInput = new ui.DateInput(element, {
                        culture: options.culture,
                        format: options.format,
                        min: options.min,
                        max: options.max,
                        value: options.value
                    });
                }
                that._old = that._update(options.value || that.element.val());
                that._oldText = element.val();
                kendo.notify(that);
            },
            events: [
                OPEN,
                CLOSE,
                CHANGE
            ],
            options: {
                name: 'DatePicker',
                value: null,
                footer: '',
                format: '',
                culture: '',
                parseFormats: [],
                min: new Date(1900, 0, 1),
                max: new Date(2099, 11, 31),
                start: MONTH,
                depth: MONTH,
                animation: {},
                month: {},
                dates: [],
                ARIATemplate: 'Current focused date is #=kendo.toString(data.current, "D")#',
                dateInput: false
            },
            setOptions: function (options) {
                var that = this;
                var value = that._value;
                Widget.fn.setOptions.call(that, options);
                options = that.options;
                options.min = parse(options.min);
                options.max = parse(options.max);
                normalize(options);
                that.dateView.setOptions(options);
                if (that._dateInput) {
                    that._dateInput.setOptions({
                        culture: options.culture,
                        format: options.format,
                        min: options.min,
                        max: options.max,
                        value: options.value
                    });
                }
                if (value) {
                    that.element.val(kendo.toString(value, options.format, options.culture));
                    that._updateARIA(value);
                }
            },
            _editable: function (options) {
                var that = this, icon = that._dateIcon.off(ns), element = that.element.off(ns), wrapper = that._inputWrapper.off(ns), readonly = options.readonly, disable = options.disable;
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    element.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false).on('keydown' + ns, proxy(that._keydown, that)).on('focusout' + ns, proxy(that._blur, that)).on('focus' + ns, function () {
                        that._inputWrapper.addClass(FOCUSED);
                    });
                    icon.on(CLICK, proxy(that._click, that)).on(MOUSEDOWN, preventDefault);
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    element.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.dateView.destroy();
                that.element.off(ns);
                that._dateIcon.off(ns);
                that._inputWrapper.off(ns);
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
            },
            open: function () {
                this.dateView.open();
            },
            close: function () {
                this.dateView.close();
            },
            min: function (value) {
                return this._option(MIN, value);
            },
            max: function (value) {
                return this._option(MAX, value);
            },
            value: function (value) {
                var that = this;
                if (value === undefined) {
                    return that._value;
                }
                that._old = that._update(value);
                if (that._old === null) {
                    that.element.val('');
                }
                that._oldText = that.element.val();
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _blur: function () {
                var that = this, value = that.element.val();
                that.close();
                if (value !== that._oldText) {
                    that._change(value);
                }
                that._inputWrapper.removeClass(FOCUSED);
            },
            _click: function () {
                var that = this, element = that.element;
                that.dateView.toggle();
                if (!kendo.support.touch && element[0] !== activeElement()) {
                    element.focus();
                }
            },
            _change: function (value) {
                var that = this, oldValue = that.element.val(), dateChanged;
                value = that._update(value);
                dateChanged = !kendo.calendar.isEqualDate(that._old, value);
                var valueUpdated = dateChanged && !that._typing;
                var textFormatted = oldValue !== that.element.val();
                if (valueUpdated || textFormatted) {
                    that.element.trigger(CHANGE);
                }
                if (dateChanged) {
                    that._old = value;
                    that._oldText = that.element.val();
                    that.trigger(CHANGE);
                }
                that._typing = false;
            },
            _keydown: function (e) {
                var that = this, dateView = that.dateView, value = that.element.val(), handled = false;
                if (!dateView.popup.visible() && e.keyCode == keys.ENTER && value !== that._oldText) {
                    that._change(value);
                } else {
                    handled = dateView.move(e);
                    that._updateARIA(dateView._current);
                    if (!handled) {
                        that._typing = true;
                    } else if (that._dateInput && e.stopImmediatePropagation) {
                        e.stopImmediatePropagation();
                    }
                }
            },
            _icon: function () {
                var that = this, element = that.element, icon;
                icon = element.next('span.k-select');
                if (!icon[0]) {
                    icon = $('<span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-calendar"></span></span>').insertAfter(element);
                }
                that._dateIcon = icon.attr({
                    'role': 'button',
                    'aria-controls': that.dateView._dateViewID
                });
            },
            _option: function (option, value) {
                var that = this, options = that.options;
                if (value === undefined) {
                    return options[option];
                }
                value = parse(value, options.parseFormats, options.culture);
                if (!value) {
                    return;
                }
                options[option] = new DATE(+value);
                that.dateView[option](value);
            },
            _update: function (value) {
                var that = this, options = that.options, min = options.min, max = options.max, current = that._value, date = parse(value, options.parseFormats, options.culture), isSameType = date === null && current === null || date instanceof Date && current instanceof Date, formattedValue;
                if (options.disableDates(date)) {
                    date = null;
                    if (!that._old && !that.element.val()) {
                        value = null;
                    }
                }
                if (+date === +current && isSameType) {
                    formattedValue = kendo.toString(date, options.format, options.culture);
                    if (formattedValue !== value) {
                        that.element.val(date === null ? value : formattedValue);
                    }
                    return date;
                }
                if (date !== null && isEqualDatePart(date, min)) {
                    date = restrictValue(date, min, max);
                } else if (!isInRange(date, min, max)) {
                    date = null;
                }
                that._value = date;
                that.dateView.value(date);
                if (that._dateInput) {
                    that._dateInput.value(date || value);
                } else {
                    that.element.val(kendo.toString(date || value, options.format, options.culture));
                }
                that._updateARIA(date);
                return date;
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper;
                wrapper = element.parents('.k-datepicker');
                if (!wrapper[0]) {
                    wrapper = element.wrap(SPAN).parent().addClass('k-picker-wrap k-state-default');
                    wrapper = wrapper.wrap(SPAN).parent();
                }
                wrapper[0].style.cssText = element[0].style.cssText;
                element.css({
                    width: '100%',
                    height: element[0].style.height
                });
                that.wrapper = wrapper.addClass('k-widget k-datepicker k-header').addClass(element[0].className);
                that._inputWrapper = $(wrapper[0].firstChild);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        that.value(element[0].defaultValue);
                        that.max(that._initialOptions.max);
                        that.min(that._initialOptions.min);
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _template: function () {
                this._ariaTemplate = template(this.options.ARIATemplate);
            },
            _updateARIA: function (date) {
                var cell;
                var that = this;
                var calendar = that.dateView.calendar;
                that.element.removeAttr('aria-activedescendant');
                if (calendar) {
                    cell = calendar._cell;
                    cell.attr('aria-label', that._ariaTemplate({ current: date || calendar.current() }));
                    that.element.attr('aria-activedescendant', cell.attr('id'));
                }
            }
        });
        ui.plugin(DatePicker);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dateinput', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'dateinput',
        name: 'DateInput',
        category: 'web',
        description: 'The DateInput widget allows to edit date by typing.',
        depends: ['core']
    };
    (function ($, undefined) {
        var global = window;
        var kendo = global.kendo;
        var caret = kendo.caret;
        var ui = kendo.ui;
        var Widget = ui.Widget;
        var keys = kendo.keys;
        var ns = '.kendoDateInput';
        var proxy = $.proxy;
        var objectToString = {}.toString;
        var INPUT_EVENT_NAME = (kendo.support.propertyChangeEvent ? 'propertychange.kendoDateInput input' : 'input') + ns;
        var STATEDISABLED = 'k-state-disabled';
        var STATEDEFAULT = 'k-state-default';
        var STATEINVALID = 'k-state-invalid';
        var DISABLED = 'disabled';
        var READONLY = 'readonly';
        var CHANGE = 'change';
        var knownSymbols = 'dMyHhmftsz';
        var DateInput = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.format = kendo._extractFormat(options.format || kendo.getCulture(options.culture).calendars.standard.patterns.d);
                options.min = kendo.parseDate(element.attr('min')) || kendo.parseDate(options.min);
                options.max = kendo.parseDate(element.attr('max')) || kendo.parseDate(options.max);
                var insidePicker = (element.parent().attr('class') || '').indexOf('k-picker-wrap') >= 0;
                if (insidePicker) {
                    that.wrapper = element.parent();
                } else {
                    that.wrapper = element.wrap('<span class=\'k-widget k-dateinput\'></span>').parent();
                    that.wrapper.addClass(element[0].className);
                    that.wrapper[0].style.cssText = element[0].style.cssText;
                    element.css({
                        width: '100%',
                        height: element[0].style.height
                    });
                }
                $('<span class=\'k-icon k-i-warning\'></span>').insertAfter(element);
                that._form();
                that.element.addClass(insidePicker ? ' ' : 'k-textbox').attr('autocomplete', 'off').on('focusout' + ns, function () {
                    that._change();
                });
                try {
                    element[0].setAttribute('type', 'text');
                } catch (e) {
                    element[0].type = 'text';
                }
                var disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                that.value(that.options.value || element.val());
                kendo.notify(that);
            },
            options: {
                name: 'DateInput',
                culture: '',
                value: '',
                format: '',
                min: new Date(1900, 0, 1),
                max: new Date(2099, 11, 31),
                messages: {
                    'year': 'year',
                    'month': 'month',
                    'day': 'day',
                    'weekday': 'day of the week',
                    'hour': 'hours',
                    'minute': 'minutes',
                    'second': 'seconds',
                    'dayperiod': 'AM/PM'
                }
            },
            events: [CHANGE],
            min: function (value) {
                if (value !== undefined) {
                    this.options.min = value;
                } else {
                    return this.options.min;
                }
            },
            max: function (value) {
                if (value !== undefined) {
                    this.options.max = value;
                } else {
                    return this.options.max;
                }
            },
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                this._unbindInput();
                this._bindInput();
                this._updateElementValue();
            },
            destroy: function () {
                var that = this;
                that.element.off(ns);
                if (that._formElement) {
                    that._formElement.off('reset', that._resetHandler);
                }
                Widget.fn.destroy.call(that);
            },
            value: function (value) {
                if (value === undefined) {
                    return this._dateTime.getDateObject();
                }
                if (value === null) {
                    value = '';
                }
                if (objectToString.call(value) !== '[object Date]') {
                    value = kendo.parseDate(value, this.options.format, this.options.culture);
                }
                if (value && !value.getTime()) {
                    value = null;
                }
                this._dateTime = new customDateTime(value, this.options.format, this.options.culture, this.options.messages);
                this._updateElementValue();
                this._oldValue = value;
            },
            _updateElementValue: function () {
                var stringAndFromat = this._dateTime.toPair(this.options.format, this.options.culture, this.options.messages);
                this.element.val(stringAndFromat[0]);
                this._oldText = stringAndFromat[0];
                this._format = stringAndFromat[1];
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            _bindInput: function () {
                var that = this;
                that.element.on('keydown' + ns, proxy(that._keydown, that)).on(INPUT_EVENT_NAME, proxy(that._input, that)).on('mouseup' + ns, proxy(that._mouseUp, that)).on('DOMMouseScroll' + ns + ' mousewheel' + ns, proxy(that._scroll, that));
            },
            _unbindInput: function () {
                this.element.off('keydown' + ns).off('paste' + ns).off(INPUT_EVENT_NAME).off('mouseup' + ns).off('DOMMouseScroll' + ns + ' mousewheel' + ns);
            },
            _editable: function (options) {
                var that = this;
                var element = that.element;
                var disable = options.disable;
                var readonly = options.readonly;
                var wrapper = that.wrapper;
                that._unbindInput();
                if (!readonly && !disable) {
                    wrapper.addClass(STATEDEFAULT).removeClass(STATEDISABLED);
                    element.removeAttr(DISABLED).removeAttr(READONLY);
                    that._bindInput();
                } else {
                    wrapper.addClass(STATEDISABLED).removeClass(STATEDEFAULT);
                    element.attr(DISABLED, disable).attr(READONLY, readonly);
                }
            },
            _change: function () {
                var that = this;
                var oldValue = that._oldValue;
                var value = that.value();
                if (value && that.min() && value < that.min()) {
                    that.value(that.min());
                    value = that.value();
                }
                if (value && that.max() && value > that.max()) {
                    that.value(that.max());
                    value = that.value();
                }
                if (oldValue && value && value.getTime() !== oldValue.getTime() || oldValue && !value || !oldValue && value) {
                    that._oldValue = value;
                    that.trigger(CHANGE);
                    that.element.trigger(CHANGE);
                }
            },
            _input: function () {
                var that = this;
                var element = that.element[0];
                var blinkInvalid = false;
                if (kendo._activeElement() !== element) {
                    return;
                }
                var diff = approximateStringMatching(this._oldText, this._format, this.element[0].value, caret(this.element[0])[0]);
                var navigationOnly = diff.length === 1 && diff[0][1] === ' ';
                if (!navigationOnly) {
                    for (var i = 0; i < diff.length; i++) {
                        var valid = this._dateTime.parsePart(diff[i][0], diff[i][1]);
                        blinkInvalid = blinkInvalid || !valid;
                    }
                }
                this._updateElementValue();
                if (diff.length && diff[0][0] !== ' ') {
                    this._selectSegment(diff[0][0]);
                    if (!navigationOnly) {
                        var difSym = diff[0][0];
                        setTimeout(function () {
                            that._selectSegment(difSym);
                        });
                    }
                }
                if (navigationOnly) {
                    var newEvent = {
                        keyCode: 39,
                        preventDefault: function () {
                        }
                    };
                    this._keydown(newEvent);
                }
                if (blinkInvalid) {
                    clearTimeout(that._blinkInvalidTimeout);
                    var stateInvalid = STATEINVALID;
                    that.wrapper.addClass(STATEINVALID);
                    that._blinkInvalidTimeout = setTimeout(function () {
                        that.wrapper.removeClass(stateInvalid);
                    }, 100);
                }
            },
            _mouseUp: function () {
                var selection = caret(this.element[0]);
                if (selection[0] === selection[1]) {
                    this._selectNearestSegment();
                }
            },
            _scroll: function (e) {
                if (kendo._activeElement() !== this.element[0] || this.element.is('[readonly]')) {
                    return;
                }
                e = window.event || e;
                var newEvent = {
                    keyCode: 37,
                    preventDefault: function () {
                    }
                };
                if (e.shiftKey) {
                    newEvent.keyCode = (e.wheelDelta || -e.detail) > 0 ? 37 : 39;
                } else {
                    newEvent.keyCode = (e.wheelDelta || -e.detail) > 0 ? 38 : 40;
                }
                this._keydown(newEvent);
                e.returnValue = false;
                if (e.preventDefault) {
                    e.preventDefault();
                }
                if (e.stopPropagation) {
                    e.stopPropagation();
                }
            },
            _form: function () {
                var that = this;
                var element = that.element;
                var formId = element.attr('form');
                var form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(element[0].value);
                        });
                    };
                    that._formElement = form.on('reset', that._resetHandler);
                }
            },
            _keydown: function (e) {
                var key = e.keyCode;
                var selection;
                if (key == 37 || key == 39) {
                    e.preventDefault();
                    selection = caret(this.element[0]);
                    if (selection[0] != selection[1]) {
                        this._selectNearestSegment();
                    }
                    var dir = key == 37 ? -1 : 1;
                    var index = dir == -1 ? caret(this.element[0])[0] - 1 : caret(this.element[0])[1] + 1;
                    while (index >= 0 && index < this._format.length) {
                        if (knownSymbols.indexOf(this._format[index]) >= 0) {
                            this._selectSegment(this._format[index]);
                            break;
                        }
                        index += dir;
                    }
                }
                if (key == 38 || key == 40) {
                    e.preventDefault();
                    selection = caret(this.element[0]);
                    var symbol = this._format[selection[0]];
                    if (knownSymbols.indexOf(symbol) >= 0) {
                        this._dateTime.modifyPart(symbol, key == 38 ? 1 : -1);
                        this._updateElementValue();
                        this._selectSegment(symbol);
                    }
                }
                if (kendo.support.browser.msie && kendo.support.browser.version < 10) {
                    var keycode = e.keyCode ? e.keyCode : e.which;
                    if (keycode === 8 || keycode === 46) {
                        var that = this;
                        setTimeout(function () {
                            that._input();
                        }, 0);
                    }
                }
                if (key === keys.ENTER) {
                    this._change();
                }
            },
            _selectNearestSegment: function () {
                var selection = caret(this.element[0]);
                var start = selection[0];
                for (var i = start, j = start - 1; i < this._format.length || j >= 0; i++, j--) {
                    if (i < this._format.length && knownSymbols.indexOf(this._format[i]) !== -1) {
                        this._selectSegment(this._format[i]);
                        return;
                    }
                    if (j >= 0 && knownSymbols.indexOf(this._format[j]) !== -1) {
                        this._selectSegment(this._format[j]);
                        return;
                    }
                }
            },
            _selectSegment: function (symbol) {
                var begin = -1, end = 0;
                for (var i = 0; i < this._format.length; i++) {
                    if (this._format[i] === symbol) {
                        end = i + 1;
                        if (begin === -1) {
                            begin = i;
                        }
                    }
                }
                if (begin < 0) {
                    begin = 0;
                }
                caret(this.element, begin, end);
            }
        });
        ui.plugin(DateInput);
        var customDateTime = function (initDate, initFormat, initCulture, initMessages) {
            var value = null;
            var year = true, month = true, date = true, hours = true, minutes = true, seconds = true, milliseconds = true;
            var typedMonthPart = '';
            var typedDayPeriodPart = '';
            var placeholders = {};
            var zeros = [
                '',
                '0',
                '00',
                '000',
                '0000'
            ];
            function pad(number, digits, end) {
                number = number + '';
                digits = digits || 2;
                end = digits - number.length;
                if (end) {
                    return zeros[digits].substring(0, end) + number;
                }
                return number;
            }
            var dateFormatRegExp = /dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|HH|H|hh|h|mm|m|fff|ff|f|tt|ss|s|zzz|zz|z|"[^"]*"|'[^']*'/g;
            var months = null, calendar = null, days = null, returnsFormat = false;
            var matcher = function (match) {
                var mins, sign;
                var result;
                switch (match) {
                case 'd':
                    result = date ? value.getDate() : placeholders.day;
                    break;
                case 'dd':
                    result = date ? pad(value.getDate()) : placeholders.day;
                    break;
                case 'ddd':
                    result = date && month && year ? days.namesAbbr[value.getDay()] : placeholders.weekday;
                    break;
                case 'dddd':
                    result = date && month && year ? days.names[value.getDay()] : placeholders.weekday;
                    break;
                case 'M':
                    result = month ? value.getMonth() + 1 : placeholders.month;
                    break;
                case 'MM':
                    result = month ? pad(value.getMonth() + 1) : placeholders.month;
                    break;
                case 'MMM':
                    result = month ? months.namesAbbr[value.getMonth()] : placeholders.month;
                    break;
                case 'MMMM':
                    result = month ? months.names[value.getMonth()] : placeholders.month;
                    break;
                case 'yy':
                    result = year ? pad(value.getFullYear() % 100) : placeholders.year;
                    break;
                case 'yyyy':
                    result = year ? pad(value.getFullYear(), 4) : placeholders.year;
                    break;
                case 'h':
                    result = hours ? value.getHours() % 12 || 12 : placeholders.hour;
                    break;
                case 'hh':
                    result = hours ? pad(value.getHours() % 12 || 12) : placeholders.hour;
                    break;
                case 'H':
                    result = hours ? value.getHours() : placeholders.hour;
                    break;
                case 'HH':
                    result = hours ? pad(value.getHours()) : placeholders.hour;
                    break;
                case 'm':
                    result = minutes ? value.getMinutes() : placeholders.minute;
                    break;
                case 'mm':
                    result = minutes ? pad(value.getMinutes()) : placeholders.minute;
                    break;
                case 's':
                    result = seconds ? value.getSeconds() : placeholders.second;
                    break;
                case 'ss':
                    result = seconds ? pad(value.getSeconds()) : placeholders.second;
                    break;
                case 'f':
                    result = milliseconds ? Math.floor(value.getMilliseconds() / 100) : milliseconds;
                    break;
                case 'ff':
                    result = value.getMilliseconds();
                    if (result > 99) {
                        result = Math.floor(result / 10);
                    }
                    result = milliseconds ? pad(result) : match;
                    break;
                case 'fff':
                    result = milliseconds ? pad(value.getMilliseconds(), 3) : match;
                    break;
                case 'tt':
                    result = hours ? value.getHours() < 12 ? calendar.AM[0] : calendar.PM[0] : placeholders.dayperiod;
                    break;
                case 'zzz':
                    mins = value.getTimezoneOffset();
                    sign = mins < 0;
                    result = Math.abs(mins / 60).toString().split('.')[0];
                    mins = Math.abs(mins) - result * 60;
                    result = (sign ? '+' : '-') + pad(result);
                    result += ':' + pad(mins);
                    break;
                case 'z':
                case 'zz':
                    result = value.getTimezoneOffset() / 60;
                    sign = result < 0;
                    result = Math.abs(result).toString().split('.')[0];
                    result = (sign ? '+' : '-') + (match === 'zz' ? pad(result) : result);
                    break;
                }
                result = result !== undefined ? result : match.slice(1, match.length - 1);
                if (returnsFormat) {
                    result = '' + result;
                    var formatResult = '';
                    if (match == 'ddd') {
                        match = 'EEE';
                    }
                    if (match == 'dddd') {
                        match = 'EEEE';
                    }
                    for (var i = 0; i < result.length; i++) {
                        formatResult += match[0];
                    }
                    return formatResult;
                } else {
                    return result;
                }
            };
            function generateMatcher(retFormat) {
                returnsFormat = retFormat;
                return matcher;
            }
            function setExisting(symbol, val) {
                switch (symbol) {
                case 'y':
                    year = val;
                    break;
                case 'M':
                    month = val;
                    if (!val) {
                        value.setMonth(0);
                        typedMonthPart = '';
                    }
                    break;
                case 'd':
                    date = val;
                    break;
                case 'H':
                case 'h':
                    hours = val;
                    if (!val) {
                        typedDayPeriodPart = '';
                    }
                    break;
                case 'm':
                    minutes = val;
                    break;
                case 's':
                    seconds = val;
                    break;
                default:
                    return;
                }
            }
            this.setValue = function (val) {
                date = val;
            };
            this.getValue = function () {
                return date;
            };
            this.modifyPart = function (symbol, offset) {
                var newValue = new Date(value && value.getTime ? value.getTime() : value);
                switch (symbol) {
                case 'y':
                    newValue.setFullYear(newValue.getFullYear() + offset);
                    break;
                case 'M':
                    var newMonth = newValue.getMonth() + offset;
                    newValue.setMonth(newMonth);
                    if (newValue.getMonth() % 12 !== (newMonth + 12) % 12) {
                        newValue.setDate(1);
                        newValue.setMonth(newMonth);
                    }
                    break;
                case 'd':
                case 'E':
                    newValue.setDate(newValue.getDate() + offset);
                    break;
                case 'H':
                case 'h':
                    newValue.setHours(newValue.getHours() + offset);
                    break;
                case 'm':
                    newValue.setMinutes(newValue.getMinutes() + offset);
                    break;
                case 's':
                    newValue.setSeconds(newValue.getSeconds() + offset);
                    break;
                case 't':
                    newValue.setHours((newValue.getHours() + 12) % 24);
                    break;
                default:
                    break;
                }
                if (newValue.getFullYear() > 0) {
                    setExisting(symbol, true);
                    value = newValue;
                }
            };
            this.parsePart = function (symbol, currentChar) {
                if (!currentChar) {
                    setExisting(symbol, false);
                    return true;
                }
                var newValue = new Date(value && value.getTime ? value.getTime() : value);
                var newHours;
                switch (symbol) {
                case 'd':
                    var newDate = (date ? newValue.getDate() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newDate)) {
                        return;
                    }
                    while (newDate > 31) {
                        newDate = parseInt(newDate.toString().slice(1), 10);
                    }
                    if (newDate < 1) {
                        date = false;
                    } else {
                        newValue.setDate(newDate);
                        if (newValue.getMonth() !== value.getMonth()) {
                            return;
                        }
                        date = true;
                    }
                    break;
                case 'M':
                    var newMonth = (month ? (newValue.getMonth() + 1) * 10 : 0) + parseInt(currentChar, 10);
                    if (!isNaN(newMonth)) {
                        while (newMonth > 12) {
                            newMonth = parseInt(newMonth.toString().slice(1), 10);
                        }
                        if (newMonth < 1) {
                            month = false;
                        } else {
                            newValue.setMonth(newMonth - 1);
                            if (newValue.getMonth() !== newMonth - 1) {
                                newValue.setDate(1);
                                newValue.setMonth(newMonth - 1);
                            }
                            month = true;
                        }
                    } else {
                        var monthNames = calendar.months.names;
                        typedMonthPart += currentChar.toLowerCase();
                        while (typedMonthPart.length > 0) {
                            for (var i = 0; i < monthNames.length; i++) {
                                if (monthNames[i].toLowerCase().indexOf(typedMonthPart) === 0) {
                                    newValue.setMonth(i);
                                    month = true;
                                    value = newValue;
                                    return true;
                                }
                            }
                            typedMonthPart = typedMonthPart.substring(1, typedMonthPart.length);
                        }
                        return false;
                    }
                    break;
                case 'y':
                    var newYear = (year ? newValue.getFullYear() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newYear)) {
                        return;
                    }
                    while (newYear > 9999) {
                        newYear = parseInt(newYear.toString().slice(1), 10);
                    }
                    if (newYear < 1) {
                        year = false;
                    } else {
                        newValue.setFullYear(newYear);
                        year = true;
                    }
                    break;
                case 'h':
                    newHours = (hours ? (newValue.getHours() % 12 || 12) * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newHours)) {
                        return;
                    }
                    while (newHours > 12) {
                        newHours = parseInt(newHours.toString().slice(1), 10);
                    }
                    newValue.setHours(Math.floor(newValue.getHours() / 12) * 12 + newHours % 12);
                    hours = true;
                    break;
                case 'H':
                    newHours = (hours ? newValue.getHours() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newHours)) {
                        return;
                    }
                    while (newHours > 23) {
                        newHours = parseInt(newHours.toString().slice(1), 10);
                    }
                    newValue.setHours(newHours);
                    hours = true;
                    break;
                case 'm':
                    var newMinutes = (minutes ? newValue.getMinutes() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newMinutes)) {
                        return;
                    }
                    while (newMinutes > 59) {
                        newMinutes = parseInt(newMinutes.toString().slice(1), 10);
                    }
                    newValue.setMinutes(newMinutes);
                    minutes = true;
                    break;
                case 's':
                    var newSeconds = (seconds ? newValue.getSeconds() * 10 : 0) + parseInt(currentChar, 10);
                    if (isNaN(newSeconds)) {
                        return;
                    }
                    while (newSeconds > 59) {
                        newSeconds = parseInt(newSeconds.toString().slice(1), 10);
                    }
                    newValue.setSeconds(newSeconds);
                    seconds = true;
                    break;
                case 't':
                    if (hours) {
                        typedDayPeriodPart += currentChar.toLowerCase();
                        while (typedDayPeriodPart.length > 0) {
                            if (calendar.AM[0].toLowerCase().indexOf(typedDayPeriodPart) === 0 && newValue.getHours() >= 12 || calendar.PM[0].toLowerCase().indexOf(typedDayPeriodPart) === 0 && newValue.getHours() < 12) {
                                newValue.setHours((newValue.getHours() + 12) % 24);
                                value = newValue;
                                return true;
                            }
                            typedDayPeriodPart = typedDayPeriodPart.substring(1, typedDayPeriodPart.length);
                        }
                        return false;
                    }
                    break;
                default:
                    break;
                }
                value = newValue;
                return true;
            };
            this.toPair = function (format, culture, messages) {
                if (!format) {
                    return [
                        '',
                        ''
                    ];
                }
                culture = kendo.getCulture(culture);
                calendar = culture.calendars.standard;
                format = calendar.patterns[format] || format;
                days = calendar.days;
                months = calendar.months;
                placeholders = messages;
                return [
                    format.replace(dateFormatRegExp, generateMatcher(false)),
                    format.replace(dateFormatRegExp, generateMatcher(true))
                ];
            };
            this.getDateObject = function () {
                return year && month && date && hours && minutes && seconds && milliseconds ? new Date(value.getTime()) : null;
            };
            if (!initDate) {
                value = new Date();
                var sampleFormat = this.toPair(initFormat, initCulture, initMessages)[1];
                for (var i = 0; i < sampleFormat.length; i++) {
                    setExisting(sampleFormat[i], false);
                }
            } else {
                value = new Date(initDate.getTime());
            }
        };
        function approximateStringMatching(oldText, oldFormat, newText, caret) {
            var oldTextSeparator = oldText[caret + oldText.length - newText.length];
            oldText = oldText.substring(0, caret + oldText.length - newText.length);
            newText = newText.substring(0, caret);
            var diff = [];
            var i;
            if (oldText === newText && caret > 0) {
                diff.push([
                    oldFormat[caret - 1],
                    newText[caret - 1]
                ]);
                return diff;
            }
            if (oldText.indexOf(newText) === 0 && (newText.length === 0 || oldFormat[newText.length - 1] !== oldFormat[newText.length])) {
                var deletedSymbol = '';
                for (i = newText.length; i < oldText.length; i++) {
                    if (oldFormat[i] !== deletedSymbol && knownSymbols.indexOf(oldFormat[i]) >= 0) {
                        deletedSymbol = oldFormat[i];
                        diff.push([
                            deletedSymbol,
                            ''
                        ]);
                    }
                }
                return diff;
            }
            if (newText[newText.length - 1] === ' ' || newText[newText.length - 1] === oldTextSeparator) {
                return [[
                        oldFormat[caret - 1],
                        ' '
                    ]];
            }
            if (newText.indexOf(oldText) === 0 || knownSymbols.indexOf(oldFormat[caret - 1]) === -1) {
                var symbol = oldFormat[0];
                for (i = Math.max(0, oldText.length - 1); i < oldFormat.length; i++) {
                    if (knownSymbols.indexOf(oldFormat[i]) >= 0) {
                        symbol = oldFormat[i];
                        break;
                    }
                }
                return [[
                        symbol,
                        newText[caret - 1]
                    ]];
            }
            return [[
                    oldFormat[caret - 1],
                    newText[caret - 1]
                ]];
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.autocomplete', [
        'kendo.list',
        'kendo.mobile.scroller'
    ], f);
}(function () {
    var __meta__ = {
        id: 'autocomplete',
        name: 'AutoComplete',
        category: 'web',
        description: 'The AutoComplete widget provides suggestions depending on the typed text.It also allows multiple value entries.',
        depends: ['list'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, caret = kendo.caret, activeElement = kendo._activeElement, placeholderSupported = support.placeholder, ui = kendo.ui, List = ui.List, keys = kendo.keys, DataSource = kendo.data.DataSource, ARIA_DISABLED = 'aria-disabled', ARIA_READONLY = 'aria-readonly', CHANGE = 'change', DEFAULT = 'k-state-default', DISABLED = 'disabled', READONLY = 'readonly', FOCUSED = 'k-state-focused', SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', HOVER = 'k-state-hover', ns = '.kendoAutoComplete', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, proxy = $.proxy;
        function indexOfWordAtCaret(caretIdx, text, separator) {
            return separator ? text.substring(0, caretIdx).split(separator).length - 1 : 0;
        }
        function wordAtCaret(caretIdx, text, separator) {
            return text.split(separator)[indexOfWordAtCaret(caretIdx, text, separator)];
        }
        function replaceWordAtCaret(caretIdx, text, word, separator, defaultSeparator) {
            var words = text.split(separator);
            words.splice(indexOfWordAtCaret(caretIdx, text, separator), 1, word);
            if (separator && words[words.length - 1] !== '') {
                words.push('');
            }
            return words.join(defaultSeparator);
        }
        var AutoComplete = List.extend({
            init: function (element, options) {
                var that = this, wrapper, disabled;
                that.ns = ns;
                options = $.isArray(options) ? { dataSource: options } : options;
                List.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.placeholder = options.placeholder || element.attr('placeholder');
                if (placeholderSupported) {
                    element.attr('placeholder', options.placeholder);
                }
                that._wrapper();
                that._loader();
                that._clearButton();
                that._dataSource();
                that._ignoreCase();
                element[0].type = 'text';
                wrapper = that.wrapper;
                that._popup();
                element.addClass('k-input').on('keydown' + ns, proxy(that._keydown, that)).on('keypress' + ns, proxy(that._keypress, that)).on('paste' + ns, proxy(that._search, that)).on('focus' + ns, function () {
                    that._prev = that._accessor();
                    that._oldText = that._prev;
                    that._placeholder(false);
                    wrapper.addClass(FOCUSED);
                }).on('focusout' + ns, function () {
                    that._change();
                    that._placeholder();
                    wrapper.removeClass(FOCUSED);
                }).attr({
                    autocomplete: 'off',
                    role: 'textbox',
                    'aria-haspopup': true
                });
                that._clear.on('click' + ns, proxy(that._clearValue, that));
                that._enable();
                that._old = that._accessor();
                if (element[0].id) {
                    element.attr('aria-owns', that.ul[0].id);
                }
                that._aria();
                that._placeholder();
                that._initList();
                disabled = $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                }
                that.listView.bind('click', function (e) {
                    e.preventDefault();
                });
                that._resetFocusItemHandler = $.proxy(that._resetFocusItem, that);
                kendo.notify(that);
                that._toggleCloseVisibility();
            },
            options: {
                name: 'AutoComplete',
                enabled: true,
                suggest: false,
                template: '',
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#',
                dataTextField: '',
                minLength: 1,
                enforceMinLength: false,
                delay: 200,
                height: 200,
                filter: 'startswith',
                ignoreCase: true,
                highlightFirst: false,
                separator: null,
                placeholder: '',
                animation: {},
                virtual: false,
                value: null,
                clearButton: true
            },
            _dataSource: function () {
                var that = this;
                if (that.dataSource && that._refreshHandler) {
                    that._unbindDataSource();
                } else {
                    that._progressHandler = proxy(that._showBusy, that);
                    that._errorHandler = proxy(that._hideBusy, that);
                }
                that.dataSource = DataSource.create(that.options.dataSource).bind('progress', that._progressHandler).bind('error', that._errorHandler);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                this.listView.setDataSource(this.dataSource);
            },
            events: [
                'open',
                'close',
                CHANGE,
                'select',
                'filtering',
                'dataBinding',
                'dataBound'
            ],
            setOptions: function (options) {
                var listOptions = this._listOptions(options);
                List.fn.setOptions.call(this, options);
                this.listView.setOptions(listOptions);
                this._accessors();
                this._aria();
            },
            _listOptions: function (options) {
                var listOptions = List.fn._listOptions.call(this, $.extend(options, { skipUpdateOnBind: true }));
                listOptions.dataValueField = listOptions.dataTextField;
                listOptions.selectedItemChange = null;
                return listOptions;
            },
            _editable: function (options) {
                var that = this, element = that.element, wrapper = that.wrapper.off(ns), readonly = options.readonly, disable = options.disable;
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    element.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false).attr(ARIA_READONLY, false);
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    element.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable).attr(ARIA_READONLY, readonly);
                }
            },
            close: function () {
                var that = this;
                var current = that.listView.focus();
                if (current) {
                    current.removeClass(SELECTED);
                }
                that.popup.close();
            },
            destroy: function () {
                var that = this;
                that.element.off(ns);
                that._clear.off(ns);
                that.wrapper.off(ns);
                List.fn.destroy.call(that);
            },
            refresh: function () {
                this.listView.refresh();
            },
            select: function (li) {
                this._select(li);
            },
            search: function (word) {
                var that = this, options = that.options, ignoreCase = options.ignoreCase, separator = that._separator(), length;
                word = word || that._accessor();
                clearTimeout(that._typingTimeout);
                if (separator) {
                    word = wordAtCaret(caret(that.element)[0], word, separator);
                }
                length = word.length;
                if (!options.enforceMinLength && !length || length >= options.minLength) {
                    that._open = true;
                    that._mute(function () {
                        this.listView.value([]);
                    });
                    that._filterSource({
                        value: ignoreCase ? word.toLowerCase() : word,
                        operator: options.filter,
                        field: options.dataTextField,
                        ignoreCase: ignoreCase
                    });
                    that.one('close', $.proxy(that._unifySeparators, that));
                }
                that._toggleCloseVisibility();
            },
            suggest: function (word) {
                var that = this, key = that._last, value = that._accessor(), element = that.element[0], caretIdx = caret(element)[0], separator = that._separator(), words = value.split(separator), wordIndex = indexOfWordAtCaret(caretIdx, value, separator), selectionEnd = caretIdx, idx;
                if (key == keys.BACKSPACE || key == keys.DELETE) {
                    that._last = undefined;
                    return;
                }
                word = word || '';
                if (typeof word !== 'string') {
                    if (word[0]) {
                        word = that.dataSource.view()[List.inArray(word[0], that.ul[0])];
                    }
                    word = word ? that._text(word) : '';
                }
                if (caretIdx <= 0) {
                    caretIdx = value.toLowerCase().indexOf(word.toLowerCase()) + 1;
                }
                idx = value.substring(0, caretIdx).lastIndexOf(separator);
                idx = idx > -1 ? caretIdx - (idx + separator.length) : caretIdx;
                value = words[wordIndex].substring(0, idx);
                if (word) {
                    word = word.toString();
                    idx = word.toLowerCase().indexOf(value.toLowerCase());
                    if (idx > -1) {
                        word = word.substring(idx + value.length);
                        selectionEnd = caretIdx + word.length;
                        value += word;
                    }
                    if (separator && words[words.length - 1] !== '') {
                        words.push('');
                    }
                }
                words[wordIndex] = value;
                that._accessor(words.join(separator || ''));
                if (element === activeElement()) {
                    caret(element, caretIdx, selectionEnd);
                }
            },
            value: function (value) {
                if (value !== undefined) {
                    this.listView.value(value);
                    this._accessor(value);
                    this._old = this._accessor();
                    this._oldText = this._accessor();
                } else {
                    return this._accessor();
                }
            },
            _click: function (e) {
                var item = e.item;
                var that = this;
                var element = that.element;
                var dataItem = that.listView.dataItemByIndex(that.listView.getElementIndex(item));
                e.preventDefault();
                that._active = true;
                if (that.trigger('select', {
                        dataItem: dataItem,
                        item: item
                    })) {
                    that.close();
                    return;
                }
                that._oldText = element.val();
                that._select(item).done(function () {
                    that._blur();
                    caret(element, element.val().length);
                });
            },
            _clearText: $.noop,
            _resetFocusItem: function () {
                var index = this.options.highlightFirst ? 0 : -1;
                if (this.options.virtual) {
                    this.listView.scrollTo(0);
                }
                this.listView.focus(index);
            },
            _listBound: function () {
                var that = this;
                var popup = that.popup;
                var options = that.options;
                var data = that.dataSource.flatView();
                var length = data.length;
                var groupsLength = that.dataSource._group.length;
                var isActive = that.element[0] === activeElement();
                var action;
                that._renderFooter();
                that._renderNoData();
                that._toggleNoData(!length);
                that._toggleHeader(!!groupsLength && !!length);
                that._resizePopup();
                popup.position();
                if (length) {
                    if (options.suggest && isActive) {
                        that.suggest(data[0]);
                    }
                }
                if (that._open) {
                    that._open = false;
                    action = that._allowOpening() ? 'open' : 'close';
                    if (that._typingTimeout && !isActive) {
                        action = 'close';
                    }
                    if (length) {
                        that._resetFocusItem();
                        if (options.virtual) {
                            that.popup.unbind('activate', that._resetFocusItemHandler).one('activate', that._resetFocusItemHandler);
                        }
                    }
                    popup[action]();
                    that._typingTimeout = undefined;
                }
                if (that._touchScroller) {
                    that._touchScroller.reset();
                }
                that._hideBusy();
                that._makeUnselectable();
                that.trigger('dataBound');
            },
            _mute: function (callback) {
                this._muted = true;
                callback.call(this);
                this._muted = false;
            },
            _listChange: function () {
                var isActive = this._active || this.element[0] === activeElement();
                if (isActive && !this._muted) {
                    this._selectValue(this.listView.selectedDataItems()[0]);
                }
            },
            _selectValue: function (dataItem) {
                var separator = this._separator();
                var text = '';
                if (dataItem) {
                    text = this._text(dataItem);
                }
                if (text === null) {
                    text = '';
                }
                if (separator) {
                    text = replaceWordAtCaret(caret(this.element)[0], this._accessor(), text, separator, this._defaultSeparator());
                }
                this._prev = text;
                this._accessor(text);
                this._placeholder();
            },
            _unifySeparators: function () {
                this._accessor(this.value().split(this._separator()).join(this._defaultSeparator()));
                return this;
            },
            _change: function () {
                var that = this;
                var value = that._unifySeparators().value();
                var trigger = value !== List.unifyType(that._old, typeof value);
                var valueUpdated = trigger && !that._typing;
                var itemSelected = that._oldText !== value;
                that._old = value;
                that._oldText = value;
                if (valueUpdated || itemSelected) {
                    that.element.trigger(CHANGE);
                }
                if (trigger) {
                    that.trigger(CHANGE);
                }
                that.typing = false;
                that._toggleCloseVisibility();
            },
            _accessor: function (value) {
                var that = this, element = that.element[0];
                if (value !== undefined) {
                    element.value = value === null ? '' : value;
                    that._placeholder();
                } else {
                    value = element.value;
                    if (element.className.indexOf('k-readonly') > -1) {
                        if (value === that.options.placeholder) {
                            return '';
                        } else {
                            return value;
                        }
                    }
                    return value;
                }
            },
            _keydown: function (e) {
                var that = this;
                var key = e.keyCode;
                var listView = that.listView;
                var visible = that.popup.visible();
                var current = listView.focus();
                that._last = key;
                if (key === keys.DOWN) {
                    if (visible) {
                        this._move(current ? 'focusNext' : 'focusFirst');
                    }
                    e.preventDefault();
                } else if (key === keys.UP) {
                    if (visible) {
                        this._move(current ? 'focusPrev' : 'focusLast');
                    }
                    e.preventDefault();
                } else if (key === keys.ENTER || key === keys.TAB) {
                    if (key === keys.ENTER && visible) {
                        e.preventDefault();
                    }
                    if (visible && current) {
                        var dataItem = listView.dataItemByIndex(listView.getElementIndex(current));
                        if (that.trigger('select', {
                                dataItem: dataItem,
                                item: current
                            })) {
                            return;
                        }
                        this._select(current);
                    }
                    this._blur();
                } else if (key === keys.ESC) {
                    if (visible) {
                        e.preventDefault();
                    }
                    that.close();
                } else if (that.popup.visible() && (key === keys.PAGEDOWN || key === keys.PAGEUP)) {
                    e.preventDefault();
                    var direction = key === keys.PAGEDOWN ? 1 : -1;
                    listView.scrollWith(direction * listView.screenHeight());
                } else {
                    that._search();
                }
            },
            _keypress: function () {
                this._oldText = this.element.val();
                this._typing = true;
            },
            _move: function (action) {
                this.listView[action]();
                if (this.options.suggest) {
                    this.suggest(this.listView.focus());
                }
            },
            _hideBusy: function () {
                var that = this;
                clearTimeout(that._busy);
                that._loading.hide();
                that.element.attr('aria-busy', false);
                that._busy = null;
                that._showClear();
            },
            _showBusy: function () {
                var that = this;
                if (that._busy) {
                    return;
                }
                that._busy = setTimeout(function () {
                    that.element.attr('aria-busy', true);
                    that._loading.show();
                    that._hideClear();
                }, 100);
            },
            _placeholder: function (show) {
                if (placeholderSupported) {
                    return;
                }
                var that = this, element = that.element, placeholder = that.options.placeholder, value;
                if (placeholder) {
                    value = element.val();
                    if (show === undefined) {
                        show = !value;
                    }
                    if (!show) {
                        if (value !== placeholder) {
                            placeholder = value;
                        } else {
                            placeholder = '';
                        }
                    }
                    if (value === that._old && !show) {
                        return;
                    }
                    element.toggleClass('k-readonly', show).val(placeholder);
                    if (!placeholder && element[0] === document.activeElement) {
                        caret(element[0], 0, 0);
                    }
                }
            },
            _separator: function () {
                var separator = this.options.separator;
                if (separator instanceof Array) {
                    return new RegExp(separator.join('|'), 'gi');
                }
                return separator;
            },
            _defaultSeparator: function () {
                var separator = this.options.separator;
                if (separator instanceof Array) {
                    return separator[0];
                }
                return separator;
            },
            _inputValue: function () {
                return this.element.val();
            },
            _search: function () {
                var that = this;
                clearTimeout(that._typingTimeout);
                that._typingTimeout = setTimeout(function () {
                    if (that._prev !== that._accessor()) {
                        that._prev = that._accessor();
                        that.search();
                    }
                }, that.options.delay);
            },
            _select: function (candidate) {
                var that = this;
                that._active = true;
                return that.listView.select(candidate).done(function () {
                    that._active = false;
                });
            },
            _loader: function () {
                this._loading = $('<span class="k-icon k-i-loading" style="display:none"></span>').insertAfter(this.element);
            },
            _clearButton: function () {
                this._clear = $('<span unselectable="on" class="k-icon k-clear-value k-i-close" title="clear"></span>').attr({
                    'role': 'button',
                    'tabIndex': -1
                });
                if (this.options.clearButton) {
                    this._clear.insertAfter(this.element);
                }
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _toggleCloseVisibility: function () {
                if (this.value()) {
                    this._showClear();
                } else {
                    this._hideClear();
                }
            },
            _wrapper: function () {
                var that = this, element = that.element, DOMelement = element[0], wrapper;
                wrapper = element.parent();
                if (!wrapper.is('span.k-widget')) {
                    wrapper = element.wrap('<span />').parent();
                }
                wrapper.attr('tabindex', -1);
                wrapper.attr('role', 'presentation');
                wrapper[0].style.cssText = DOMelement.style.cssText;
                element.css({
                    width: '100%',
                    height: DOMelement.style.height
                });
                that._focused = that.element;
                that.wrapper = wrapper.addClass('k-widget k-autocomplete k-header').addClass(DOMelement.className);
            }
        });
        ui.plugin(AutoComplete);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dropdownlist', [
        'kendo.list',
        'kendo.mobile.scroller'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dropdownlist',
        name: 'DropDownList',
        category: 'web',
        description: 'The DropDownList widget displays a list of values and allows the selection of a single value from the list.',
        depends: ['list'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, List = ui.List, Select = ui.Select, support = kendo.support, activeElement = kendo._activeElement, ObservableObject = kendo.data.ObservableObject, keys = kendo.keys, ns = '.kendoDropDownList', DISABLED = 'disabled', READONLY = 'readonly', CHANGE = 'change', FOCUSED = 'k-state-focused', DEFAULT = 'k-state-default', STATEDISABLED = 'k-state-disabled', ARIA_DISABLED = 'aria-disabled', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, TABINDEX = 'tabindex', STATE_FILTER = 'filter', STATE_ACCEPT = 'accept', MSG_INVALID_OPTION_LABEL = 'The `optionLabel` option is not valid due to missing fields. Define a custom optionLabel as shown here http://docs.telerik.com/kendo-ui/api/javascript/ui/dropdownlist#configuration-optionLabel', proxy = $.proxy;
        var DropDownList = Select.extend({
            init: function (element, options) {
                var that = this;
                var index = options && options.index;
                var optionLabel, text, disabled;
                that.ns = ns;
                options = $.isArray(options) ? { dataSource: options } : options;
                Select.fn.init.call(that, element, options);
                options = that.options;
                element = that.element.on('focus' + ns, proxy(that._focusHandler, that));
                that._focusInputHandler = $.proxy(that._focusInput, that);
                that.optionLabel = $();
                that._optionLabel();
                that._inputTemplate();
                that._reset();
                that._prev = '';
                that._word = '';
                that._wrapper();
                that._tabindex();
                that.wrapper.data(TABINDEX, that.wrapper.attr(TABINDEX));
                that._span();
                that._popup();
                that._mobile();
                that._dataSource();
                that._ignoreCase();
                that._filterHeader();
                that._aria();
                that._enable();
                that._oldIndex = that.selectedIndex = -1;
                if (index !== undefined) {
                    options.index = index;
                }
                that._initialIndex = options.index;
                that.requireValueMapper(that.options);
                that._initList();
                that._cascade();
                if (options.autoBind) {
                    that.dataSource.fetch();
                } else if (that.selectedIndex === -1) {
                    text = options.text || '';
                    if (!text) {
                        optionLabel = options.optionLabel;
                        if (optionLabel && options.index === 0) {
                            text = optionLabel;
                        } else if (that._isSelect) {
                            text = element.children(':selected').text();
                        }
                    }
                    that._textAccessor(text);
                }
                disabled = $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                }
                that.listView.bind('click', function (e) {
                    e.preventDefault();
                });
                kendo.notify(that);
            },
            options: {
                name: 'DropDownList',
                enabled: true,
                autoBind: true,
                index: 0,
                text: null,
                value: null,
                delay: 500,
                height: 200,
                dataTextField: '',
                dataValueField: '',
                optionLabel: '',
                cascadeFrom: '',
                cascadeFromField: '',
                ignoreCase: true,
                animation: {},
                filter: 'none',
                minLength: 1,
                enforceMinLength: false,
                virtual: false,
                template: null,
                valueTemplate: null,
                optionLabelTemplate: null,
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#'
            },
            events: [
                'open',
                'close',
                CHANGE,
                'select',
                'filtering',
                'dataBinding',
                'dataBound',
                'cascade',
                'set'
            ],
            setOptions: function (options) {
                Select.fn.setOptions.call(this, options);
                this.listView.setOptions(this._listOptions(options));
                this._optionLabel();
                this._inputTemplate();
                this._accessors();
                this._filterHeader();
                this._enable();
                this._aria();
                if (!this.value() && this.hasOptionLabel()) {
                    this.select(0);
                }
            },
            destroy: function () {
                var that = this;
                Select.fn.destroy.call(that);
                that.wrapper.off(ns);
                that.element.off(ns);
                that._inputWrapper.off(ns);
                that._arrow.off();
                that._arrow = null;
                that._arrowIcon = null;
                that.optionLabel.off();
            },
            open: function () {
                var that = this;
                if (that.popup.visible()) {
                    return;
                }
                if (!that.listView.bound() || that._state === STATE_ACCEPT) {
                    that._open = true;
                    that._state = 'rebind';
                    if (that.filterInput) {
                        that.filterInput.val('');
                        that._prev = '';
                    }
                    if (that.filterInput && that.options.minLength !== 1) {
                        that.refresh();
                        that.popup.one('activate', that._focusInputHandler);
                        that.popup.open();
                        that._resizeFilterInput();
                    } else {
                        that._filterSource();
                    }
                } else if (that._allowOpening()) {
                    that.popup.one('activate', that._focusInputHandler);
                    that.popup.open();
                    that._resizeFilterInput();
                    that._focusItem();
                }
            },
            _focusInput: function () {
                this._focusElement(this.filterInput);
            },
            _resizeFilterInput: function () {
                var filterInput = this.filterInput;
                var originalPrevent = this._prevent;
                if (!filterInput) {
                    return;
                }
                var isInputActive = this.filterInput[0] === activeElement();
                var caret = kendo.caret(this.filterInput[0])[0];
                this._prevent = true;
                filterInput.css('display', 'none').css('width', this.popup.element.css('width')).css('display', 'inline-block');
                if (isInputActive) {
                    filterInput.focus();
                    kendo.caret(filterInput[0], caret);
                }
                this._prevent = originalPrevent;
            },
            _allowOpening: function () {
                return this.hasOptionLabel() || this.filterInput || Select.fn._allowOpening.call(this);
            },
            toggle: function (toggle) {
                this._toggle(toggle, true);
            },
            current: function (candidate) {
                var current;
                if (candidate === undefined) {
                    current = this.listView.focus();
                    if (!current && this.selectedIndex === 0 && this.hasOptionLabel()) {
                        return this.optionLabel;
                    }
                    return current;
                }
                this._focus(candidate);
            },
            dataItem: function (index) {
                var that = this;
                var dataItem = null;
                if (index === null) {
                    return index;
                }
                if (index === undefined) {
                    dataItem = that.listView.selectedDataItems()[0];
                } else {
                    if (typeof index !== 'number') {
                        if (that.options.virtual) {
                            return that.dataSource.getByUid($(index).data('uid'));
                        }
                        if (index.hasClass('k-list-optionlabel')) {
                            index = -1;
                        } else {
                            index = $(that.items()).index(index);
                        }
                    } else if (that.hasOptionLabel()) {
                        index -= 1;
                    }
                    dataItem = that.dataSource.flatView()[index];
                }
                if (!dataItem) {
                    dataItem = that._optionLabelDataItem();
                }
                return dataItem;
            },
            refresh: function () {
                this.listView.refresh();
            },
            text: function (text) {
                var that = this;
                var loweredText;
                var ignoreCase = that.options.ignoreCase;
                text = text === null ? '' : text;
                if (text !== undefined) {
                    if (typeof text !== 'string') {
                        that._textAccessor(text);
                        return;
                    }
                    loweredText = ignoreCase ? text.toLowerCase() : text;
                    that._select(function (data) {
                        data = that._text(data);
                        if (ignoreCase) {
                            data = (data + '').toLowerCase();
                        }
                        return data === loweredText;
                    }).done(function () {
                        that._textAccessor(that.dataItem() || text);
                    });
                } else {
                    return that._textAccessor();
                }
            },
            _clearFilter: function () {
                $(this.filterInput).val('');
                Select.fn._clearFilter.call(this);
            },
            value: function (value) {
                var that = this;
                var listView = that.listView;
                var dataSource = that.dataSource;
                if (value === undefined) {
                    value = that._accessor() || that.listView.value()[0];
                    return value === undefined || value === null ? '' : value;
                }
                that.requireValueMapper(that.options, value);
                if (value || !that.hasOptionLabel()) {
                    that._initialIndex = null;
                }
                this.trigger('set', { value: value });
                if (that._request && that.options.cascadeFrom && that.listView.bound()) {
                    if (that._valueSetter) {
                        dataSource.unbind(CHANGE, that._valueSetter);
                    }
                    that._valueSetter = proxy(function () {
                        that.value(value);
                    }, that);
                    dataSource.one(CHANGE, that._valueSetter);
                    return;
                }
                if (that._isFilterEnabled() && listView.bound() && listView.isFiltered()) {
                    that._clearFilter();
                } else {
                    that._fetchData();
                }
                listView.value(value).done(function () {
                    that._old = that._accessor();
                    that._oldIndex = that.selectedIndex;
                });
            },
            hasOptionLabel: function () {
                return this.optionLabel && !!this.optionLabel[0];
            },
            _optionLabel: function () {
                var that = this;
                var options = that.options;
                var optionLabel = options.optionLabel;
                var template = options.optionLabelTemplate;
                if (!optionLabel) {
                    that.optionLabel.off().remove();
                    that.optionLabel = $();
                    return;
                }
                if (!template) {
                    template = '#:';
                    if (typeof optionLabel === 'string') {
                        template += 'data';
                    } else {
                        template += kendo.expr(options.dataTextField, 'data');
                    }
                    template += '#';
                }
                if (typeof template !== 'function') {
                    template = kendo.template(template);
                }
                that.optionLabelTemplate = template;
                if (!that.hasOptionLabel()) {
                    that.optionLabel = $('<div class="k-list-optionlabel"></div>').prependTo(that.list);
                }
                that.optionLabel.html(template(optionLabel)).off().click(proxy(that._click, that)).on(HOVEREVENTS, that._toggleHover);
                that.angular('compile', function () {
                    return {
                        elements: that.optionLabel,
                        data: [{ dataItem: that._optionLabelDataItem() }]
                    };
                });
            },
            _optionLabelText: function () {
                var optionLabel = this.options.optionLabel;
                return typeof optionLabel === 'string' ? optionLabel : this._text(optionLabel);
            },
            _optionLabelDataItem: function () {
                var that = this;
                var optionLabel = that.options.optionLabel;
                if (that.hasOptionLabel()) {
                    return $.isPlainObject(optionLabel) ? new ObservableObject(optionLabel) : that._assignInstance(that._optionLabelText(), '');
                }
                return null;
            },
            _buildOptions: function (data) {
                var that = this;
                if (!that._isSelect) {
                    return;
                }
                var value = that.listView.value()[0];
                var optionLabel = that._optionLabelDataItem();
                var optionLabelValue = optionLabel && that._value(optionLabel);
                if (value === undefined || value === null) {
                    value = '';
                }
                if (optionLabel) {
                    if (optionLabelValue === undefined || optionLabelValue === null) {
                        optionLabelValue = '';
                    }
                    optionLabel = '<option value="' + optionLabelValue + '">' + that._text(optionLabel) + '</option>';
                }
                that._options(data, optionLabel, value);
                if (value !== List.unifyType(that._accessor(), typeof value)) {
                    that._customOption = null;
                    that._custom(value);
                }
            },
            _listBound: function () {
                var that = this;
                var initialIndex = that._initialIndex;
                var filtered = that._state === STATE_FILTER;
                var data = that.dataSource.flatView();
                var dataItem;
                that._presetValue = false;
                that._renderFooter();
                that._renderNoData();
                that._toggleNoData(!data.length);
                that._resizePopup(true);
                that.popup.position();
                that._buildOptions(data);
                that._makeUnselectable();
                if (!filtered) {
                    if (that._open) {
                        that.toggle(that._allowOpening());
                    }
                    that._open = false;
                    if (!that._fetch) {
                        if (data.length) {
                            if (!that.listView.value().length && initialIndex > -1 && initialIndex !== null) {
                                that.select(initialIndex);
                            }
                            that._initialIndex = null;
                            dataItem = that.listView.selectedDataItems()[0];
                            if (dataItem && that.text() !== that._text(dataItem)) {
                                that._selectValue(dataItem);
                            }
                        } else if (that._textAccessor() !== that._optionLabelText()) {
                            that.listView.value('');
                            that._selectValue(null);
                            that._oldIndex = that.selectedIndex;
                        }
                    }
                }
                that._hideBusy();
                that.trigger('dataBound');
            },
            _listChange: function () {
                this._selectValue(this.listView.selectedDataItems()[0]);
                if (this._presetValue || this._old && this._oldIndex === -1) {
                    this._oldIndex = this.selectedIndex;
                }
            },
            _filterPaste: function () {
                this._search();
            },
            _focusHandler: function () {
                this.wrapper.focus();
            },
            _focusinHandler: function () {
                this._inputWrapper.addClass(FOCUSED);
                this._prevent = false;
            },
            _focusoutHandler: function () {
                var that = this;
                var isIFrame = window.self !== window.top;
                if (!that._prevent) {
                    clearTimeout(that._typingTimeout);
                    if (support.mobileOS.ios && isIFrame) {
                        that._change();
                    } else {
                        that._blur();
                    }
                    that._inputWrapper.removeClass(FOCUSED);
                    that._prevent = true;
                    that._open = false;
                    that.element.blur();
                }
            },
            _wrapperMousedown: function () {
                this._prevent = !!this.filterInput;
            },
            _wrapperClick: function (e) {
                e.preventDefault();
                this.popup.unbind('activate', this._focusInputHandler);
                this._focused = this.wrapper;
                this._toggle();
            },
            _editable: function (options) {
                var that = this;
                var element = that.element;
                var disable = options.disable;
                var readonly = options.readonly;
                var wrapper = that.wrapper.add(that.filterInput).off(ns);
                var dropDownWrapper = that._inputWrapper.off(HOVEREVENTS);
                if (!readonly && !disable) {
                    element.removeAttr(DISABLED).removeAttr(READONLY);
                    dropDownWrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    wrapper.attr(TABINDEX, wrapper.data(TABINDEX)).attr(ARIA_DISABLED, false).on('keydown' + ns, proxy(that._keydown, that)).on('focusin' + ns, proxy(that._focusinHandler, that)).on('focusout' + ns, proxy(that._focusoutHandler, that)).on('mousedown' + ns, proxy(that._wrapperMousedown, that)).on('paste' + ns, proxy(that._filterPaste, that));
                    that.wrapper.on('click' + ns, proxy(that._wrapperClick, that));
                    if (!that.filterInput) {
                        wrapper.on('keypress' + ns, proxy(that._keypress, that));
                    }
                } else if (disable) {
                    wrapper.removeAttr(TABINDEX);
                    dropDownWrapper.addClass(STATEDISABLED).removeClass(DEFAULT);
                } else {
                    dropDownWrapper.addClass(DEFAULT).removeClass(STATEDISABLED);
                    wrapper.on('focusin' + ns, proxy(that._focusinHandler, that)).on('focusout' + ns, proxy(that._focusoutHandler, that));
                }
                element.attr(DISABLED, disable).attr(READONLY, readonly);
                wrapper.attr(ARIA_DISABLED, disable);
            },
            _keydown: function (e) {
                var that = this;
                var key = e.keyCode;
                var altKey = e.altKey;
                var isInputActive;
                var handled;
                var isPopupVisible = that.popup.visible();
                if (that.filterInput) {
                    isInputActive = that.filterInput[0] === activeElement();
                }
                if (key === keys.LEFT) {
                    key = keys.UP;
                    handled = true;
                } else if (key === keys.RIGHT) {
                    key = keys.DOWN;
                    handled = true;
                }
                if (handled && isInputActive) {
                    return;
                }
                e.keyCode = key;
                if (altKey && key === keys.UP || key === keys.ESC) {
                    that._focusElement(that.wrapper);
                }
                if (that._state === STATE_FILTER && key === keys.ESC) {
                    that._clearFilter();
                }
                if (key === keys.ENTER && that._typingTimeout && that.filterInput && isPopupVisible) {
                    e.preventDefault();
                    return;
                }
                handled = that._move(e);
                if (handled) {
                    return;
                }
                if (!isPopupVisible || !that.filterInput) {
                    var current = that._focus();
                    if (key === keys.HOME) {
                        handled = true;
                        that._firstItem();
                    } else if (key === keys.END) {
                        handled = true;
                        that._lastItem();
                    }
                    if (handled) {
                        if (that.trigger('select', {
                                dataItem: that._getElementDataItem(that._focus()),
                                item: that._focus()
                            })) {
                            that._focus(current);
                            return;
                        }
                        that._select(that._focus(), true).done(function () {
                            if (!isPopupVisible) {
                                that._blur();
                            }
                        });
                        e.preventDefault();
                    }
                }
                if (!altKey && !handled && that.filterInput) {
                    that._search();
                }
            },
            _matchText: function (text, word) {
                var ignoreCase = this.options.ignoreCase;
                if (text === undefined || text === null) {
                    return false;
                }
                text = text + '';
                if (ignoreCase) {
                    text = text.toLowerCase();
                }
                return text.indexOf(word) === 0;
            },
            _shuffleData: function (data, splitIndex) {
                var optionDataItem = this._optionLabelDataItem();
                if (optionDataItem) {
                    data = [optionDataItem].concat(data);
                }
                return data.slice(splitIndex).concat(data.slice(0, splitIndex));
            },
            _selectNext: function () {
                var that = this;
                var data = that.dataSource.flatView();
                var dataLength = data.length + (that.hasOptionLabel() ? 1 : 0);
                var isInLoop = sameCharsOnly(that._word, that._last);
                var startIndex = that.selectedIndex;
                var oldFocusedItem;
                var text;
                if (startIndex === -1) {
                    startIndex = 0;
                } else {
                    startIndex += isInLoop ? 1 : 0;
                    startIndex = normalizeIndex(startIndex, dataLength);
                }
                data = data.toJSON ? data.toJSON() : data.slice();
                data = that._shuffleData(data, startIndex);
                for (var idx = 0; idx < dataLength; idx++) {
                    text = that._text(data[idx]);
                    if (isInLoop && that._matchText(text, that._last)) {
                        break;
                    } else if (that._matchText(text, that._word)) {
                        break;
                    }
                }
                if (idx !== dataLength) {
                    oldFocusedItem = that._focus();
                    that._select(normalizeIndex(startIndex + idx, dataLength)).done(function () {
                        var done = function () {
                            if (!that.popup.visible()) {
                                that._change();
                            }
                        };
                        if (that.trigger('select', {
                                dataItem: that._getElementDataItem(that._focus()),
                                item: that._focus()
                            })) {
                            that._select(oldFocusedItem).done(done);
                        } else {
                            done();
                        }
                    });
                }
            },
            _keypress: function (e) {
                var that = this;
                if (e.which === 0 || e.keyCode === kendo.keys.ENTER) {
                    return;
                }
                var character = String.fromCharCode(e.charCode || e.keyCode);
                if (that.options.ignoreCase) {
                    character = character.toLowerCase();
                }
                if (character === ' ') {
                    e.preventDefault();
                }
                that._word += character;
                that._last = character;
                that._search();
            },
            _popupOpen: function () {
                var popup = this.popup;
                popup.wrapper = kendo.wrap(popup.element);
                if (popup.element.closest('.km-root')[0]) {
                    popup.wrapper.addClass('km-popup km-widget');
                    this.wrapper.addClass('km-widget');
                }
            },
            _popup: function () {
                Select.fn._popup.call(this);
                this.popup.one('open', proxy(this._popupOpen, this));
            },
            _getElementDataItem: function (element) {
                if (!element || !element[0]) {
                    return null;
                }
                if (element[0] === this.optionLabel[0]) {
                    return this._optionLabelDataItem();
                }
                return this.listView.dataItemByIndex(this.listView.getElementIndex(element));
            },
            _click: function (e) {
                var that = this;
                var item = e.item || $(e.currentTarget);
                e.preventDefault();
                if (that.trigger('select', {
                        dataItem: that._getElementDataItem(item),
                        item: item
                    })) {
                    that.close();
                    return;
                }
                that._userTriggered = true;
                that._select(item).done(function () {
                    that._focusElement(that.wrapper);
                    that._blur();
                });
            },
            _focusElement: function (element) {
                var active = activeElement();
                var wrapper = this.wrapper;
                var filterInput = this.filterInput;
                var compareElement = element === filterInput ? wrapper : filterInput;
                var touchEnabled = support.mobileOS && (support.touch || support.MSPointers || support.pointers);
                if (filterInput && filterInput[0] === element[0] && touchEnabled) {
                    return;
                }
                if (filterInput && compareElement[0] === active) {
                    this._prevent = true;
                    this._focused = element.focus();
                }
            },
            _searchByWord: function (word) {
                if (!word) {
                    return;
                }
                var that = this;
                var ignoreCase = that.options.ignoreCase;
                if (ignoreCase) {
                    word = word.toLowerCase();
                }
                that._select(function (dataItem) {
                    return that._matchText(that._text(dataItem), word);
                });
            },
            _inputValue: function () {
                return this.text();
            },
            _search: function () {
                var that = this;
                var dataSource = that.dataSource;
                clearTimeout(that._typingTimeout);
                if (that._isFilterEnabled()) {
                    that._typingTimeout = setTimeout(function () {
                        var value = that.filterInput.val();
                        if (that._prev !== value) {
                            that._prev = value;
                            that.search(value);
                            that._resizeFilterInput();
                        }
                        that._typingTimeout = null;
                    }, that.options.delay);
                } else {
                    that._typingTimeout = setTimeout(function () {
                        that._word = '';
                    }, that.options.delay);
                    if (!that.listView.bound()) {
                        dataSource.fetch().done(function () {
                            that._selectNext();
                        });
                        return;
                    }
                    that._selectNext();
                }
            },
            _get: function (candidate) {
                var data, found, idx;
                var isFunction = typeof candidate === 'function';
                var jQueryCandidate = !isFunction ? $(candidate) : $();
                if (this.hasOptionLabel()) {
                    if (typeof candidate === 'number') {
                        if (candidate > -1) {
                            candidate -= 1;
                        }
                    } else if (jQueryCandidate.hasClass('k-list-optionlabel')) {
                        candidate = -1;
                    }
                }
                if (isFunction) {
                    data = this.dataSource.flatView();
                    for (idx = 0; idx < data.length; idx++) {
                        if (candidate(data[idx])) {
                            candidate = idx;
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        candidate = -1;
                    }
                }
                return candidate;
            },
            _firstItem: function () {
                if (this.hasOptionLabel()) {
                    this._focus(this.optionLabel);
                } else {
                    this.listView.focusFirst();
                }
            },
            _lastItem: function () {
                this._resetOptionLabel();
                this.listView.focusLast();
            },
            _nextItem: function () {
                if (this.optionLabel.hasClass('k-state-focused')) {
                    this._resetOptionLabel();
                    this.listView.focusFirst();
                } else {
                    this.listView.focusNext();
                }
            },
            _prevItem: function () {
                if (this.optionLabel.hasClass('k-state-focused')) {
                    return;
                }
                this.listView.focusPrev();
                if (!this.listView.focus()) {
                    this._focus(this.optionLabel);
                }
            },
            _focusItem: function () {
                var options = this.options;
                var listView = this.listView;
                var focusedItem = listView.focus();
                var index = listView.select();
                index = index[index.length - 1];
                if (index === undefined && options.highlightFirst && !focusedItem) {
                    index = 0;
                }
                if (index !== undefined) {
                    listView.focus(index);
                } else {
                    if (options.optionLabel && (!options.virtual || options.virtual.mapValueTo !== 'dataItem')) {
                        this._focus(this.optionLabel);
                        this._select(this.optionLabel);
                    } else {
                        listView.scrollToIndex(0);
                    }
                }
            },
            _resetOptionLabel: function (additionalClass) {
                this.optionLabel.removeClass('k-state-focused' + (additionalClass || '')).removeAttr('id');
            },
            _focus: function (candidate) {
                var listView = this.listView;
                var optionLabel = this.optionLabel;
                if (candidate === undefined) {
                    candidate = listView.focus();
                    if (!candidate && optionLabel.hasClass('k-state-focused')) {
                        candidate = optionLabel;
                    }
                    return candidate;
                }
                this._resetOptionLabel();
                candidate = this._get(candidate);
                listView.focus(candidate);
                if (candidate === -1) {
                    optionLabel.addClass('k-state-focused').attr('id', listView._optionID);
                    this._focused.add(this.filterInput).removeAttr('aria-activedescendant').attr('aria-activedescendant', listView._optionID);
                }
            },
            _select: function (candidate, keepState) {
                var that = this;
                candidate = that._get(candidate);
                return that.listView.select(candidate).done(function () {
                    if (!keepState && that._state === STATE_FILTER) {
                        that._state = STATE_ACCEPT;
                    }
                    if (candidate === -1) {
                        that._selectValue(null);
                    }
                });
            },
            _selectValue: function (dataItem) {
                var that = this;
                var optionLabel = that.options.optionLabel;
                var idx = that.listView.select();
                var value = '';
                var text = '';
                idx = idx[idx.length - 1];
                if (idx === undefined) {
                    idx = -1;
                }
                this._resetOptionLabel(' k-state-selected');
                if (dataItem) {
                    text = dataItem;
                    value = that._dataValue(dataItem);
                    if (optionLabel) {
                        idx += 1;
                    }
                } else if (optionLabel) {
                    that._focus(that.optionLabel.addClass('k-state-selected'));
                    text = that._optionLabelText();
                    if (typeof optionLabel === 'string') {
                        value = '';
                    } else {
                        value = that._value(optionLabel);
                    }
                    idx = 0;
                }
                that.selectedIndex = idx;
                if (value === null) {
                    value = '';
                }
                that._textAccessor(text);
                that._accessor(value, idx);
                that._triggerCascade();
            },
            _mobile: function () {
                var that = this, popup = that.popup, mobileOS = support.mobileOS, root = popup.element.parents('.km-root').eq(0);
                if (root.length && mobileOS) {
                    popup.options.animation.open.effects = mobileOS.android || mobileOS.meego ? 'fadeIn' : mobileOS.ios || mobileOS.wp ? 'slideIn:up' : popup.options.animation.open.effects;
                }
            },
            _filterHeader: function () {
                var icon;
                if (this.filterInput) {
                    this.filterInput.off(ns).parent().remove();
                    this.filterInput = null;
                }
                if (this._isFilterEnabled()) {
                    icon = '<span class="k-icon k-i-zoom"></span>';
                    this.filterInput = $('<input class="k-textbox"/>').attr({
                        placeholder: this.element.attr('placeholder'),
                        title: this.element.attr('title'),
                        role: 'listbox',
                        'aria-haspopup': true,
                        'aria-expanded': false
                    });
                    this.list.prepend($('<span class="k-list-filter" />').append(this.filterInput.add(icon)));
                }
            },
            _span: function () {
                var that = this, wrapper = that.wrapper, SELECTOR = 'span.k-input', span;
                span = wrapper.find(SELECTOR);
                if (!span[0]) {
                    wrapper.append('<span unselectable="on" class="k-dropdown-wrap k-state-default"><span unselectable="on" class="k-input">&nbsp;</span><span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-arrow-60-down"></span></span></span>').append(that.element);
                    span = wrapper.find(SELECTOR);
                }
                that.span = span;
                that._inputWrapper = $(wrapper[0].firstChild);
                that._arrow = wrapper.find('.k-select');
                that._arrowIcon = that._arrow.find('.k-icon');
            },
            _wrapper: function () {
                var that = this, element = that.element, DOMelement = element[0], wrapper;
                wrapper = element.parent();
                if (!wrapper.is('span.k-widget')) {
                    wrapper = element.wrap('<span />').parent();
                    wrapper[0].style.cssText = DOMelement.style.cssText;
                    wrapper[0].title = DOMelement.title;
                }
                that._focused = that.wrapper = wrapper.addClass('k-widget k-dropdown k-header').addClass(DOMelement.className).css('display', '').attr({
                    accesskey: element.attr('accesskey'),
                    unselectable: 'on',
                    role: 'listbox',
                    'aria-haspopup': true,
                    'aria-expanded': false
                });
                element.hide().removeAttr('accesskey');
            },
            _clearSelection: function (parent) {
                this.select(parent.value() ? 0 : -1);
            },
            _inputTemplate: function () {
                var that = this, template = that.options.valueTemplate;
                if (!template) {
                    template = $.proxy(kendo.template('#:this._text(data)#', { useWithBlock: false }), that);
                } else {
                    template = kendo.template(template);
                }
                that.valueTemplate = template;
                if (that.hasOptionLabel() && !that.options.optionLabelTemplate) {
                    try {
                        that.valueTemplate(that._optionLabelDataItem());
                    } catch (e) {
                        throw new Error(MSG_INVALID_OPTION_LABEL);
                    }
                }
            },
            _textAccessor: function (text) {
                var dataItem = null;
                var template = this.valueTemplate;
                var optionLabelText = this._optionLabelText();
                var span = this.span;
                if (text === undefined) {
                    return span.text();
                }
                if ($.isPlainObject(text) || text instanceof ObservableObject) {
                    dataItem = text;
                } else if (optionLabelText && optionLabelText === text) {
                    dataItem = this.options.optionLabel;
                }
                if (!dataItem) {
                    dataItem = this._assignInstance(text, this._accessor());
                }
                if (this.hasOptionLabel()) {
                    if (dataItem === optionLabelText || this._text(dataItem) === optionLabelText) {
                        template = this.optionLabelTemplate;
                        if (typeof this.options.optionLabel === 'string' && !this.options.optionLabelTemplate) {
                            dataItem = optionLabelText;
                        }
                    }
                }
                var getElements = function () {
                    return {
                        elements: span.get(),
                        data: [{ dataItem: dataItem }]
                    };
                };
                this.angular('cleanup', getElements);
                try {
                    span.html(template(dataItem));
                } catch (e) {
                    span.html('');
                }
                this.angular('compile', getElements);
            },
            _preselect: function (value, text) {
                if (!value && !text) {
                    text = this._optionLabelText();
                }
                this._accessor(value);
                this._textAccessor(text);
                this._old = this._accessor();
                this._oldIndex = this.selectedIndex;
                this.listView.setValue(value);
                this._initialIndex = null;
                this._presetValue = true;
            },
            _assignInstance: function (text, value) {
                var dataTextField = this.options.dataTextField;
                var dataItem = {};
                if (dataTextField) {
                    assign(dataItem, dataTextField.split('.'), text);
                    assign(dataItem, this.options.dataValueField.split('.'), value);
                    dataItem = new ObservableObject(dataItem);
                } else {
                    dataItem = text;
                }
                return dataItem;
            }
        });
        function assign(instance, fields, value) {
            var idx = 0, lastIndex = fields.length - 1, field;
            for (; idx < lastIndex; ++idx) {
                field = fields[idx];
                if (!(field in instance)) {
                    instance[field] = {};
                }
                instance = instance[field];
            }
            instance[fields[lastIndex]] = value;
        }
        function normalizeIndex(index, length) {
            if (index >= length) {
                index -= length;
            }
            return index;
        }
        function sameCharsOnly(word, character) {
            for (var idx = 0; idx < word.length; idx++) {
                if (word.charAt(idx) !== character) {
                    return false;
                }
            }
            return true;
        }
        ui.plugin(DropDownList);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.combobox', [
        'kendo.list',
        'kendo.mobile.scroller'
    ], f);
}(function () {
    var __meta__ = {
        id: 'combobox',
        name: 'ComboBox',
        category: 'web',
        description: 'The ComboBox widget allows the selection from pre-defined values or entering a new value.',
        depends: ['list'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, List = ui.List, Select = ui.Select, caret = kendo.caret, support = kendo.support, placeholderSupported = support.placeholder, activeElement = kendo._activeElement, keys = kendo.keys, ns = '.kendoComboBox', CLICK = 'click' + ns, MOUSEDOWN = 'mousedown' + ns, DISABLED = 'disabled', READONLY = 'readonly', CHANGE = 'change', DEFAULT = 'k-state-default', FOCUSED = 'k-state-focused', STATEDISABLED = 'k-state-disabled', ARIA_DISABLED = 'aria-disabled', STATE_FILTER = 'filter', STATE_ACCEPT = 'accept', STATE_REBIND = 'rebind', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, proxy = $.proxy;
        var ComboBox = Select.extend({
            init: function (element, options) {
                var that = this, text, disabled;
                that.ns = ns;
                options = $.isArray(options) ? { dataSource: options } : options;
                Select.fn.init.call(that, element, options);
                options = that.options;
                element = that.element.on('focus' + ns, proxy(that._focusHandler, that));
                options.placeholder = options.placeholder || element.attr('placeholder');
                that._reset();
                that._wrapper();
                that._input();
                that._clearButton();
                that._tabindex(that.input);
                that._popup();
                that._dataSource();
                that._ignoreCase();
                that._enable();
                that._oldIndex = that.selectedIndex = -1;
                that._aria();
                that._initialIndex = options.index;
                that.requireValueMapper(that.options);
                that._initList();
                that._cascade();
                if (options.autoBind) {
                    that._filterSource();
                } else {
                    text = options.text;
                    if (!text && that._isSelect) {
                        text = element.children(':selected').text();
                    }
                    if (text) {
                        that._setText(text);
                    }
                }
                if (!text) {
                    that._placeholder();
                }
                disabled = $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                }
                kendo.notify(that);
                that._toggleCloseVisibility();
            },
            options: {
                name: 'ComboBox',
                enabled: true,
                index: -1,
                text: null,
                value: null,
                autoBind: true,
                delay: 200,
                dataTextField: '',
                dataValueField: '',
                minLength: 1,
                enforceMinLength: false,
                height: 200,
                highlightFirst: true,
                filter: 'none',
                placeholder: '',
                suggest: false,
                cascadeFrom: '',
                cascadeFromField: '',
                ignoreCase: true,
                animation: {},
                virtual: false,
                template: null,
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#',
                clearButton: true,
                syncValueAndText: true
            },
            events: [
                'open',
                'close',
                CHANGE,
                'select',
                'filtering',
                'dataBinding',
                'dataBound',
                'cascade',
                'set'
            ],
            setOptions: function (options) {
                Select.fn.setOptions.call(this, options);
                this.listView.setOptions(options);
                this._accessors();
                this._aria();
            },
            destroy: function () {
                var that = this;
                that.input.off(ns);
                that.element.off(ns);
                that._inputWrapper.off(ns);
                clearTimeout(that._pasteTimeout);
                that._arrow.off(CLICK + ' ' + MOUSEDOWN);
                that._clear.off(CLICK + ' ' + MOUSEDOWN);
                Select.fn.destroy.call(that);
            },
            _change: function () {
                var that = this;
                var text = that.text();
                var hasText = text && text !== that._oldText && text !== that.options.placeholder;
                var index = that.selectedIndex;
                var isCustom = index === -1;
                if (!that.options.syncValueAndText && !that.value() && isCustom && hasText) {
                    that._old = '';
                    that._oldIndex = index;
                    that._oldText = text;
                    if (!that._typing) {
                        that.element.trigger(CHANGE);
                    }
                    that.trigger(CHANGE);
                    that._typing = false;
                    return;
                }
                Select.fn._change.call(that);
                that._toggleCloseVisibility();
            },
            _focusHandler: function () {
                this.input.focus();
            },
            _arrowClick: function () {
                this._toggle();
            },
            _inputFocus: function () {
                this._inputWrapper.addClass(FOCUSED);
                this._placeholder(false);
            },
            _inputFocusout: function () {
                var that = this;
                var value = that.value();
                that._inputWrapper.removeClass(FOCUSED);
                clearTimeout(that._typingTimeout);
                that._typingTimeout = null;
                that.text(that.text());
                var item = that._focus();
                var dataItem = this.listView.dataItemByIndex(this.listView.getElementIndex(item));
                if (value !== that.value() && that.trigger('select', {
                        dataItem: dataItem,
                        item: item
                    })) {
                    that.value(value);
                    return;
                }
                that._placeholder();
                that._blur();
                that.element.blur();
            },
            _inputPaste: function () {
                var that = this;
                clearTimeout(that._pasteTimeout);
                that._pasteTimeout = null;
                that._pasteTimeout = setTimeout(function () {
                    that.search();
                });
            },
            _editable: function (options) {
                var that = this, disable = options.disable, readonly = options.readonly, wrapper = that._inputWrapper.off(ns), input = that.element.add(that.input.off(ns)), arrow = that._arrow.off(CLICK + ' ' + MOUSEDOWN), clear = that._clear;
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    input.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false);
                    arrow.on(CLICK, proxy(that._arrowClick, that)).on(MOUSEDOWN, function (e) {
                        e.preventDefault();
                    });
                    clear.on(CLICK, proxy(that._clearValue, that)).on(MOUSEDOWN, function (e) {
                        e.preventDefault();
                    });
                    that.input.on('keydown' + ns, proxy(that._keydown, that)).on('focus' + ns, proxy(that._inputFocus, that)).on('focusout' + ns, proxy(that._inputFocusout, that)).on('paste' + ns, proxy(that._inputPaste, that));
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    input.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            open: function () {
                var that = this;
                var state = that._state;
                if (that.popup.visible()) {
                    return;
                }
                if (!that.listView.bound() && state !== STATE_FILTER || state === STATE_ACCEPT) {
                    that._open = true;
                    that._state = STATE_REBIND;
                    if (that.options.minLength !== 1) {
                        that.refresh();
                        that._openPopup();
                    } else {
                        that._filterSource();
                    }
                } else if (that._allowOpening()) {
                    that._openPopup();
                    that._focusItem();
                }
            },
            _scrollToFocusedItem: function () {
                var listView = this.listView;
                listView.scrollToIndex(listView.getElementIndex(listView.focus()));
            },
            _openPopup: function () {
                this.popup.one('activate', proxy(this._scrollToFocusedItem, this));
                this.popup.open();
            },
            _updateSelectionState: function () {
                var that = this;
                var text = that.options.text;
                var value = that.options.value;
                if (that.listView.isFiltered()) {
                    return;
                }
                if (that.selectedIndex === -1) {
                    if (text === undefined || text === null) {
                        text = value;
                    }
                    that._accessor(value);
                    that.input.val(text || that.input.val());
                    that._placeholder();
                } else if (that._oldIndex === -1) {
                    that._oldIndex = that.selectedIndex;
                }
            },
            _buildOptions: function (data) {
                var that = this;
                if (!that._isSelect) {
                    return;
                }
                var custom = that._customOption;
                if (that._state === STATE_REBIND) {
                    that._state = '';
                }
                that._customOption = undefined;
                that._options(data, '', that.value());
                if (custom && custom[0].selected) {
                    that._custom(custom.val());
                }
            },
            _updateSelection: function () {
                var that = this;
                var listView = that.listView;
                var initialIndex = that._initialIndex;
                var hasInitialIndex = initialIndex !== null && initialIndex > -1;
                var filtered = that._state === STATE_FILTER;
                if (filtered) {
                    $(listView.focus()).removeClass('k-state-selected');
                    return;
                }
                if (that._fetch) {
                    return;
                }
                if (!listView.value().length) {
                    if (hasInitialIndex) {
                        that.select(initialIndex);
                    } else if (that._accessor()) {
                        listView.value(that._accessor());
                    }
                }
                that._initialIndex = null;
                var dataItem = listView.selectedDataItems()[0];
                if (!dataItem) {
                    return;
                }
                if (that._value(dataItem) !== that.value()) {
                    that._custom(that._value(dataItem));
                }
                if (that.text() && that.text() !== that._text(dataItem)) {
                    that._selectValue(dataItem);
                }
            },
            _updateItemFocus: function () {
                var listView = this.listView;
                if (!this.options.highlightFirst) {
                    listView.focus(-1);
                } else if (!listView.focus() && !listView.focusIndex()) {
                    listView.focus(0);
                }
            },
            _listBound: function () {
                var that = this;
                var isActive = that.input[0] === activeElement();
                var data = that.dataSource.flatView();
                var skip = that.listView.skip();
                var isFirstPage = skip === undefined || skip === 0;
                that._presetValue = false;
                that._renderFooter();
                that._renderNoData();
                that._toggleNoData(!data.length);
                that._resizePopup();
                that.popup.position();
                that._buildOptions(data);
                that._makeUnselectable();
                that._updateSelection();
                if (data.length && isFirstPage) {
                    that._updateItemFocus();
                    if (that.options.suggest && isActive && that.input.val()) {
                        that.suggest(data[0]);
                    }
                }
                if (that._open) {
                    that._open = false;
                    if (that._typingTimeout && !isActive) {
                        that.popup.close();
                    } else {
                        that.toggle(that._allowOpening());
                    }
                    that._typingTimeout = null;
                }
                that._hideBusy();
                that.trigger('dataBound');
            },
            _listChange: function () {
                this._selectValue(this.listView.selectedDataItems()[0]);
                if (this._presetValue) {
                    this._oldIndex = this.selectedIndex;
                }
            },
            _get: function (candidate) {
                var data, found, idx;
                if (typeof candidate === 'function') {
                    data = this.dataSource.flatView();
                    for (idx = 0; idx < data.length; idx++) {
                        if (candidate(data[idx])) {
                            candidate = idx;
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        candidate = -1;
                    }
                }
                return candidate;
            },
            _select: function (candidate, keepState) {
                var that = this;
                candidate = that._get(candidate);
                if (candidate === -1) {
                    that.input[0].value = '';
                    that._accessor('');
                }
                return that.listView.select(candidate).done(function () {
                    if (!keepState && that._state === STATE_FILTER) {
                        that._state = STATE_ACCEPT;
                    }
                });
            },
            _selectValue: function (dataItem) {
                var idx = this.listView.select();
                var value = '';
                var text = '';
                idx = idx[idx.length - 1];
                if (idx === undefined) {
                    idx = -1;
                }
                this.selectedIndex = idx;
                if (idx === -1 && !dataItem) {
                    text = this.input[0].value;
                    if (this.options.syncValueAndText) {
                        value = text;
                    }
                    this.listView.focus(-1);
                } else {
                    if (dataItem) {
                        value = this._dataValue(dataItem);
                        text = this._text(dataItem);
                    }
                    if (value === null) {
                        value = '';
                    }
                }
                this._prev = this.input[0].value = text;
                this._accessor(value !== undefined ? value : text, idx);
                this._placeholder();
                this._triggerCascade();
            },
            refresh: function () {
                this.listView.refresh();
            },
            _toggleCloseVisibility: function () {
                if (this.text()) {
                    this._showClear();
                } else {
                    this._hideClear();
                }
            },
            suggest: function (word) {
                var that = this;
                var element = that.input[0];
                var value = that.text();
                var caretIdx = caret(element)[0];
                var key = that._last;
                var idx;
                if (key == keys.BACKSPACE || key == keys.DELETE) {
                    that._last = undefined;
                    return;
                }
                word = word || '';
                if (typeof word !== 'string') {
                    if (word[0]) {
                        word = that.dataSource.view()[List.inArray(word[0], that.ul[0])];
                    }
                    word = word ? that._text(word) : '';
                }
                if (caretIdx <= 0) {
                    caretIdx = value.toLowerCase().indexOf(word.toLowerCase()) + 1;
                }
                if (word) {
                    word = word.toString();
                    idx = word.toLowerCase().indexOf(value.toLowerCase());
                    if (idx > -1) {
                        value += word.substring(idx + value.length);
                    }
                } else {
                    value = value.substring(0, caretIdx);
                }
                if (value.length !== caretIdx || !word) {
                    element.value = value;
                    if (element === activeElement()) {
                        caret(element, caretIdx, value.length);
                    }
                }
            },
            text: function (text) {
                text = text === null ? '' : text;
                var that = this;
                var input = that.input[0];
                var ignoreCase = that.options.ignoreCase;
                var loweredText = text;
                var dataItem;
                var value;
                if (text === undefined) {
                    return input.value;
                }
                if (that.options.autoBind === false && !that.listView.bound()) {
                    that._setText(text);
                    return;
                }
                dataItem = that.dataItem();
                if (dataItem && that._text(dataItem) === text) {
                    value = that._value(dataItem);
                    if (value === List.unifyType(that._old, typeof value)) {
                        that._triggerCascade();
                        return;
                    }
                }
                if (ignoreCase && !that.listView.value().length) {
                    loweredText = loweredText.toLowerCase();
                }
                that._select(function (data) {
                    data = that._text(data);
                    if (ignoreCase && !that.listView.value().length) {
                        data = (data + '').toLowerCase();
                    }
                    return data === loweredText;
                }).done(function () {
                    if (that.selectedIndex < 0) {
                        input.value = text;
                        if (that.options.syncValueAndText) {
                            that._accessor(text);
                        }
                        that._triggerCascade();
                    }
                    that._prev = input.value;
                });
            },
            toggle: function (toggle) {
                this._toggle(toggle, true);
            },
            value: function (value) {
                var that = this;
                var options = that.options;
                var listView = that.listView;
                if (value === undefined) {
                    value = that._accessor() || that.listView.value()[0];
                    return value === undefined || value === null ? '' : value;
                }
                that.requireValueMapper(that.options, value);
                that.trigger('set', { value: value });
                if (value === options.value && that.input.val() === options.text) {
                    return;
                }
                that._accessor(value);
                if (that._isFilterEnabled() && listView.bound() && listView.isFiltered()) {
                    that._clearFilter();
                } else {
                    that._fetchData();
                }
                listView.value(value).done(function () {
                    if (that.selectedIndex === -1) {
                        that._accessor(value);
                        that.input.val(value);
                        that._placeholder(true);
                    }
                    that._old = that._accessor();
                    that._oldIndex = that.selectedIndex;
                    that._prev = that.input.val();
                    if (that._state === STATE_FILTER) {
                        that._state = STATE_ACCEPT;
                    }
                });
            },
            _click: function (e) {
                var that = this;
                var item = e.item;
                var dataItem = that.listView.dataItemByIndex(that.listView.getElementIndex(item));
                e.preventDefault();
                if (that.trigger('select', {
                        dataItem: dataItem,
                        item: item
                    })) {
                    that.close();
                    return;
                }
                that._userTriggered = true;
                that._select(item).done(function () {
                    that._blur();
                });
            },
            _inputValue: function () {
                return this.text();
            },
            _searchByWord: function (word) {
                var that = this;
                var options = that.options;
                var dataSource = that.dataSource;
                var ignoreCase = options.ignoreCase;
                var predicate = function (dataItem) {
                    var text = that._text(dataItem);
                    if (text !== undefined) {
                        text = text + '';
                        if (text !== '' && word === '') {
                            return false;
                        }
                        if (ignoreCase) {
                            text = text.toLowerCase();
                        }
                        return text.indexOf(word) === 0;
                    }
                };
                if (ignoreCase) {
                    word = word.toLowerCase();
                }
                if (!that.ul[0].firstChild) {
                    dataSource.one(CHANGE, function () {
                        if (dataSource.view()[0]) {
                            that.search(word);
                        }
                    }).fetch();
                    return;
                }
                this.listView.focus(this._get(predicate));
                var current = this.listView.focus();
                if (current) {
                    if (options.suggest) {
                        that.suggest(current);
                    }
                    this.open();
                }
                if (this.options.highlightFirst && !word) {
                    this.listView.focusFirst();
                }
            },
            _input: function () {
                var that = this, element = that.element.removeClass('k-input')[0], accessKey = element.accessKey, wrapper = that.wrapper, SELECTOR = 'input.k-input', name = element.name || '', input, maxLength;
                if (name) {
                    name = 'name="' + name + '_input" ';
                }
                input = wrapper.find(SELECTOR);
                if (!input[0]) {
                    wrapper.append('<span tabindex="-1" unselectable="on" class="k-dropdown-wrap k-state-default"><input ' + name + 'class="k-input" type="text" autocomplete="off"/><span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-arrow-60-down"></span></span></span>').append(that.element);
                    input = wrapper.find(SELECTOR);
                }
                input[0].style.cssText = element.style.cssText;
                input[0].title = element.title;
                maxLength = parseInt(this.element.prop('maxlength') || this.element.attr('maxlength'), 10);
                if (maxLength > -1) {
                    input[0].maxLength = maxLength;
                }
                input.addClass(element.className).css({
                    width: '100%',
                    height: element.style.height
                }).attr({
                    'role': 'combobox',
                    'aria-expanded': false
                }).show();
                if (placeholderSupported) {
                    input.attr('placeholder', that.options.placeholder);
                }
                if (accessKey) {
                    element.accessKey = '';
                    input[0].accessKey = accessKey;
                }
                that._focused = that.input = input;
                that._inputWrapper = $(wrapper[0].firstChild);
                that._arrow = wrapper.find('.k-select').attr({
                    'role': 'button',
                    'tabIndex': -1
                });
                that._arrowIcon = that._arrow.find('.k-icon');
                if (element.id) {
                    that._arrow.attr('aria-controls', that.ul[0].id);
                }
            },
            _clearButton: function () {
                this._clear = $('<span unselectable="on" class="k-icon k-clear-value k-i-close" title="clear"></span>').attr({
                    'role': 'button',
                    'tabIndex': -1
                });
                if (this.options.clearButton) {
                    this._clear.insertAfter(this.input);
                    this.wrapper.addClass('k-combobox-clearable');
                }
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode;
                that._last = key;
                clearTimeout(that._typingTimeout);
                that._typingTimeout = null;
                if (key != keys.TAB && !that._move(e)) {
                    that._search();
                }
            },
            _placeholder: function (show) {
                if (placeholderSupported) {
                    return;
                }
                var that = this, input = that.input, placeholder = that.options.placeholder, value;
                if (placeholder) {
                    value = that.value();
                    if (show === undefined) {
                        show = !value;
                    }
                    input.toggleClass('k-readonly', show);
                    if (!show) {
                        if (!value) {
                            placeholder = '';
                        } else {
                            return;
                        }
                    }
                    input.val(placeholder);
                    if (!placeholder && input[0] === activeElement()) {
                        caret(input[0], 0, 0);
                    }
                }
            },
            _search: function () {
                var that = this;
                that._typingTimeout = setTimeout(function () {
                    var value = that.text();
                    if (that._prev !== value) {
                        that._prev = value;
                        if (that.options.filter === 'none') {
                            that.listView.select(-1);
                        }
                        that.search(value);
                        that._toggleCloseVisibility();
                    }
                    that._typingTimeout = null;
                }, that.options.delay);
            },
            _setText: function (text) {
                this.input.val(text);
                this._prev = text;
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper = element.parent();
                if (!wrapper.is('span.k-widget')) {
                    wrapper = element.hide().wrap('<span />').parent();
                    wrapper[0].style.cssText = element[0].style.cssText;
                }
                that.wrapper = wrapper.addClass('k-widget k-combobox k-header').addClass(element[0].className).css('display', '');
            },
            _clearSelection: function (parent, isFiltered) {
                var that = this;
                var hasValue = parent.value();
                var custom = hasValue && parent.selectedIndex === -1;
                if (this.selectedIndex == -1 && this.value()) {
                    return;
                }
                if (isFiltered || !hasValue || custom) {
                    that.options.value = '';
                    that.value('');
                }
            },
            _preselect: function (value, text) {
                this.input.val(text);
                this._accessor(value);
                this._old = this._accessor();
                this._oldIndex = this.selectedIndex;
                this.listView.setValue(value);
                this._placeholder();
                this._initialIndex = null;
                this._presetValue = true;
            }
        });
        ui.plugin(ComboBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.multiselect', [
        'kendo.list',
        'kendo.mobile.scroller'
    ], f);
}(function () {
    var __meta__ = {
        id: 'multiselect',
        name: 'MultiSelect',
        category: 'web',
        description: 'The MultiSelect widget allows the selection from pre-defined values.',
        depends: ['list'],
        features: [
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            },
            {
                id: 'virtualization',
                name: 'VirtualList',
                description: 'Support for virtualization',
                depends: ['virtuallist']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, List = ui.List, keys = kendo.keys, activeElement = kendo._activeElement, ObservableArray = kendo.data.ObservableArray, proxy = $.proxy, ID = 'id', LI = 'li', ACCEPT = 'accept', FILTER = 'filter', REBIND = 'rebind', OPEN = 'open', CLOSE = 'close', CHANGE = 'change', PROGRESS = 'progress', SELECT = 'select', DESELECT = 'deselect', ARIA_DISABLED = 'aria-disabled', FOCUSEDCLASS = 'k-state-focused', HIDDENCLASS = 'k-hidden', HOVERCLASS = 'k-state-hover', STATEDISABLED = 'k-state-disabled', DISABLED = 'disabled', READONLY = 'readonly', ns = '.kendoMultiSelect', CLICK = 'click' + ns, KEYDOWN = 'keydown' + ns, MOUSEENTER = 'mouseenter' + ns, MOUSELEAVE = 'mouseleave' + ns, HOVEREVENTS = MOUSEENTER + ' ' + MOUSELEAVE, quotRegExp = /"/g, isArray = $.isArray, styles = [
                'font-family',
                'font-size',
                'font-stretch',
                'font-style',
                'font-weight',
                'letter-spacing',
                'text-transform',
                'line-height'
            ];
        var MultiSelect = List.extend({
            init: function (element, options) {
                var that = this, id, disabled;
                that.ns = ns;
                List.fn.init.call(that, element, options);
                that._optionsMap = {};
                that._customOptions = {};
                that._wrapper();
                that._tagList();
                that._input();
                that._textContainer();
                that._loader();
                that._clearButton();
                that._tabindex(that.input);
                element = that.element.attr('multiple', 'multiple').hide();
                options = that.options;
                if (!options.placeholder) {
                    options.placeholder = element.data('placeholder');
                }
                id = element.attr(ID);
                if (id) {
                    that._tagID = id + '_tag_active';
                    id = id + '_taglist';
                    that.tagList.attr(ID, id);
                }
                that._aria(id);
                that._dataSource();
                that._ignoreCase();
                that._popup();
                that._tagTemplate();
                that.requireValueMapper(that.options);
                that._initList();
                that._reset();
                that._enable();
                that._placeholder();
                if (options.autoBind) {
                    that.dataSource.fetch();
                } else if (options.value) {
                    that._preselect(options.value);
                }
                disabled = $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                }
                kendo.notify(that);
                that._toggleCloseVisibility();
            },
            options: {
                name: 'MultiSelect',
                tagMode: 'multiple',
                enabled: true,
                autoBind: true,
                autoClose: true,
                highlightFirst: true,
                dataTextField: '',
                dataValueField: '',
                filter: 'startswith',
                ignoreCase: true,
                minLength: 1,
                enforceMinLength: false,
                delay: 100,
                value: null,
                maxSelectedItems: null,
                placeholder: '',
                height: 200,
                animation: {},
                virtual: false,
                itemTemplate: '',
                tagTemplate: '',
                groupTemplate: '#:data#',
                fixedGroupTemplate: '#:data#',
                clearButton: true
            },
            events: [
                OPEN,
                CLOSE,
                CHANGE,
                SELECT,
                DESELECT,
                'filtering',
                'dataBinding',
                'dataBound'
            ],
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._state = '';
                this._dataSource();
                this.listView.setDataSource(this.dataSource);
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            setOptions: function (options) {
                var listOptions = this._listOptions(options);
                List.fn.setOptions.call(this, options);
                this.listView.setOptions(listOptions);
                this._accessors();
                this._aria(this.tagList.attr(ID));
                this._tagTemplate();
            },
            currentTag: function (candidate) {
                var that = this;
                if (candidate !== undefined) {
                    if (that._currentTag) {
                        that._currentTag.removeClass(FOCUSEDCLASS).removeAttr(ID);
                        that.input.removeAttr('aria-activedescendant');
                    }
                    if (candidate) {
                        candidate.addClass(FOCUSEDCLASS).attr(ID, that._tagID);
                        that.input.attr('aria-activedescendant', that._tagID);
                    }
                    that._currentTag = candidate;
                } else {
                    return that._currentTag;
                }
            },
            dataItems: function () {
                return this.listView.selectedDataItems();
            },
            destroy: function () {
                var that = this, ns = that.ns;
                clearTimeout(that._busy);
                clearTimeout(that._typingTimeout);
                that.wrapper.off(ns);
                that.tagList.off(ns);
                that.input.off(ns);
                that._clear.off(ns);
                List.fn.destroy.call(that);
            },
            _activateItem: function () {
                List.fn._activateItem.call(this);
                this.currentTag(null);
            },
            _listOptions: function (options) {
                var that = this;
                var listOptions = List.fn._listOptions.call(that, $.extend(options, {
                    selectedItemChange: proxy(that._selectedItemChange, that),
                    selectable: 'multiple'
                }));
                var itemTemplate = this.options.itemTemplate || this.options.template;
                var template = listOptions.itemTemplate || itemTemplate || listOptions.template;
                if (!template) {
                    template = '#:' + kendo.expr(listOptions.dataTextField, 'data') + '#';
                }
                listOptions.template = template;
                return listOptions;
            },
            _setListValue: function () {
                List.fn._setListValue.call(this, this._initialValues.slice(0));
            },
            _listChange: function (e) {
                var data = this.dataSource.flatView();
                var optionsMap = this._optionsMap;
                var valueGetter = this._value;
                if (this._state === REBIND) {
                    this._state = '';
                }
                for (var i = 0; i < e.added.length; i++) {
                    if (optionsMap[valueGetter(e.added[i].dataItem)] === undefined) {
                        this._render(data);
                        break;
                    }
                }
                this._selectValue(e.added, e.removed);
            },
            _selectedItemChange: function (e) {
                var items = e.items;
                var context;
                var idx;
                for (idx = 0; idx < items.length; idx++) {
                    context = items[idx];
                    this.tagList.children().eq(context.index).children('span:first').html(this.tagTextTemplate(context.item));
                }
            },
            _wrapperMousedown: function (e) {
                var that = this;
                var notInput = e.target.nodeName.toLowerCase() !== 'input';
                var target = $(e.target);
                var closeButton = target.hasClass('k-select') || target.hasClass('k-icon');
                if (closeButton) {
                    closeButton = !target.closest('.k-select').children('.k-i-arrow-60-down').length;
                }
                if (notInput && !(closeButton && kendo.support.mobileOS)) {
                    e.preventDefault();
                }
                if (!closeButton) {
                    if (that.input[0] !== activeElement() && notInput) {
                        that.input.focus();
                    }
                    if (that.options.minLength === 1) {
                        that.open();
                    }
                }
            },
            _inputFocus: function () {
                this._placeholder(false);
                this.wrapper.addClass(FOCUSEDCLASS);
            },
            _inputFocusout: function () {
                var that = this;
                clearTimeout(that._typingTimeout);
                that.wrapper.removeClass(FOCUSEDCLASS);
                that._placeholder(!that.listView.selectedDataItems()[0], true);
                that.close();
                if (that._state === FILTER) {
                    that._state = ACCEPT;
                    that.listView.skipUpdate(true);
                }
                that.element.blur();
            },
            _removeTag: function (tag) {
                var that = this;
                var state = that._state;
                var position = tag.index();
                var listView = that.listView;
                var value = listView.value()[position];
                var dataItem = that.listView.selectedDataItems()[position];
                var customIndex = that._customOptions[value];
                var option;
                if (that.trigger(DESELECT, {
                        dataItem: dataItem,
                        item: tag
                    })) {
                    that._close();
                    return;
                }
                if (customIndex === undefined && (state === ACCEPT || state === FILTER)) {
                    customIndex = that._optionsMap[value];
                }
                var done = function () {
                    that.currentTag(null);
                    that._change();
                    that._close();
                };
                if (customIndex === undefined) {
                    listView.select(listView.select()[position]).done(done);
                } else {
                    option = that.element[0].children[customIndex];
                    option.selected = false;
                    listView.removeAt(position);
                    tag.remove();
                    done();
                }
            },
            _tagListClick: function (e) {
                var target = $(e.currentTarget);
                if (!target.children('.k-i-arrow-60-down').length) {
                    this._removeTag(target.closest(LI));
                }
            },
            _clearClick: function () {
                var that = this;
                that.tagList.children().each(function (index, tag) {
                    that._removeTag($(tag));
                });
                that.input.val('');
                that._search();
                that.trigger('change');
                that.focus();
            },
            _editable: function (options) {
                var that = this, disable = options.disable, readonly = options.readonly, wrapper = that.wrapper.off(ns), tagList = that.tagList.off(ns), input = that.element.add(that.input.off(ns));
                if (!readonly && !disable) {
                    wrapper.removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover).on('mousedown' + ns + ' touchend' + ns, proxy(that._wrapperMousedown, that));
                    that.input.on(KEYDOWN, proxy(that._keydown, that)).on('paste' + ns, proxy(that._search, that)).on('focus' + ns, proxy(that._inputFocus, that)).on('focusout' + ns, proxy(that._inputFocusout, that));
                    that._clear.on('click' + ns, proxy(that._clearClick, that));
                    input.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false);
                    tagList.on(MOUSEENTER, LI, function () {
                        $(this).addClass(HOVERCLASS);
                    }).on(MOUSELEAVE, LI, function () {
                        $(this).removeClass(HOVERCLASS);
                    }).on(CLICK, 'li.k-button .k-select', proxy(that._tagListClick, that));
                } else {
                    if (disable) {
                        wrapper.addClass(STATEDISABLED);
                    } else {
                        wrapper.removeClass(STATEDISABLED);
                    }
                    input.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            _close: function () {
                var that = this;
                if (that.options.autoClose) {
                    that.close();
                } else {
                    that.popup.position();
                }
            },
            _filterSource: function (filter, force) {
                if (!force) {
                    force = this._retrieveData;
                }
                this._retrieveData = false;
                List.fn._filterSource.call(this, filter, force);
            },
            close: function () {
                this.popup.close();
            },
            open: function () {
                var that = this;
                if (that._request) {
                    that._retrieveData = false;
                }
                if (that._retrieveData || !that.listView.bound() || that._state === ACCEPT) {
                    that._open = true;
                    that._state = REBIND;
                    that.listView.skipUpdate(true);
                    that._filterSource();
                } else if (that._allowOpening()) {
                    that.popup.open();
                    that._focusItem();
                }
            },
            toggle: function (toggle) {
                toggle = toggle !== undefined ? toggle : !this.popup.visible();
                this[toggle ? OPEN : CLOSE]();
            },
            refresh: function () {
                this.listView.refresh();
            },
            _listBound: function () {
                var that = this;
                var data = that.dataSource.flatView();
                var skip = that.listView.skip();
                that._render(data);
                that._renderFooter();
                that._renderNoData();
                that._toggleNoData(!data.length);
                that._resizePopup();
                if (that._open) {
                    that._open = false;
                    that.toggle(that._allowOpening());
                }
                that.popup.position();
                if (that.options.highlightFirst && (skip === undefined || skip === 0)) {
                    that.listView.focusFirst();
                }
                if (that._touchScroller) {
                    that._touchScroller.reset();
                }
                that._hideBusy();
                that._makeUnselectable();
                that.trigger('dataBound');
            },
            _inputValue: function () {
                var that = this;
                var inputValue = that.input.val();
                if (that.options.placeholder === inputValue) {
                    inputValue = '';
                }
                return inputValue;
            },
            value: function (value) {
                var that = this;
                var listView = that.listView;
                var oldValue = listView.value().slice();
                var maxSelectedItems = that.options.maxSelectedItems;
                var clearFilters = listView.bound() && listView.isFiltered();
                if (value === undefined) {
                    return oldValue;
                }
                that.requireValueMapper(that.options, value);
                value = that._normalizeValues(value);
                if (maxSelectedItems !== null && value.length > maxSelectedItems) {
                    value = value.slice(0, maxSelectedItems);
                }
                if (clearFilters) {
                    that._clearFilter();
                }
                listView.value(value);
                that._old = listView.value();
                if (!clearFilters) {
                    that._fetchData();
                }
            },
            _preselect: function (data, value) {
                var that = this;
                if (!isArray(data) && !(data instanceof kendo.data.ObservableArray)) {
                    data = [data];
                }
                if ($.isPlainObject(data[0]) || data[0] instanceof kendo.data.ObservableObject || !that.options.dataValueField) {
                    that.dataSource.data(data);
                    that.value(value || that._initialValues);
                    that._retrieveData = true;
                }
            },
            _setOption: function (value, selected) {
                var option = this.element[0].children[this._optionsMap[value]];
                if (option) {
                    option.selected = selected;
                }
            },
            _fetchData: function () {
                var that = this;
                var hasItems = !!that.dataSource.view().length;
                var isEmptyArray = that.listView.value().length === 0;
                if (isEmptyArray || that._request) {
                    return;
                }
                if (that._retrieveData || !that._fetch && !hasItems) {
                    that._fetch = true;
                    that._retrieveData = false;
                    that.dataSource.read().done(function () {
                        that._fetch = false;
                    });
                }
            },
            _isBound: function () {
                return this.listView.bound() && !this._retrieveData;
            },
            _dataSource: function () {
                var that = this, element = that.element, options = that.options, dataSource = options.dataSource || {};
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                dataSource.select = element;
                dataSource.fields = [
                    { field: options.dataTextField },
                    { field: options.dataValueField }
                ];
                if (that.dataSource && that._refreshHandler) {
                    that._unbindDataSource();
                } else {
                    that._progressHandler = proxy(that._showBusy, that);
                    that._errorHandler = proxy(that._hideBusy, that);
                }
                that.dataSource = kendo.data.DataSource.create(dataSource).bind(PROGRESS, that._progressHandler).bind('error', that._errorHandler);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(that._initialValues);
                            that._placeholder();
                        });
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _initValue: function () {
                var value = this.options.value || this.element.val();
                this._old = this._initialValues = this._normalizeValues(value);
            },
            _normalizeValues: function (value) {
                var that = this;
                if (value === null) {
                    value = [];
                } else if (value && $.isPlainObject(value)) {
                    value = [that._value(value)];
                } else if (value && $.isPlainObject(value[0])) {
                    value = $.map(value, function (dataItem) {
                        return that._value(dataItem);
                    });
                } else if (!isArray(value) && !(value instanceof ObservableArray)) {
                    value = [value];
                } else if (isArray(value)) {
                    value = value.slice();
                }
                return value;
            },
            _change: function () {
                var that = this, value = that.value();
                if (!compare(value, that._old)) {
                    that._old = value.slice();
                    that.trigger(CHANGE);
                    that.element.trigger(CHANGE);
                }
                that._toggleCloseVisibility();
            },
            _click: function (e) {
                var that = this;
                var item = e.item;
                e.preventDefault();
                that._select(item).done(function () {
                    that._change();
                    that._close();
                });
            },
            _keydown: function (e) {
                var that = this;
                var key = e.keyCode;
                var tag = that._currentTag;
                var listView = that.listView;
                var current = listView.focus();
                var hasValue = that.input.val();
                var isRtl = kendo.support.isRtl(that.wrapper);
                var visible = that.popup.visible();
                if (key === keys.DOWN) {
                    e.preventDefault();
                    if (!visible) {
                        that.open();
                        if (!current) {
                            listView.focusFirst();
                        }
                        return;
                    }
                    if (current) {
                        listView.focusNext();
                        if (!listView.focus()) {
                            listView.focusLast();
                        }
                    } else {
                        listView.focusFirst();
                    }
                } else if (key === keys.UP) {
                    if (visible) {
                        if (current) {
                            listView.focusPrev();
                        }
                        if (!listView.focus()) {
                            that.close();
                        }
                    }
                    e.preventDefault();
                } else if (key === keys.LEFT && !isRtl || key === keys.RIGHT && isRtl) {
                    if (!hasValue) {
                        tag = tag ? tag.prev() : $(that.tagList[0].lastChild);
                        if (tag[0]) {
                            that.currentTag(tag);
                        }
                    }
                } else if (key === keys.RIGHT && !isRtl || key === keys.LEFT && isRtl) {
                    if (!hasValue && tag) {
                        tag = tag.next();
                        that.currentTag(tag[0] ? tag : null);
                    }
                } else if (key === keys.ENTER && visible) {
                    that._select(current).done(function () {
                        that._change();
                        that._close();
                    });
                    e.preventDefault();
                } else if (key === keys.ESC) {
                    if (visible) {
                        e.preventDefault();
                    } else {
                        that.currentTag(null);
                    }
                    that.close();
                } else if (key === keys.HOME) {
                    if (visible) {
                        listView.focusFirst();
                    } else if (!hasValue) {
                        tag = that.tagList[0].firstChild;
                        if (tag) {
                            that.currentTag($(tag));
                        }
                    }
                } else if (key === keys.END) {
                    if (visible) {
                        listView.focusLast();
                    } else if (!hasValue) {
                        tag = that.tagList[0].lastChild;
                        if (tag) {
                            that.currentTag($(tag));
                        }
                    }
                } else if ((key === keys.DELETE || key === keys.BACKSPACE) && !hasValue) {
                    if (that.options.tagMode === 'single') {
                        listView.value([]);
                        that._change();
                        that._close();
                        return;
                    }
                    if (key === keys.BACKSPACE && !tag) {
                        tag = $(that.tagList[0].lastChild);
                    }
                    if (tag && tag[0]) {
                        that._removeTag(tag);
                    }
                } else if (that.popup.visible() && (key === keys.PAGEDOWN || key === keys.PAGEUP)) {
                    e.preventDefault();
                    var direction = key === keys.PAGEDOWN ? 1 : -1;
                    listView.scrollWith(direction * listView.screenHeight());
                } else {
                    clearTimeout(that._typingTimeout);
                    setTimeout(function () {
                        that._scale();
                    });
                    that._search();
                }
            },
            _hideBusy: function () {
                var that = this;
                clearTimeout(that._busy);
                that.input.attr('aria-busy', false);
                that._loading.addClass(HIDDENCLASS);
                that._request = false;
                that._busy = null;
                that._showClear();
            },
            _showBusyHandler: function () {
                this.input.attr('aria-busy', true);
                this._loading.removeClass(HIDDENCLASS);
                this._hideClear();
            },
            _showBusy: function () {
                var that = this;
                that._request = true;
                if (that._busy) {
                    return;
                }
                that._busy = setTimeout(proxy(that._showBusyHandler, that), 100);
            },
            _placeholder: function (show, skipCaret) {
                var that = this;
                var input = that.input;
                var active = activeElement();
                var placeholder = that.options.placeholder;
                var inputValue = input.val();
                var isActive = input[0] === active;
                var caretPos = inputValue.length;
                if (!isActive || that.options.autoClose || inputValue === placeholder) {
                    caretPos = 0;
                    inputValue = '';
                }
                if (show === undefined) {
                    show = false;
                    if (input[0] !== active) {
                        show = !that.listView.selectedDataItems()[0];
                    }
                }
                that._prev = inputValue;
                input.toggleClass('k-readonly', show).val(show ? placeholder : inputValue);
                if (isActive && !skipCaret) {
                    kendo.caret(input[0], caretPos, caretPos);
                }
                that._scale();
            },
            _scale: function () {
                var that = this, wrapper = that.wrapper, wrapperWidth = wrapper.width(), span = that._span.text(that.input.val()), textWidth;
                if (!wrapper.is(':visible')) {
                    span.appendTo(document.documentElement);
                    wrapperWidth = textWidth = span.width() + 25;
                    span.appendTo(wrapper);
                } else {
                    textWidth = span.width() + 25;
                }
                that.input.width(textWidth > wrapperWidth ? wrapperWidth : textWidth);
            },
            _option: function (dataValue, dataText, selected) {
                var option = '<option';
                if (dataValue !== undefined) {
                    dataValue += '';
                    if (dataValue.indexOf('"') !== -1) {
                        dataValue = dataValue.replace(quotRegExp, '&quot;');
                    }
                    option += ' value="' + dataValue + '"';
                }
                if (selected) {
                    option += ' selected';
                }
                option += '>';
                if (dataText !== undefined) {
                    option += kendo.htmlEncode(dataText);
                }
                return option += '</option>';
            },
            _render: function (data) {
                var selectedItems = this.listView.selectedDataItems();
                var values = this.listView.value();
                var length = data.length;
                var selectedIndex;
                var options = '';
                var dataItem;
                var value;
                var idx;
                if (values.length !== selectedItems.length) {
                    selectedItems = this._buildSelectedItems(values);
                }
                var custom = {};
                var optionsMap = {};
                for (idx = 0; idx < length; idx++) {
                    dataItem = data[idx];
                    value = this._value(dataItem);
                    selectedIndex = this._selectedItemIndex(value, selectedItems);
                    if (selectedIndex !== -1) {
                        selectedItems.splice(selectedIndex, 1);
                    }
                    optionsMap[value] = idx;
                    options += this._option(value, this._text(dataItem), selectedIndex !== -1);
                }
                if (selectedItems.length) {
                    for (idx = 0; idx < selectedItems.length; idx++) {
                        dataItem = selectedItems[idx];
                        value = this._value(dataItem);
                        custom[value] = length;
                        optionsMap[value] = length;
                        length += 1;
                        options += this._option(value, this._text(dataItem), true);
                    }
                }
                this._customOptions = custom;
                this._optionsMap = optionsMap;
                this.element.html(options);
            },
            _buildSelectedItems: function (values) {
                var valueField = this.options.dataValueField;
                var textField = this.options.dataTextField;
                var result = [];
                var item;
                for (var idx = 0; idx < values.length; idx++) {
                    item = {};
                    item[valueField] = values[idx];
                    item[textField] = values[idx];
                    result.push(item);
                }
                return result;
            },
            _selectedItemIndex: function (value, selectedItems) {
                var valueGetter = this._value;
                var idx = 0;
                for (; idx < selectedItems.length; idx++) {
                    if (value === valueGetter(selectedItems[idx])) {
                        return idx;
                    }
                }
                return -1;
            },
            _search: function () {
                var that = this;
                that._typingTimeout = setTimeout(function () {
                    var value = that._inputValue();
                    if (that._prev !== value) {
                        that._prev = value;
                        that.search(value);
                        that._toggleCloseVisibility();
                    }
                }, that.options.delay);
            },
            _toggleCloseVisibility: function () {
                if (this.value().length || this.input.val() && this.input.val() !== this.options.placeholder) {
                    this._showClear();
                } else {
                    this._hideClear();
                }
            },
            _allowOpening: function () {
                return this._allowSelection() && List.fn._allowOpening.call(this);
            },
            _allowSelection: function () {
                var max = this.options.maxSelectedItems;
                return max === null || max > this.listView.value().length;
            },
            _angularTagItems: function (cmd) {
                var that = this;
                that.angular(cmd, function () {
                    return {
                        elements: that.tagList[0].children,
                        data: $.map(that.dataItems(), function (dataItem) {
                            return { dataItem: dataItem };
                        })
                    };
                });
            },
            _selectValue: function (added, removed) {
                var that = this;
                var values = that.value();
                var total = that.dataSource.total();
                var tagList = that.tagList;
                var getter = that._value;
                var removedItem;
                var addedItem;
                var idx;
                that._angularTagItems('cleanup');
                if (that.options.tagMode === 'multiple') {
                    for (idx = removed.length - 1; idx > -1; idx--) {
                        removedItem = removed[idx];
                        tagList[0].removeChild(tagList[0].children[removedItem.position]);
                        that._setOption(getter(removedItem.dataItem), false);
                    }
                    for (idx = 0; idx < added.length; idx++) {
                        addedItem = added[idx];
                        tagList.append(that.tagTemplate(addedItem.dataItem));
                        that._setOption(getter(addedItem.dataItem), true);
                    }
                } else {
                    if (!that._maxTotal || that._maxTotal < total) {
                        that._maxTotal = total;
                    }
                    tagList.html('');
                    if (values.length) {
                        tagList.append(that.tagTemplate({
                            values: values,
                            dataItems: that.dataItems(),
                            maxTotal: that._maxTotal,
                            currentTotal: total
                        }));
                    }
                    for (idx = removed.length - 1; idx > -1; idx--) {
                        that._setOption(getter(removed[idx].dataItem), false);
                    }
                    for (idx = 0; idx < added.length; idx++) {
                        that._setOption(getter(added[idx].dataItem), true);
                    }
                }
                that._angularTagItems('compile');
                that._placeholder();
            },
            _select: function (candidate) {
                var resolved = $.Deferred().resolve();
                if (!candidate) {
                    return resolved;
                }
                var that = this;
                var listView = that.listView;
                var dataItem = listView.dataItemByIndex(listView.getElementIndex(candidate));
                var isSelected = candidate.hasClass('k-state-selected');
                if (that._state === REBIND) {
                    that._state = '';
                }
                if (!that._allowSelection()) {
                    return resolved;
                }
                if (that.trigger(isSelected ? DESELECT : SELECT, {
                        dataItem: dataItem,
                        item: candidate
                    })) {
                    that._close();
                    return resolved;
                }
                return listView.select(candidate).done(function () {
                    that._placeholder();
                    if (that._state === FILTER) {
                        that._state = ACCEPT;
                        listView.skipUpdate(true);
                    }
                });
            },
            _input: function () {
                var that = this;
                var element = that.element;
                var accessKey = element[0].accessKey;
                var input = that._innerWrapper.children('input.k-input');
                if (!input[0]) {
                    input = $('<input class="k-input" style="width: 25px" />').appendTo(that._innerWrapper);
                }
                element.removeAttr('accesskey');
                that._focused = that.input = input.attr({
                    'accesskey': accessKey,
                    'autocomplete': 'off',
                    'role': 'listbox',
                    'title': element[0].title,
                    'aria-expanded': false
                });
            },
            _tagList: function () {
                var that = this, tagList = that._innerWrapper.children('ul');
                if (!tagList[0]) {
                    tagList = $('<ul role="listbox" deselectable="on" class="k-reset"/>').appendTo(that._innerWrapper);
                }
                that.tagList = tagList;
            },
            _tagTemplate: function () {
                var that = this;
                var options = that.options;
                var tagTemplate = options.tagTemplate;
                var hasDataSource = options.dataSource;
                var isMultiple = options.tagMode === 'multiple';
                var defaultTemplate;
                if (that.element[0].length && !hasDataSource) {
                    options.dataTextField = options.dataTextField || 'text';
                    options.dataValueField = options.dataValueField || 'value';
                }
                defaultTemplate = isMultiple ? kendo.template('#:' + kendo.expr(options.dataTextField, 'data') + '#', { useWithBlock: false }) : kendo.template('#:values.length# item(s) selected');
                that.tagTextTemplate = tagTemplate = tagTemplate ? kendo.template(tagTemplate) : defaultTemplate;
                that.tagTemplate = function (data) {
                    return '<li class="k-button" deselectable="on"><span deselectable="on">' + tagTemplate(data) + '</span><span unselectable="on" aria-label="' + (isMultiple ? 'delete' : 'open') + '" class="k-select"><span class="k-icon ' + (isMultiple ? 'k-i-close' : 'k-i-arrow-60-down') + '">' + '</span></span></li>';
                };
            },
            _loader: function () {
                this._loading = $('<span class="k-icon k-i-loading ' + HIDDENCLASS + '"></span>').insertAfter(this.input);
            },
            _clearButton: function () {
                this._clear = $('<span deselectable="on" class="k-icon k-clear-value k-i-close" title="clear"></span>').attr({
                    'role': 'button',
                    'tabIndex': -1
                });
                if (this.options.clearButton) {
                    this._clear.insertAfter(this.input);
                }
            },
            _textContainer: function () {
                var computedStyles = kendo.getComputedStyles(this.input[0], styles);
                computedStyles.position = 'absolute';
                computedStyles.visibility = 'hidden';
                computedStyles.top = -3333;
                computedStyles.left = -3333;
                this._span = $('<span/>').css(computedStyles).appendTo(this.wrapper);
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper = element.parent('span.k-multiselect');
                if (!wrapper[0]) {
                    wrapper = element.wrap('<div class="k-widget k-multiselect k-header" deselectable="on" />').parent();
                    wrapper[0].style.cssText = element[0].style.cssText;
                    wrapper[0].title = element[0].title;
                    $('<div class="k-multiselect-wrap k-floatwrap" deselectable="on" />').insertBefore(element);
                }
                that.wrapper = wrapper.addClass(element[0].className).css('display', '');
                that._innerWrapper = $(wrapper[0].firstChild);
            }
        });
        function compare(a, b) {
            var length;
            if (a === null && b !== null || a !== null && b === null) {
                return false;
            }
            length = a.length;
            if (length !== b.length) {
                return false;
            }
            while (length--) {
                if (a[length] !== b[length]) {
                    return false;
                }
            }
            return true;
        }
        ui.plugin(MultiSelect);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.slider', ['kendo.draganddrop'], f);
}(function () {
    var __meta__ = {
        id: 'slider',
        name: 'Slider',
        category: 'web',
        description: 'The Slider widget provides a rich input for selecting values or ranges of values.',
        depends: ['draganddrop']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, Draggable = kendo.ui.Draggable, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, extend = $.extend, format = kendo.format, parse = kendo.parseFloat, proxy = $.proxy, isArray = $.isArray, math = Math, support = kendo.support, pointers = support.pointers, msPointers = support.msPointers, CHANGE = 'change', SLIDE = 'slide', NS = '.slider', MOUSE_DOWN = 'touchstart' + NS + ' mousedown' + NS, TRACK_MOUSE_DOWN = pointers ? 'pointerdown' + NS : msPointers ? 'MSPointerDown' + NS : MOUSE_DOWN, MOUSE_UP = 'touchend' + NS + ' mouseup' + NS, TRACK_MOUSE_UP = pointers ? 'pointerup' : msPointers ? 'MSPointerUp' + NS : MOUSE_UP, MOVE_SELECTION = 'moveSelection', KEY_DOWN = 'keydown' + NS, CLICK = 'click' + NS, MOUSE_OVER = 'mouseover' + NS, FOCUS = 'focus' + NS, BLUR = 'blur' + NS, DRAG_HANDLE = '.k-draghandle', TRACK_SELECTOR = '.k-slider-track', TICK_SELECTOR = '.k-tick', STATE_SELECTED = 'k-state-selected', STATE_FOCUSED = 'k-state-focused', STATE_DEFAULT = 'k-state-default', STATE_DISABLED = 'k-state-disabled', DISABLED = 'disabled', UNDEFINED = 'undefined', TABINDEX = 'tabindex', getTouches = kendo.getTouches;
        var SliderBase = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                that._isHorizontal = options.orientation == 'horizontal';
                that._isRtl = that._isHorizontal && kendo.support.isRtl(element);
                that._position = that._isHorizontal ? 'left' : 'bottom';
                that._sizeFn = that._isHorizontal ? 'width' : 'height';
                that._outerSize = that._isHorizontal ? outerWidth : outerHeight;
                options.tooltip.format = options.tooltip.enabled ? options.tooltip.format || '{0}' : '{0}';
                if (options.smallStep <= 0) {
                    throw new Error('Kendo UI Slider smallStep must be a positive number.');
                }
                that._createHtml();
                that.wrapper = that.element.closest('.k-slider');
                that._trackDiv = that.wrapper.find(TRACK_SELECTOR);
                that._setTrackDivWidth();
                that._maxSelection = that._trackDiv[that._sizeFn]();
                that._sliderItemsInit();
                that._reset();
                that._tabindex(that.wrapper.find(DRAG_HANDLE));
                that[options.enabled ? 'enable' : 'disable']();
                var rtlDirectionSign = kendo.support.isRtl(that.wrapper) ? -1 : 1;
                that._keyMap = {
                    37: step(-1 * rtlDirectionSign * options.smallStep),
                    40: step(-options.smallStep),
                    39: step(+1 * rtlDirectionSign * options.smallStep),
                    38: step(+options.smallStep),
                    35: setValue(options.max),
                    36: setValue(options.min),
                    33: step(+options.largeStep),
                    34: step(-options.largeStep)
                };
                kendo.notify(that);
            },
            events: [
                CHANGE,
                SLIDE
            ],
            options: {
                enabled: true,
                min: 0,
                max: 10,
                smallStep: 1,
                largeStep: 5,
                orientation: 'horizontal',
                tickPlacement: 'both',
                tooltip: {
                    enabled: true,
                    format: '{0}'
                }
            },
            _distance: function () {
                return round(this.options.max - this.options.min);
            },
            _resize: function () {
                this._setTrackDivWidth();
                this.wrapper.find('.k-slider-items').remove();
                this._maxSelection = this._trackDiv[this._sizeFn]();
                this._sliderItemsInit();
                this._refresh();
                if (this.options.enabled) {
                    this.enable(true);
                }
            },
            _sliderItemsInit: function () {
                var that = this, options = that.options;
                var sizeBetweenTicks = that._maxSelection / ((options.max - options.min) / options.smallStep);
                var pixelWidths = that._calculateItemsWidth(math.floor(that._distance() / options.smallStep));
                if (options.tickPlacement != 'none' && sizeBetweenTicks >= 2) {
                    $(this.element).parent().find('.k-slider-items').remove();
                    that._trackDiv.before(createSliderItems(options, that._distance()));
                    that._setItemsWidth(pixelWidths);
                    that._setItemsTitle();
                }
                that._calculateSteps(pixelWidths);
                if (options.tickPlacement != 'none' && sizeBetweenTicks >= 2 && options.largeStep >= options.smallStep) {
                    that._setItemsLargeTick();
                }
            },
            getSize: function () {
                return kendo.dimensions(this.wrapper);
            },
            _setTrackDivWidth: function () {
                var that = this, trackDivPosition = parseFloat(that._trackDiv.css(that._isRtl ? 'right' : that._position), 10) * 2;
                that._trackDiv[that._sizeFn](that.wrapper[that._sizeFn]() - 2 - trackDivPosition);
            },
            _setItemsWidth: function (pixelWidths) {
                var that = this, options = that.options, first = 0, last = pixelWidths.length - 1, items = that.wrapper.find(TICK_SELECTOR), i, paddingTop = 0, bordersWidth = 2, count = items.length, selection = 0;
                for (i = 0; i < count - 2; i++) {
                    $(items[i + 1])[that._sizeFn](pixelWidths[i]);
                }
                if (that._isHorizontal) {
                    $(items[first]).addClass('k-first')[that._sizeFn](pixelWidths[last - 1]);
                    $(items[last]).addClass('k-last')[that._sizeFn](pixelWidths[last]);
                } else {
                    $(items[last]).addClass('k-first')[that._sizeFn](pixelWidths[last]);
                    $(items[first]).addClass('k-last')[that._sizeFn](pixelWidths[last - 1]);
                }
                if (that._distance() % options.smallStep !== 0 && !that._isHorizontal) {
                    for (i = 0; i < pixelWidths.length; i++) {
                        selection += pixelWidths[i];
                    }
                    paddingTop = that._maxSelection - selection;
                    paddingTop += parseFloat(that._trackDiv.css(that._position), 10) + bordersWidth;
                    that.wrapper.find('.k-slider-items').css('padding-top', paddingTop);
                }
            },
            _setItemsTitle: function () {
                var that = this, options = that.options, items = that.wrapper.find(TICK_SELECTOR), titleNumber = options.min, count = items.length, i = that._isHorizontal && !that._isRtl ? 0 : count - 1, limit = that._isHorizontal && !that._isRtl ? count : -1, increment = that._isHorizontal && !that._isRtl ? 1 : -1;
                for (; i - limit !== 0; i += increment) {
                    $(items[i]).attr('title', format(options.tooltip.format, round(titleNumber)));
                    titleNumber += options.smallStep;
                }
            },
            _setItemsLargeTick: function () {
                var that = this, options = that.options, items = that.wrapper.find(TICK_SELECTOR), i = 0, item, value;
                if (removeFraction(options.largeStep) % removeFraction(options.smallStep) === 0 || that._distance() / options.largeStep >= 3) {
                    if (!that._isHorizontal && !that._isRtl) {
                        items = $.makeArray(items).reverse();
                    }
                    for (i = 0; i < items.length; i++) {
                        item = $(items[i]);
                        value = that._values[i];
                        var valueWithoutFraction = round(removeFraction(value - this.options.min));
                        if (valueWithoutFraction % removeFraction(options.smallStep) === 0 && valueWithoutFraction % removeFraction(options.largeStep) === 0) {
                            item.addClass('k-tick-large').html('<span class=\'k-label\'>' + item.attr('title') + '</span>');
                            if (i !== 0 && i !== items.length - 1) {
                                item.css('line-height', item[that._sizeFn]() + 'px');
                            }
                        }
                    }
                }
            },
            _calculateItemsWidth: function (itemsCount) {
                var that = this, options = that.options, trackDivSize = parseFloat(that._trackDiv.css(that._sizeFn)) + 1, distance = that._distance(), pixelStep = trackDivSize / distance, itemWidth, pixelWidths, i;
                if (distance / options.smallStep - math.floor(distance / options.smallStep) > 0) {
                    trackDivSize -= distance % options.smallStep * pixelStep;
                }
                itemWidth = trackDivSize / itemsCount;
                pixelWidths = [];
                for (i = 0; i < itemsCount - 1; i++) {
                    pixelWidths[i] = itemWidth;
                }
                pixelWidths[itemsCount - 1] = pixelWidths[itemsCount] = itemWidth / 2;
                return that._roundWidths(pixelWidths);
            },
            _roundWidths: function (pixelWidthsArray) {
                var balance = 0, count = pixelWidthsArray.length, i;
                for (i = 0; i < count; i++) {
                    balance += pixelWidthsArray[i] - math.floor(pixelWidthsArray[i]);
                    pixelWidthsArray[i] = math.floor(pixelWidthsArray[i]);
                }
                balance = math.round(balance);
                return this._addAdditionalSize(balance, pixelWidthsArray);
            },
            _addAdditionalSize: function (additionalSize, pixelWidthsArray) {
                if (additionalSize === 0) {
                    return pixelWidthsArray;
                }
                var step = parseFloat(pixelWidthsArray.length - 1) / parseFloat(additionalSize == 1 ? additionalSize : additionalSize - 1), i;
                for (i = 0; i < additionalSize; i++) {
                    pixelWidthsArray[parseInt(math.round(step * i), 10)] += 1;
                }
                return pixelWidthsArray;
            },
            _calculateSteps: function (pixelWidths) {
                var that = this, options = that.options, val = options.min, selection = 0, distance = that._distance(), itemsCount = math.ceil(distance / options.smallStep), i = 1, lastItem;
                itemsCount += distance / options.smallStep % 1 === 0 ? 1 : 0;
                pixelWidths.splice(0, 0, pixelWidths[itemsCount - 2] * 2);
                pixelWidths.splice(itemsCount - 1, 1, pixelWidths.pop() * 2);
                that._pixelSteps = [selection];
                that._values = [val];
                if (itemsCount === 0) {
                    return;
                }
                while (i < itemsCount) {
                    selection += (pixelWidths[i - 1] + pixelWidths[i]) / 2;
                    that._pixelSteps[i] = selection;
                    val += options.smallStep;
                    that._values[i] = round(val);
                    i++;
                }
                lastItem = distance % options.smallStep === 0 ? itemsCount - 1 : itemsCount;
                that._pixelSteps[lastItem] = that._maxSelection;
                that._values[lastItem] = options.max;
                if (that._isRtl) {
                    that._pixelSteps.reverse();
                    that._values.reverse();
                }
            },
            _getValueFromPosition: function (mousePosition, dragableArea) {
                var that = this, options = that.options, step = math.max(options.smallStep * (that._maxSelection / that._distance()), 0), position = 0, halfStep = step / 2, i;
                if (that._isHorizontal) {
                    position = mousePosition - dragableArea.startPoint;
                    if (that._isRtl) {
                        position = that._maxSelection - position;
                    }
                } else {
                    position = dragableArea.startPoint - mousePosition;
                }
                if (that._maxSelection - (parseInt(that._maxSelection % step, 10) - 3) / 2 < position) {
                    return options.max;
                }
                for (i = 0; i < that._pixelSteps.length; i++) {
                    if (math.abs(that._pixelSteps[i] - position) - 1 <= halfStep) {
                        return round(that._values[i]);
                    }
                }
            },
            _getFormattedValue: function (val, drag) {
                var that = this, html = '', tooltip = that.options.tooltip, tooltipTemplate, selectionStart, selectionEnd;
                if (isArray(val)) {
                    selectionStart = val[0];
                    selectionEnd = val[1];
                } else if (drag && drag.type) {
                    selectionStart = drag.selectionStart;
                    selectionEnd = drag.selectionEnd;
                }
                if (drag) {
                    tooltipTemplate = drag.tooltipTemplate;
                }
                if (!tooltipTemplate && tooltip.template) {
                    tooltipTemplate = kendo.template(tooltip.template);
                }
                if (isArray(val) || drag && drag.type) {
                    if (tooltipTemplate) {
                        html = tooltipTemplate({
                            selectionStart: selectionStart,
                            selectionEnd: selectionEnd
                        });
                    } else {
                        selectionStart = format(tooltip.format, selectionStart);
                        selectionEnd = format(tooltip.format, selectionEnd);
                        html = selectionStart + ' - ' + selectionEnd;
                    }
                } else {
                    if (drag) {
                        drag.val = val;
                    }
                    if (tooltipTemplate) {
                        html = tooltipTemplate({ value: val });
                    } else {
                        html = format(tooltip.format, val);
                    }
                }
                return html;
            },
            _getDraggableArea: function () {
                var that = this, offset = kendo.getOffset(that._trackDiv);
                return {
                    startPoint: that._isHorizontal ? offset.left : offset.top + that._maxSelection,
                    endPoint: that._isHorizontal ? offset.left + that._maxSelection : offset.top
                };
            },
            _createHtml: function () {
                var that = this, element = that.element, options = that.options, inputs = element.find('input');
                if (inputs.length == 2) {
                    inputs.eq(0).prop('value', formatValue(options.selectionStart));
                    inputs.eq(1).prop('value', formatValue(options.selectionEnd));
                } else {
                    element.prop('value', formatValue(options.value));
                }
                element.wrap(createWrapper(options, element, that._isHorizontal)).hide();
                if (options.showButtons) {
                    element.before(createButton(options, 'increase', that._isHorizontal, that._isRtl)).before(createButton(options, 'decrease', that._isHorizontal, that._isRtl));
                }
                element.before(createTrack(options, element));
            },
            _focus: function (e) {
                var that = this, target = e.target, val = that.value(), drag = that._drag;
                if (!drag) {
                    if (target == that.wrapper.find(DRAG_HANDLE).eq(0)[0]) {
                        drag = that._firstHandleDrag;
                        that._activeHandle = 0;
                    } else {
                        drag = that._lastHandleDrag;
                        that._activeHandle = 1;
                    }
                    val = val[that._activeHandle];
                }
                $(target).addClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                if (drag) {
                    that._activeHandleDrag = drag;
                    drag.selectionStart = that.options.selectionStart;
                    drag.selectionEnd = that.options.selectionEnd;
                    drag._updateTooltip(val);
                }
            },
            _focusWithMouse: function (target) {
                target = $(target);
                var that = this, idx = target.is(DRAG_HANDLE) ? target.index() : 0;
                window.setTimeout(function () {
                    that.wrapper.find(DRAG_HANDLE)[idx == 2 ? 1 : 0].focus();
                }, 1);
                that._setTooltipTimeout();
            },
            _blur: function (e) {
                var that = this, drag = that._activeHandleDrag;
                $(e.target).removeClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                if (drag) {
                    drag._removeTooltip();
                    delete that._activeHandleDrag;
                    delete that._activeHandle;
                }
            },
            _setTooltipTimeout: function () {
                var that = this;
                that._tooltipTimeout = window.setTimeout(function () {
                    var drag = that._drag || that._activeHandleDrag;
                    if (drag) {
                        drag._removeTooltip();
                    }
                }, 300);
            },
            _clearTooltipTimeout: function () {
                var that = this;
                window.clearTimeout(this._tooltipTimeout);
                var drag = that._drag || that._activeHandleDrag;
                if (drag && drag.tooltipDiv) {
                    drag.tooltipDiv.stop(true, false).css('opacity', 1);
                }
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._form = form.on('reset', proxy(that._formResetHandler, that));
                }
            },
            min: function (value) {
                if (!value) {
                    return this.options.min;
                }
                this.setOptions({ 'min': value });
            },
            max: function (value) {
                if (!value) {
                    return this.options.max;
                }
                this.setOptions({ 'max': value });
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._sliderItemsInit();
                this._refresh();
            },
            destroy: function () {
                if (this._form) {
                    this._form.off('reset', this._formResetHandler);
                }
                Widget.fn.destroy.call(this);
            }
        });
        function createWrapper(options, element, isHorizontal) {
            var orientationCssClass = isHorizontal ? ' k-slider-horizontal' : ' k-slider-vertical', style = options.style ? options.style : element.attr('style'), cssClasses = element.attr('class') ? ' ' + element.attr('class') : '', tickPlacementCssClass = '';
            if (options.tickPlacement == 'bottomRight') {
                tickPlacementCssClass = ' k-slider-bottomright';
            } else if (options.tickPlacement == 'topLeft') {
                tickPlacementCssClass = ' k-slider-topleft';
            }
            style = style ? ' style=\'' + style + '\'' : '';
            return '<div class=\'k-widget k-slider' + orientationCssClass + cssClasses + '\'' + style + '>' + '<div class=\'k-slider-wrap' + (options.showButtons ? ' k-slider-buttons' : '') + tickPlacementCssClass + '\'></div></div>';
        }
        function createButton(options, type, isHorizontal, isRtl) {
            var buttonCssClass = '';
            if (isHorizontal) {
                if (!isRtl && type == 'increase' || isRtl && type != 'increase') {
                    buttonCssClass = 'k-i-arrow-60-right';
                } else {
                    buttonCssClass = 'k-i-arrow-60-left';
                }
            } else {
                if (type == 'increase') {
                    buttonCssClass = 'k-i-arrow-60-up';
                } else {
                    buttonCssClass = 'k-i-arrow-60-down';
                }
            }
            return '<a class=\'k-button k-button-' + type + '\' ' + 'title=\'' + options[type + 'ButtonTitle'] + '\' ' + 'aria-label=\'' + options[type + 'ButtonTitle'] + '\'>' + '<span class=\'k-icon ' + buttonCssClass + '\'></span></a>';
        }
        function createSliderItems(options, distance) {
            var result = '<ul class=\'k-reset k-slider-items\'>', count = math.floor(round(distance / options.smallStep)) + 1, i;
            for (i = 0; i < count; i++) {
                result += '<li class=\'k-tick\' role=\'presentation\'>&nbsp;</li>';
            }
            result += '</ul>';
            return result;
        }
        function createTrack(options, element) {
            var dragHandleCount = element.is('input') ? 1 : 2, firstDragHandleTitle = dragHandleCount == 2 ? options.leftDragHandleTitle : options.dragHandleTitle;
            return '<div class=\'k-slider-track\'><div class=\'k-slider-selection\'><!-- --></div>' + '<a href=\'#\' class=\'k-draghandle\' title=\'' + firstDragHandleTitle + '\' role=\'slider\' aria-valuemin=\'' + options.min + '\' aria-valuemax=\'' + options.max + '\' aria-valuenow=\'' + (dragHandleCount > 1 ? options.selectionStart || options.min : options.value || options.min) + '\'>Drag</a>' + (dragHandleCount > 1 ? '<a href=\'#\' class=\'k-draghandle\' title=\'' + options.rightDragHandleTitle + '\'role=\'slider\' aria-valuemin=\'' + options.min + '\' aria-valuemax=\'' + options.max + '\' aria-valuenow=\'' + (options.selectionEnd || options.max) + '\'>Drag</a>' : '') + '</div>';
        }
        function step(stepValue) {
            return function (value) {
                return value + stepValue;
            };
        }
        function setValue(value) {
            return function () {
                return value;
            };
        }
        function formatValue(value) {
            return (value + '').replace('.', kendo.cultures.current.numberFormat['.']);
        }
        function calculatePrecision(value) {
            var number = value.toString();
            var precision = 0;
            number = number.split('.');
            if (number[1]) {
                precision = number[1].length;
            }
            precision = precision > 10 ? 10 : precision;
            return precision;
        }
        function round(value) {
            var precision, power;
            value = parseFloat(value, 10);
            precision = calculatePrecision(value);
            power = math.pow(10, precision || 0);
            return math.round(value * power) / power;
        }
        function parseAttr(element, name) {
            var value = parse(element.getAttribute(name));
            if (value === null) {
                value = undefined;
            }
            return value;
        }
        function defined(value) {
            return typeof value !== UNDEFINED;
        }
        function removeFraction(value) {
            return value * 10000;
        }
        var Slider = SliderBase.extend({
            init: function (element, options) {
                var that = this, dragHandle;
                element.type = 'text';
                options = extend({}, {
                    value: parseAttr(element, 'value'),
                    min: parseAttr(element, 'min'),
                    max: parseAttr(element, 'max'),
                    smallStep: parseAttr(element, 'step')
                }, options);
                element = $(element);
                if (options && options.enabled === undefined) {
                    options.enabled = !element.is('[disabled]');
                }
                SliderBase.fn.init.call(that, element, options);
                options = that.options;
                if (!defined(options.value) || options.value === null) {
                    options.value = options.min;
                    element.prop('value', formatValue(options.min));
                }
                options.value = math.max(math.min(options.value, options.max), options.min);
                dragHandle = that.wrapper.find(DRAG_HANDLE);
                this._selection = new Slider.Selection(dragHandle, that, options);
                that._drag = new Slider.Drag(dragHandle, '', that, options);
            },
            options: {
                name: 'Slider',
                showButtons: true,
                increaseButtonTitle: 'Increase',
                decreaseButtonTitle: 'Decrease',
                dragHandleTitle: 'drag',
                tooltip: { format: '{0:#,#.##}' },
                value: null
            },
            enable: function (enable) {
                var that = this, options = that.options, clickHandler, move;
                that.disable();
                if (enable === false) {
                    return;
                }
                that.wrapper.removeClass(STATE_DISABLED).addClass(STATE_DEFAULT);
                that.wrapper.find('input').removeAttr(DISABLED);
                clickHandler = function (e) {
                    var touch = getTouches(e)[0];
                    if (!touch) {
                        return;
                    }
                    var mousePosition = that._isHorizontal ? touch.location.pageX : touch.location.pageY, dragableArea = that._getDraggableArea(), target = $(e.target);
                    if (target.hasClass('k-draghandle')) {
                        target.addClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                        return;
                    }
                    that._update(that._getValueFromPosition(mousePosition, dragableArea));
                    that._focusWithMouse(e.target);
                    that._drag.dragstart(e);
                    e.preventDefault();
                };
                that.wrapper.find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).on(TRACK_MOUSE_DOWN, clickHandler).end().on(TRACK_MOUSE_DOWN, function () {
                    $(document.documentElement).one('selectstart', kendo.preventDefault);
                }).on(TRACK_MOUSE_UP, function () {
                    that._drag._end();
                });
                that.wrapper.find(DRAG_HANDLE).attr(TABINDEX, 0).on(MOUSE_UP, function () {
                    that._setTooltipTimeout();
                }).on(CLICK, function (e) {
                    that._focusWithMouse(e.target);
                    e.preventDefault();
                }).on(FOCUS, proxy(that._focus, that)).on(BLUR, proxy(that._blur, that));
                move = proxy(function (sign) {
                    var newVal = that._nextValueByIndex(that._valueIndex + sign * 1);
                    that._setValueInRange(newVal);
                    that._drag._updateTooltip(newVal);
                }, that);
                if (options.showButtons) {
                    var mouseDownHandler = proxy(function (e, sign) {
                        this._clearTooltipTimeout();
                        if (e.which === 1 || support.touch && e.which === 0) {
                            move(sign);
                            this.timeout = setTimeout(proxy(function () {
                                this.timer = setInterval(function () {
                                    move(sign);
                                }, 60);
                            }, this), 200);
                        }
                    }, that);
                    that.wrapper.find('.k-button').on(MOUSE_UP, proxy(function (e) {
                        this._clearTimer();
                        that._focusWithMouse(e.target);
                    }, that)).on(MOUSE_OVER, function (e) {
                        $(e.currentTarget).addClass('k-state-hover');
                    }).on('mouseout' + NS, proxy(function (e) {
                        $(e.currentTarget).removeClass('k-state-hover');
                        this._clearTimer();
                    }, that)).eq(0).on(MOUSE_DOWN, proxy(function (e) {
                        mouseDownHandler(e, 1);
                    }, that)).click(false).end().eq(1).on(MOUSE_DOWN, proxy(function (e) {
                        mouseDownHandler(e, -1);
                    }, that)).click(kendo.preventDefault);
                }
                that.wrapper.find(DRAG_HANDLE).off(KEY_DOWN, false).on(KEY_DOWN, proxy(this._keydown, that));
                options.enabled = true;
            },
            disable: function () {
                var that = this;
                that.wrapper.removeClass(STATE_DEFAULT).addClass(STATE_DISABLED);
                $(that.element).prop(DISABLED, DISABLED);
                that.wrapper.find('.k-button').off(MOUSE_DOWN).on(MOUSE_DOWN, function (e) {
                    e.preventDefault();
                    $(this).addClass('k-state-active');
                }).off(MOUSE_UP).on(MOUSE_UP, function (e) {
                    e.preventDefault();
                    $(this).removeClass('k-state-active');
                }).off('mouseleave' + NS).on('mouseleave' + NS, kendo.preventDefault).off(MOUSE_OVER).on(MOUSE_OVER, kendo.preventDefault);
                that.wrapper.find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).off(TRACK_MOUSE_DOWN).off(TRACK_MOUSE_UP);
                that.wrapper.find(DRAG_HANDLE).attr(TABINDEX, -1).off(MOUSE_UP).off(KEY_DOWN).off(CLICK).off(FOCUS).off(BLUR);
                that.options.enabled = false;
            },
            _update: function (val) {
                var that = this, change = that.value() != val;
                that.value(val);
                if (change) {
                    that.trigger(CHANGE, { value: that.options.value });
                }
            },
            value: function (value) {
                var that = this, options = that.options;
                value = round(value);
                if (isNaN(value)) {
                    return options.value;
                }
                if (value >= options.min && value <= options.max) {
                    if (options.value != value) {
                        that.element.prop('value', formatValue(value));
                        options.value = value;
                        that._refreshAriaAttr(value);
                        that._refresh();
                    }
                }
            },
            _refresh: function () {
                this.trigger(MOVE_SELECTION, { value: this.options.value });
            },
            _refreshAriaAttr: function (value) {
                var that = this, drag = that._drag, formattedValue;
                if (drag && drag._tooltipDiv) {
                    formattedValue = drag._tooltipDiv.text();
                } else {
                    formattedValue = that._getFormattedValue(value, null);
                }
                this.wrapper.find(DRAG_HANDLE).attr('aria-valuenow', value).attr('aria-valuetext', formattedValue);
            },
            _clearTimer: function () {
                clearTimeout(this.timeout);
                clearInterval(this.timer);
            },
            _keydown: function (e) {
                var that = this;
                if (e.keyCode in that._keyMap) {
                    that._clearTooltipTimeout();
                    that._setValueInRange(that._keyMap[e.keyCode](that.options.value));
                    that._drag._updateTooltip(that.value());
                    e.preventDefault();
                }
            },
            _setValueInRange: function (val) {
                var that = this, options = that.options;
                val = round(val);
                if (isNaN(val)) {
                    that._update(options.min);
                    return;
                }
                val = math.max(math.min(val, options.max), options.min);
                that._update(val);
            },
            _nextValueByIndex: function (index) {
                var count = this._values.length;
                if (this._isRtl) {
                    index = count - 1 - index;
                }
                return this._values[math.max(0, math.min(index, count - 1))];
            },
            _formResetHandler: function () {
                var that = this, min = that.options.min;
                setTimeout(function () {
                    var value = that.element[0].value;
                    that.value(value === '' || isNaN(value) ? min : value);
                });
            },
            destroy: function () {
                var that = this;
                SliderBase.fn.destroy.call(that);
                that.wrapper.off(NS).find('.k-button').off(NS).end().find(DRAG_HANDLE).off(NS).end().find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).off(NS).end();
                that._drag.draggable.destroy();
                that._drag._removeTooltip(true);
            }
        });
        Slider.Selection = function (dragHandle, that, options) {
            function moveSelection(val) {
                var selectionValue = val - options.min, index = that._valueIndex = math.ceil(round(selectionValue / options.smallStep)), selection = parseInt(that._pixelSteps[index], 10), selectionDiv = that._trackDiv.find('.k-slider-selection'), halfDragHanndle = parseInt(that._outerSize(dragHandle) / 2, 10), rtlCorrection = that._isRtl ? 2 : 0;
                selectionDiv[that._sizeFn](that._isRtl ? that._maxSelection - selection : selection);
                dragHandle.css(that._position, selection - halfDragHanndle - rtlCorrection);
            }
            moveSelection(options.value);
            that.bind([
                SLIDE,
                MOVE_SELECTION
            ], function (e) {
                moveSelection(parseFloat(e.value, 10));
            });
            that.bind(CHANGE, function (e) {
                moveSelection(parseFloat(e.sender.value(), 10));
            });
        };
        Slider.Drag = function (element, type, owner, options) {
            var that = this;
            that.owner = owner;
            that.options = options;
            that.element = element;
            that.type = type;
            that.draggable = new Draggable(element, {
                distance: 0,
                dragstart: proxy(that._dragstart, that),
                drag: proxy(that.drag, that),
                dragend: proxy(that.dragend, that),
                dragcancel: proxy(that.dragcancel, that)
            });
            element.click(false);
        };
        Slider.Drag.prototype = {
            dragstart: function (e) {
                this.owner._activeDragHandle = this;
                this.draggable.userEvents.cancel();
                this._dragstart(e);
                this.dragend();
            },
            _dragstart: function (e) {
                var that = this, owner = that.owner, options = that.options;
                if (!options.enabled) {
                    e.preventDefault();
                    return;
                }
                this.owner._activeDragHandle = this;
                owner.element.off(MOUSE_OVER);
                owner.wrapper.find('.' + STATE_FOCUSED).removeClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                that.element.addClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                $(document.documentElement).css('cursor', 'pointer');
                that.dragableArea = owner._getDraggableArea();
                that.step = math.max(options.smallStep * (owner._maxSelection / owner._distance()), 0);
                if (that.type) {
                    that.selectionStart = options.selectionStart;
                    that.selectionEnd = options.selectionEnd;
                    owner._setZIndex(that.type);
                } else {
                    that.oldVal = that.val = options.value;
                }
                that._removeTooltip(true);
                that._createTooltip();
            },
            _createTooltip: function () {
                var that = this, owner = that.owner, tooltip = that.options.tooltip, html = '', wnd = $(window), tooltipTemplate, colloutCssClass;
                if (!tooltip.enabled) {
                    return;
                }
                if (tooltip.template) {
                    tooltipTemplate = that.tooltipTemplate = kendo.template(tooltip.template);
                }
                $('.k-slider-tooltip').remove();
                that.tooltipDiv = $('<div class=\'k-widget k-tooltip k-slider-tooltip\'><!-- --></div>').appendTo(document.body);
                html = owner._getFormattedValue(that.val || owner.value(), that);
                if (!that.type) {
                    colloutCssClass = 'k-callout-' + (owner._isHorizontal ? 's' : 'e');
                    that.tooltipInnerDiv = '<div class=\'k-callout ' + colloutCssClass + '\'><!-- --></div>';
                    html += that.tooltipInnerDiv;
                }
                that.tooltipDiv.html(html);
                that._scrollOffset = {
                    top: wnd.scrollTop(),
                    left: wnd.scrollLeft()
                };
                that.moveTooltip();
            },
            drag: function (e) {
                var that = this, owner = that.owner, x = e.x.location, y = e.y.location, startPoint = that.dragableArea.startPoint, endPoint = that.dragableArea.endPoint, slideParams;
                e.preventDefault();
                if (owner._isHorizontal) {
                    if (owner._isRtl) {
                        that.val = that.constrainValue(x, startPoint, endPoint, x < endPoint);
                    } else {
                        that.val = that.constrainValue(x, startPoint, endPoint, x >= endPoint);
                    }
                } else {
                    that.val = that.constrainValue(y, endPoint, startPoint, y <= endPoint);
                }
                if (that.oldVal != that.val) {
                    that.oldVal = that.val;
                    if (that.type) {
                        if (that.type == 'firstHandle') {
                            if (that.val < that.selectionEnd) {
                                that.selectionStart = that.val;
                            } else {
                                that.selectionStart = that.selectionEnd = that.val;
                            }
                        } else {
                            if (that.val > that.selectionStart) {
                                that.selectionEnd = that.val;
                            } else {
                                that.selectionStart = that.selectionEnd = that.val;
                            }
                        }
                        slideParams = {
                            values: [
                                that.selectionStart,
                                that.selectionEnd
                            ],
                            value: [
                                that.selectionStart,
                                that.selectionEnd
                            ]
                        };
                    } else {
                        slideParams = { value: that.val };
                    }
                    owner.trigger(SLIDE, slideParams);
                }
                that._updateTooltip(that.val);
            },
            _updateTooltip: function (val) {
                var that = this, options = that.options, tooltip = options.tooltip, html = '';
                if (!tooltip.enabled) {
                    return;
                }
                if (!that.tooltipDiv) {
                    that._createTooltip();
                }
                html = that.owner._getFormattedValue(round(val), that);
                if (!that.type) {
                    html += that.tooltipInnerDiv;
                }
                that.tooltipDiv.html(html);
                that.moveTooltip();
            },
            dragcancel: function () {
                this.owner._refresh();
                $(document.documentElement).css('cursor', '');
                return this._end();
            },
            dragend: function () {
                var that = this, owner = that.owner;
                $(document.documentElement).css('cursor', '');
                if (that.type) {
                    owner._update(that.selectionStart, that.selectionEnd);
                } else {
                    owner._update(that.val);
                    that.draggable.userEvents._disposeAll();
                }
                that.draggable.userEvents.cancel();
                return that._end();
            },
            _end: function () {
                var that = this, owner = that.owner;
                owner._focusWithMouse(that.element);
                owner.element.on(MOUSE_OVER);
                return false;
            },
            _removeTooltip: function (noAnimation) {
                var that = this, owner = that.owner;
                if (that.tooltipDiv && owner.options.tooltip.enabled && owner.options.enabled) {
                    if (noAnimation) {
                        that.tooltipDiv.remove();
                        that.tooltipDiv = null;
                    } else {
                        that.tooltipDiv.fadeOut('slow', function () {
                            $(this).remove();
                            that.tooltipDiv = null;
                        });
                    }
                }
            },
            moveTooltip: function () {
                var that = this, owner = that.owner, top = 0, left = 0, element = that.element, offset = kendo.getOffset(element), margin = 8, viewport = $(window), callout = that.tooltipDiv.find('.k-callout'), width = outerWidth(that.tooltipDiv), height = outerHeight(that.tooltipDiv), dragHandles, sdhOffset, diff, anchorSize;
                if (that.type) {
                    dragHandles = owner.wrapper.find(DRAG_HANDLE);
                    offset = kendo.getOffset(dragHandles.eq(0));
                    sdhOffset = kendo.getOffset(dragHandles.eq(1));
                    if (owner._isHorizontal) {
                        top = sdhOffset.top;
                        left = offset.left + (sdhOffset.left - offset.left) / 2;
                    } else {
                        top = offset.top + (sdhOffset.top - offset.top) / 2;
                        left = sdhOffset.left;
                    }
                    anchorSize = outerWidth(dragHandles.eq(0)) + 2 * margin;
                } else {
                    top = offset.top;
                    left = offset.left;
                    anchorSize = outerWidth(element) + 2 * margin;
                }
                if (owner._isHorizontal) {
                    left -= parseInt((width - owner._outerSize(element)) / 2, 10);
                    top -= height + callout.height() + margin;
                } else {
                    top -= parseInt((height - owner._outerSize(element)) / 2, 10);
                    left -= width + callout.width() + margin;
                }
                if (owner._isHorizontal) {
                    diff = that._flip(top, height, anchorSize, outerHeight(viewport) + that._scrollOffset.top);
                    top += diff;
                    left += that._fit(left, width, outerWidth(viewport) + that._scrollOffset.left);
                } else {
                    diff = that._flip(left, width, anchorSize, outerWidth(viewport) + that._scrollOffset.left);
                    top += that._fit(top, height, outerHeight(viewport) + that._scrollOffset.top);
                    left += diff;
                }
                if (diff > 0 && callout) {
                    callout.removeClass();
                    callout.addClass('k-callout k-callout-' + (owner._isHorizontal ? 'n' : 'w'));
                }
                that.tooltipDiv.css({
                    top: top,
                    left: left
                });
            },
            _fit: function (position, size, viewPortEnd) {
                var output = 0;
                if (position + size > viewPortEnd) {
                    output = viewPortEnd - (position + size);
                }
                if (position < 0) {
                    output = -position;
                }
                return output;
            },
            _flip: function (offset, size, anchorSize, viewPortEnd) {
                var output = 0;
                if (offset + size > viewPortEnd) {
                    output += -(anchorSize + size);
                }
                if (offset + output < 0) {
                    output += anchorSize + size;
                }
                return output;
            },
            constrainValue: function (position, min, max, maxOverflow) {
                var that = this, val = 0;
                if (min < position && position < max) {
                    val = that.owner._getValueFromPosition(position, that.dragableArea);
                } else {
                    if (maxOverflow) {
                        val = that.options.max;
                    } else {
                        val = that.options.min;
                    }
                }
                return val;
            }
        };
        kendo.ui.plugin(Slider);
        var RangeSlider = SliderBase.extend({
            init: function (element, options) {
                var that = this, inputs = $(element).find('input'), firstInput = inputs.eq(0)[0], secondInput = inputs.eq(1)[0];
                firstInput.type = 'text';
                secondInput.type = 'text';
                if (options && options.showButtons) {
                    if (window.console) {
                        window.console.warn('showbuttons option is not supported for the range slider, ignoring');
                    }
                    options.showButtons = false;
                }
                options = extend({}, {
                    selectionStart: parseAttr(firstInput, 'value'),
                    min: parseAttr(firstInput, 'min'),
                    max: parseAttr(firstInput, 'max'),
                    smallStep: parseAttr(firstInput, 'step')
                }, {
                    selectionEnd: parseAttr(secondInput, 'value'),
                    min: parseAttr(secondInput, 'min'),
                    max: parseAttr(secondInput, 'max'),
                    smallStep: parseAttr(secondInput, 'step')
                }, options);
                if (options && options.enabled === undefined) {
                    options.enabled = !inputs.is('[disabled]');
                }
                SliderBase.fn.init.call(that, element, options);
                options = that.options;
                if (!defined(options.selectionStart) || options.selectionStart === null) {
                    options.selectionStart = options.min;
                    inputs.eq(0).prop('value', formatValue(options.min));
                }
                if (!defined(options.selectionEnd) || options.selectionEnd === null) {
                    options.selectionEnd = options.max;
                    inputs.eq(1).prop('value', formatValue(options.max));
                }
                var dragHandles = that.wrapper.find(DRAG_HANDLE);
                this._selection = new RangeSlider.Selection(dragHandles, that, options);
                that._firstHandleDrag = new Slider.Drag(dragHandles.eq(0), 'firstHandle', that, options);
                that._lastHandleDrag = new Slider.Drag(dragHandles.eq(1), 'lastHandle', that, options);
            },
            options: {
                name: 'RangeSlider',
                leftDragHandleTitle: 'drag',
                rightDragHandleTitle: 'drag',
                tooltip: { format: '{0:#,#.##}' },
                selectionStart: null,
                selectionEnd: null
            },
            enable: function (enable) {
                var that = this, options = that.options, clickHandler;
                that.disable();
                if (enable === false) {
                    return;
                }
                that.wrapper.removeClass(STATE_DISABLED).addClass(STATE_DEFAULT);
                that.wrapper.find('input').removeAttr(DISABLED);
                clickHandler = function (e) {
                    var touch = getTouches(e)[0];
                    if (!touch) {
                        return;
                    }
                    var mousePosition = that._isHorizontal ? touch.location.pageX : touch.location.pageY, dragableArea = that._getDraggableArea(), val = that._getValueFromPosition(mousePosition, dragableArea), target = $(e.target), from, to, drag;
                    if (target.hasClass('k-draghandle')) {
                        that.wrapper.find('.' + STATE_FOCUSED).removeClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                        target.addClass(STATE_FOCUSED + ' ' + STATE_SELECTED);
                        return;
                    }
                    if (val < options.selectionStart) {
                        from = val;
                        to = options.selectionEnd;
                        drag = that._firstHandleDrag;
                    } else if (val > that.selectionEnd) {
                        from = options.selectionStart;
                        to = val;
                        drag = that._lastHandleDrag;
                    } else {
                        if (val - options.selectionStart <= options.selectionEnd - val) {
                            from = val;
                            to = options.selectionEnd;
                            drag = that._firstHandleDrag;
                        } else {
                            from = options.selectionStart;
                            to = val;
                            drag = that._lastHandleDrag;
                        }
                    }
                    drag.dragstart(e);
                    that._setValueInRange(from, to);
                    that._focusWithMouse(drag.element);
                };
                that.wrapper.find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).on(TRACK_MOUSE_DOWN, clickHandler).end().on(TRACK_MOUSE_DOWN, function () {
                    $(document.documentElement).one('selectstart', kendo.preventDefault);
                }).on(TRACK_MOUSE_UP, function () {
                    if (that._activeDragHandle) {
                        that._activeDragHandle._end();
                    }
                });
                that.wrapper.find(DRAG_HANDLE).attr(TABINDEX, 0).on(MOUSE_UP, function () {
                    that._setTooltipTimeout();
                }).on(CLICK, function (e) {
                    that._focusWithMouse(e.target);
                    e.preventDefault();
                }).on(FOCUS, proxy(that._focus, that)).on(BLUR, proxy(that._blur, that));
                that.wrapper.find(DRAG_HANDLE).off(KEY_DOWN, kendo.preventDefault).eq(0).on(KEY_DOWN, proxy(function (e) {
                    this._keydown(e, 'firstHandle');
                }, that)).end().eq(1).on(KEY_DOWN, proxy(function (e) {
                    this._keydown(e, 'lastHandle');
                }, that));
                that.options.enabled = true;
            },
            disable: function () {
                var that = this;
                that.wrapper.removeClass(STATE_DEFAULT).addClass(STATE_DISABLED);
                that.wrapper.find('input').prop(DISABLED, DISABLED);
                that.wrapper.find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).off(TRACK_MOUSE_DOWN).off(TRACK_MOUSE_UP);
                that.wrapper.find(DRAG_HANDLE).attr(TABINDEX, -1).off(MOUSE_UP).off(KEY_DOWN).off(CLICK).off(FOCUS).off(BLUR);
                that.options.enabled = false;
            },
            _keydown: function (e, handle) {
                var that = this, selectionStartValue = that.options.selectionStart, selectionEndValue = that.options.selectionEnd, dragSelectionStart, dragSelectionEnd, activeHandleDrag;
                if (e.keyCode in that._keyMap) {
                    that._clearTooltipTimeout();
                    if (handle == 'firstHandle') {
                        activeHandleDrag = that._activeHandleDrag = that._firstHandleDrag;
                        selectionStartValue = that._keyMap[e.keyCode](selectionStartValue);
                        if (selectionStartValue > selectionEndValue) {
                            selectionEndValue = selectionStartValue;
                        }
                    } else {
                        activeHandleDrag = that._activeHandleDrag = that._lastHandleDrag;
                        selectionEndValue = that._keyMap[e.keyCode](selectionEndValue);
                        if (selectionStartValue > selectionEndValue) {
                            selectionStartValue = selectionEndValue;
                        }
                    }
                    that._setValueInRange(round(selectionStartValue), round(selectionEndValue));
                    dragSelectionStart = Math.max(selectionStartValue, that.options.selectionStart);
                    dragSelectionEnd = Math.min(selectionEndValue, that.options.selectionEnd);
                    activeHandleDrag.selectionEnd = Math.max(dragSelectionEnd, that.options.selectionStart);
                    activeHandleDrag.selectionStart = Math.min(dragSelectionStart, that.options.selectionEnd);
                    activeHandleDrag._updateTooltip(that.value()[that._activeHandle]);
                    e.preventDefault();
                }
            },
            _update: function (selectionStart, selectionEnd) {
                var that = this, values = that.value();
                var change = values[0] != selectionStart || values[1] != selectionEnd;
                that.value([
                    selectionStart,
                    selectionEnd
                ]);
                if (change) {
                    that.trigger(CHANGE, {
                        values: [
                            selectionStart,
                            selectionEnd
                        ],
                        value: [
                            selectionStart,
                            selectionEnd
                        ]
                    });
                }
            },
            value: function (value) {
                if (value && value.length) {
                    return this._value(value[0], value[1]);
                } else {
                    return this._value();
                }
            },
            _value: function (start, end) {
                var that = this, options = that.options, selectionStart = options.selectionStart, selectionEnd = options.selectionEnd;
                if (isNaN(start) && isNaN(end)) {
                    return [
                        selectionStart,
                        selectionEnd
                    ];
                } else {
                    start = round(start);
                    end = round(end);
                }
                if (start >= options.min && start <= options.max && end >= options.min && end <= options.max && start <= end) {
                    if (selectionStart != start || selectionEnd != end) {
                        that.element.find('input').eq(0).prop('value', formatValue(start)).end().eq(1).prop('value', formatValue(end));
                        options.selectionStart = start;
                        options.selectionEnd = end;
                        that._refresh();
                        that._refreshAriaAttr(start, end);
                    }
                }
            },
            values: function (start, end) {
                if (isArray(start)) {
                    return this._value(start[0], start[1]);
                } else {
                    return this._value(start, end);
                }
            },
            _refresh: function () {
                var that = this, options = that.options;
                that.trigger(MOVE_SELECTION, {
                    values: [
                        options.selectionStart,
                        options.selectionEnd
                    ],
                    value: [
                        options.selectionStart,
                        options.selectionEnd
                    ]
                });
                if (options.selectionStart == options.max && options.selectionEnd == options.max) {
                    that._setZIndex('firstHandle');
                }
            },
            _refreshAriaAttr: function (start, end) {
                var that = this, dragHandles = that.wrapper.find(DRAG_HANDLE), drag = that._activeHandleDrag, formattedValue;
                formattedValue = that._getFormattedValue([
                    start,
                    end
                ], drag);
                dragHandles.eq(0).attr('aria-valuenow', start);
                dragHandles.eq(1).attr('aria-valuenow', end);
                dragHandles.attr('aria-valuetext', formattedValue);
            },
            _setValueInRange: function (selectionStart, selectionEnd) {
                var options = this.options;
                selectionStart = math.max(math.min(selectionStart, options.max), options.min);
                selectionEnd = math.max(math.min(selectionEnd, options.max), options.min);
                if (selectionStart == options.max && selectionEnd == options.max) {
                    this._setZIndex('firstHandle');
                }
                this._update(math.min(selectionStart, selectionEnd), math.max(selectionStart, selectionEnd));
            },
            _setZIndex: function (type) {
                this.wrapper.find(DRAG_HANDLE).each(function (index) {
                    $(this).css('z-index', type == 'firstHandle' ? 1 - index : index);
                });
            },
            _formResetHandler: function () {
                var that = this, options = that.options;
                setTimeout(function () {
                    var inputs = that.element.find('input');
                    var start = inputs[0].value;
                    var end = inputs[1].value;
                    that.values(start === '' || isNaN(start) ? options.min : start, end === '' || isNaN(end) ? options.max : end);
                });
            },
            destroy: function () {
                var that = this;
                SliderBase.fn.destroy.call(that);
                that.wrapper.off(NS).find(TICK_SELECTOR + ', ' + TRACK_SELECTOR).off(NS).end().find(DRAG_HANDLE).off(NS);
                that._firstHandleDrag.draggable.destroy();
                that._lastHandleDrag.draggable.destroy();
            }
        });
        RangeSlider.Selection = function (dragHandles, that, options) {
            function moveSelection(value) {
                value = value || [];
                var selectionStartValue = value[0] - options.min, selectionEndValue = value[1] - options.min, selectionStartIndex = math.ceil(round(selectionStartValue / options.smallStep)), selectionEndIndex = math.ceil(round(selectionEndValue / options.smallStep)), selectionStart = that._pixelSteps[selectionStartIndex], selectionEnd = that._pixelSteps[selectionEndIndex], halfHandle = parseInt(that._outerSize(dragHandles.eq(0)) / 2, 10), rtlCorrection = that._isRtl ? 2 : 0;
                dragHandles.eq(0).css(that._position, selectionStart - halfHandle - rtlCorrection).end().eq(1).css(that._position, selectionEnd - halfHandle - rtlCorrection);
                makeSelection(selectionStart, selectionEnd);
            }
            function makeSelection(selectionStart, selectionEnd) {
                var selection, selectionPosition, selectionDiv = that._trackDiv.find('.k-slider-selection');
                selection = math.abs(selectionStart - selectionEnd);
                selectionDiv[that._sizeFn](selection);
                if (that._isRtl) {
                    selectionPosition = math.max(selectionStart, selectionEnd);
                    selectionDiv.css('right', that._maxSelection - selectionPosition - 1);
                } else {
                    selectionPosition = math.min(selectionStart, selectionEnd);
                    selectionDiv.css(that._position, selectionPosition - 1);
                }
            }
            moveSelection(that.value());
            that.bind([
                CHANGE,
                SLIDE,
                MOVE_SELECTION
            ], function (e) {
                moveSelection(e.values);
            });
        };
        kendo.ui.plugin(RangeSlider);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.colorpicker', [
        'kendo.core',
        'kendo.color',
        'kendo.popup',
        'kendo.slider',
        'kendo.userevents',
        'kendo.button'
    ], f);
}(function () {
    var __meta__ = {
        id: 'colorpicker',
        name: 'Color tools',
        category: 'web',
        description: 'Color selection widgets',
        depends: [
            'core',
            'color',
            'popup',
            'slider',
            'userevents',
            'button'
        ]
    };
    (function ($, parseInt, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, parseColor = kendo.parseColor, Color = kendo.Color, KEYS = kendo.keys, BACKGROUNDCOLOR = 'background-color', ITEMSELECTEDCLASS = 'k-state-selected', SIMPLEPALETTE = '000000,7f7f7f,880015,ed1c24,ff7f27,fff200,22b14c,00a2e8,3f48cc,a349a4,ffffff,c3c3c3,b97a57,ffaec9,ffc90e,efe4b0,b5e61d,99d9ea,7092be,c8bfe7', WEBPALETTE = 'FFFFFF,FFCCFF,FF99FF,FF66FF,FF33FF,FF00FF,CCFFFF,CCCCFF,CC99FF,CC66FF,CC33FF,CC00FF,99FFFF,99CCFF,9999FF,9966FF,9933FF,9900FF,FFFFCC,FFCCCC,FF99CC,FF66CC,FF33CC,FF00CC,CCFFCC,CCCCCC,CC99CC,CC66CC,CC33CC,CC00CC,99FFCC,99CCCC,9999CC,9966CC,9933CC,9900CC,FFFF99,FFCC99,FF9999,FF6699,FF3399,FF0099,CCFF99,CCCC99,CC9999,CC6699,CC3399,CC0099,99FF99,99CC99,999999,996699,993399,990099,FFFF66,FFCC66,FF9966,FF6666,FF3366,FF0066,CCFF66,CCCC66,CC9966,CC6666,CC3366,CC0066,99FF66,99CC66,999966,996666,993366,990066,FFFF33,FFCC33,FF9933,FF6633,FF3333,FF0033,CCFF33,CCCC33,CC9933,CC6633,CC3333,CC0033,99FF33,99CC33,999933,996633,993333,990033,FFFF00,FFCC00,FF9900,FF6600,FF3300,FF0000,CCFF00,CCCC00,CC9900,CC6600,CC3300,CC0000,99FF00,99CC00,999900,996600,993300,990000,66FFFF,66CCFF,6699FF,6666FF,6633FF,6600FF,33FFFF,33CCFF,3399FF,3366FF,3333FF,3300FF,00FFFF,00CCFF,0099FF,0066FF,0033FF,0000FF,66FFCC,66CCCC,6699CC,6666CC,6633CC,6600CC,33FFCC,33CCCC,3399CC,3366CC,3333CC,3300CC,00FFCC,00CCCC,0099CC,0066CC,0033CC,0000CC,66FF99,66CC99,669999,666699,663399,660099,33FF99,33CC99,339999,336699,333399,330099,00FF99,00CC99,009999,006699,003399,000099,66FF66,66CC66,669966,666666,663366,660066,33FF66,33CC66,339966,336666,333366,330066,00FF66,00CC66,009966,006666,003366,000066,66FF33,66CC33,669933,666633,663333,660033,33FF33,33CC33,339933,336633,333333,330033,00FF33,00CC33,009933,006633,003333,000033,66FF00,66CC00,669900,666600,663300,660000,33FF00,33CC00,339900,336600,333300,330000,00FF00,00CC00,009900,006600,003300,000000', WHITE = '#ffffff', MESSAGES = {
                apply: 'Apply',
                cancel: 'Cancel',
                noColor: 'no color',
                clearColor: 'Clear color',
                previewInput: 'Color Hexadecimal Code'
            }, NS = '.kendoColorTools', CLICK_NS = 'click' + NS, KEYDOWN_NS = 'keydown' + NS, browser = kendo.support.browser, isIE8 = browser.msie && browser.version < 9;
        var ColorSelector = Widget.extend({
            init: function (element, options) {
                var that = this, ariaId;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                that._value = options.value = parseColor(options.value);
                that._tabIndex = element.attr('tabIndex') || 0;
                ariaId = that._ariaId = options.ariaId;
                if (ariaId) {
                    element.attr('aria-labelledby', ariaId);
                }
                if (options._standalone) {
                    that._triggerSelect = that._triggerChange;
                }
            },
            options: {
                name: 'ColorSelector',
                value: null,
                _standalone: true
            },
            events: [
                'change',
                'select',
                'cancel'
            ],
            color: function (value) {
                if (value !== undefined) {
                    this._value = parseColor(value);
                    this._updateUI(this._value);
                }
                return this._value;
            },
            value: function (color) {
                color = this.color(color);
                if (color) {
                    if (this.options.opacity) {
                        color = color.toCssRgba();
                    } else {
                        color = color.toCss();
                    }
                }
                return color || null;
            },
            enable: function (enable) {
                if (arguments.length === 0) {
                    enable = true;
                }
                $('.k-disabled-overlay', this.wrapper).remove();
                if (!enable) {
                    this.wrapper.append('<div class=\'k-disabled-overlay\'></div>');
                }
                this._onEnable(enable);
            },
            _select: function (color, nohooks) {
                var prev = this._value;
                color = this.color(color);
                if (!nohooks) {
                    this.element.trigger('change');
                    if (!color.equals(prev)) {
                        this.trigger('change', { value: this.value() });
                    } else if (!this._standalone) {
                        this.trigger('cancel');
                    }
                }
            },
            _triggerSelect: function (color) {
                triggerEvent(this, 'select', color);
            },
            _triggerChange: function (color) {
                triggerEvent(this, 'change', color);
            },
            destroy: function () {
                if (this.element) {
                    this.element.off(NS);
                }
                if (this.wrapper) {
                    this.wrapper.off(NS).find('*').off(NS);
                }
                this.wrapper = null;
                Widget.fn.destroy.call(this);
            },
            _updateUI: $.noop,
            _selectOnHide: function () {
                return null;
            },
            _cancel: function () {
                this.trigger('cancel');
            }
        });
        function triggerEvent(self, type, color) {
            color = parseColor(color);
            if (color && !color.equals(self.color())) {
                if (type == 'change') {
                    self._value = color;
                }
                if (color.a != 1) {
                    color = color.toCssRgba();
                } else {
                    color = color.toCss();
                }
                self.trigger(type, { value: color });
            }
        }
        var ColorPalette = ColorSelector.extend({
            init: function (element, options) {
                var that = this;
                ColorSelector.fn.init.call(that, element, options);
                element = that.wrapper = that.element;
                options = that.options;
                var colors = options.palette;
                if (colors == 'websafe') {
                    colors = WEBPALETTE;
                    options.columns = 18;
                } else if (colors == 'basic') {
                    colors = SIMPLEPALETTE;
                }
                if (typeof colors == 'string') {
                    colors = colors.split(',');
                }
                if ($.isArray(colors)) {
                    colors = $.map(colors, function (x) {
                        return parseColor(x);
                    });
                }
                that._selectedID = (options.ariaId || kendo.guid()) + '_selected';
                element.addClass('k-widget k-colorpalette').attr('role', 'grid').attr('aria-readonly', 'true').append($(that._template({
                    colors: colors,
                    columns: options.columns,
                    tileSize: options.tileSize,
                    value: that._value,
                    id: options.ariaId
                }))).on(CLICK_NS, '.k-item', function (ev) {
                    that._select($(ev.currentTarget).css(BACKGROUNDCOLOR));
                }).attr('tabIndex', that._tabIndex).on(KEYDOWN_NS, bind(that._keydown, that));
                var tileSize = options.tileSize, width, height;
                if (tileSize) {
                    if (/number|string/.test(typeof tileSize)) {
                        width = height = parseFloat(tileSize);
                    } else if (typeof tileSize == 'object') {
                        width = parseFloat(tileSize.width);
                        height = parseFloat(tileSize.height);
                    } else {
                        throw new Error('Unsupported value for the \'tileSize\' argument');
                    }
                    element.find('.k-item').css({
                        width: width,
                        height: height
                    });
                }
            },
            focus: function () {
                this.wrapper.focus();
            },
            options: {
                name: 'ColorPalette',
                columns: 10,
                tileSize: null,
                palette: 'basic'
            },
            _onEnable: function (enable) {
                if (enable) {
                    this.wrapper.attr('tabIndex', this._tabIndex);
                } else {
                    this.wrapper.removeAttr('tabIndex');
                }
            },
            _keydown: function (e) {
                var selected, wrapper = this.wrapper, items = wrapper.find('.k-item'), current = items.filter('.' + ITEMSELECTEDCLASS).get(0), keyCode = e.keyCode;
                if (keyCode == KEYS.LEFT) {
                    selected = relative(items, current, -1);
                } else if (keyCode == KEYS.RIGHT) {
                    selected = relative(items, current, 1);
                } else if (keyCode == KEYS.DOWN) {
                    selected = relative(items, current, this.options.columns);
                } else if (keyCode == KEYS.UP) {
                    selected = relative(items, current, -this.options.columns);
                } else if (keyCode == KEYS.ENTER) {
                    preventDefault(e);
                    if (current) {
                        this._select($(current).css(BACKGROUNDCOLOR));
                    }
                } else if (keyCode == KEYS.ESC) {
                    this._cancel();
                }
                if (selected) {
                    preventDefault(e);
                    this._current(selected);
                    try {
                        var color = parseColor(selected.css(BACKGROUNDCOLOR));
                        this._triggerSelect(color);
                    } catch (ex) {
                    }
                }
            },
            _current: function (item) {
                this.wrapper.find('.' + ITEMSELECTEDCLASS).removeClass(ITEMSELECTEDCLASS).attr('aria-selected', false).removeAttr('id');
                $(item).addClass(ITEMSELECTEDCLASS).attr('aria-selected', true).attr('id', this._selectedID);
                this.element.removeAttr('aria-activedescendant').attr('aria-activedescendant', this._selectedID);
            },
            _updateUI: function (color) {
                var item = null;
                this.wrapper.find('.k-item').each(function () {
                    var c = parseColor($(this).css(BACKGROUNDCOLOR));
                    if (c && c.equals(color)) {
                        item = this;
                        return false;
                    }
                });
                this._current(item);
            },
            _template: kendo.template('<table class="k-palette k-reset" role="presentation"><tr role="row">' + '# for (var i = 0; i < colors.length; ++i) { #' + '# var selected = colors[i].equals(value); #' + '# if (i && i % columns == 0) { # </tr><tr role="row"> # } #' + '<td role="gridcell" unselectable="on" style="background-color:#= colors[i].toCss() #"' + '#= selected ? " aria-selected=true" : "" # ' + '#=(id && i === 0) ? "id=\\""+id+"\\" " : "" # ' + 'class="k-item#= selected ? " ' + ITEMSELECTEDCLASS + '" : "" #" ' + 'aria-label="#= colors[i].toCss() #"></td>' + '# } #' + '</tr></table>')
        });
        var FlatColorPicker = ColorSelector.extend({
            init: function (element, options) {
                var that = this;
                ColorSelector.fn.init.call(that, element, options);
                options = that.options;
                options.messages = options.options ? $.extend(that.options.messages, options.options.messages) : that.options.messages;
                element = that.element;
                that.wrapper = element.addClass('k-widget k-flatcolorpicker').append(that._template(options));
                that._hueElements = $('.k-hsv-rectangle, .k-transparency-slider .k-slider-track', element);
                that._selectedColor = $('.k-selected-color-display', element);
                that._colorAsText = $('input.k-color-value', element);
                that._sliders();
                that._hsvArea();
                that._updateUI(that._value || parseColor('#f00'));
                element.find('input.k-color-value').on(KEYDOWN_NS, function (ev) {
                    var input = this;
                    if (ev.keyCode == KEYS.ENTER) {
                        try {
                            var color = parseColor(input.value);
                            var val = that.color();
                            that._select(color, color.equals(val));
                        } catch (ex) {
                            $(input).addClass('k-state-error');
                        }
                    } else if (that.options.autoupdate) {
                        setTimeout(function () {
                            var color = parseColor(input.value, true);
                            if (color) {
                                that._updateUI(color, true);
                            }
                        }, 10);
                    }
                }).end().on(CLICK_NS, '.k-controls button.apply', function () {
                    if (that.options._clearedColor) {
                        that.trigger('change');
                    } else {
                        that._select(that._getHSV());
                    }
                }).on(CLICK_NS, '.k-controls button.cancel', function () {
                    that._updateUI(that.color());
                    that._cancel();
                });
                if (isIE8) {
                    that._applyIEFilter();
                }
            },
            destroy: function () {
                this._hueSlider.destroy();
                if (this._opacitySlider) {
                    this._opacitySlider.destroy();
                }
                this._hueSlider = this._opacitySlider = this._hsvRect = this._hsvHandle = this._hueElements = this._selectedColor = this._colorAsText = null;
                ColorSelector.fn.destroy.call(this);
            },
            options: {
                name: 'FlatColorPicker',
                opacity: false,
                buttons: false,
                input: true,
                preview: true,
                clearButton: false,
                autoupdate: true,
                messages: MESSAGES
            },
            _applyIEFilter: function () {
                var track = this.element.find('.k-hue-slider .k-slider-track')[0], url = track.currentStyle.backgroundImage;
                url = url.replace(/^url\([\'\"]?|[\'\"]?\)$/g, '');
                track.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + url + '\', sizingMethod=\'scale\')';
            },
            _sliders: function () {
                var that = this, element = that.element, hueSlider = element.find('.k-hue-slider'), opacitySlider = element.find('.k-transparency-slider');
                function hueChange(e) {
                    that._updateUI(that._getHSV(e.value, null, null, null));
                }
                hueSlider.attr('aria-label', 'hue saturation');
                that._hueSlider = hueSlider.kendoSlider({
                    min: 0,
                    max: 360,
                    tickPlacement: 'none',
                    showButtons: false,
                    slide: hueChange,
                    change: hueChange
                }).data('kendoSlider');
                function opacityChange(e) {
                    that._updateUI(that._getHSV(null, null, null, e.value / 100));
                }
                opacitySlider.attr('aria-label', 'opacity');
                that._opacitySlider = opacitySlider.kendoSlider({
                    min: 0,
                    max: 100,
                    tickPlacement: 'none',
                    showButtons: false,
                    slide: opacityChange,
                    change: opacityChange
                }).data('kendoSlider');
            },
            _hsvArea: function () {
                var that = this, element = that.element, hsvRect = element.find('.k-hsv-rectangle'), hsvHandle = hsvRect.find('.k-draghandle').attr('tabIndex', 0).on(KEYDOWN_NS, bind(that._keydown, that));
                function update(x, y) {
                    var offset = this.offset, dx = x - offset.left, dy = y - offset.top, rw = this.width, rh = this.height;
                    dx = dx < 0 ? 0 : dx > rw ? rw : dx;
                    dy = dy < 0 ? 0 : dy > rh ? rh : dy;
                    that._svChange(dx / rw, 1 - dy / rh);
                }
                that._hsvEvents = new kendo.UserEvents(hsvRect, {
                    global: true,
                    press: function (e) {
                        this.offset = kendo.getOffset(hsvRect);
                        this.width = hsvRect.width();
                        this.height = hsvRect.height();
                        hsvHandle.focus();
                        update.call(this, e.x.location, e.y.location);
                    },
                    start: function () {
                        hsvRect.addClass('k-dragging');
                        hsvHandle.focus();
                    },
                    move: function (e) {
                        e.preventDefault();
                        update.call(this, e.x.location, e.y.location);
                    },
                    end: function () {
                        hsvRect.removeClass('k-dragging');
                    }
                });
                that._hsvRect = hsvRect;
                that._hsvHandle = hsvHandle;
            },
            _onEnable: function (enable) {
                this._hueSlider.enable(enable);
                if (this._opacitySlider) {
                    this._opacitySlider.enable(enable);
                }
                this.wrapper.find('input').attr('disabled', !enable);
                var handle = this._hsvRect.find('.k-draghandle');
                if (enable) {
                    handle.attr('tabIndex', this._tabIndex);
                } else {
                    handle.removeAttr('tabIndex');
                }
            },
            _keydown: function (ev) {
                var that = this;
                function move(prop, d) {
                    var c = that._getHSV();
                    c[prop] += d * (ev.shiftKey ? 0.01 : 0.05);
                    if (c[prop] < 0) {
                        c[prop] = 0;
                    }
                    if (c[prop] > 1) {
                        c[prop] = 1;
                    }
                    that._updateUI(c);
                    preventDefault(ev);
                }
                function hue(d) {
                    var c = that._getHSV();
                    c.h += d * (ev.shiftKey ? 1 : 5);
                    if (c.h < 0) {
                        c.h = 0;
                    }
                    if (c.h > 359) {
                        c.h = 359;
                    }
                    that._updateUI(c);
                    preventDefault(ev);
                }
                switch (ev.keyCode) {
                case KEYS.LEFT:
                    if (ev.ctrlKey) {
                        hue(-1);
                    } else {
                        move('s', -1);
                    }
                    break;
                case KEYS.RIGHT:
                    if (ev.ctrlKey) {
                        hue(1);
                    } else {
                        move('s', 1);
                    }
                    break;
                case KEYS.UP:
                    move(ev.ctrlKey && that._opacitySlider ? 'a' : 'v', 1);
                    break;
                case KEYS.DOWN:
                    move(ev.ctrlKey && that._opacitySlider ? 'a' : 'v', -1);
                    break;
                case KEYS.ENTER:
                    that._select(that._getHSV());
                    break;
                case KEYS.F2:
                    that.wrapper.find('input.k-color-value').focus().select();
                    break;
                case KEYS.ESC:
                    that._cancel();
                    break;
                }
            },
            focus: function () {
                this._hsvHandle.focus();
            },
            _getHSV: function (h, s, v, a) {
                var rect = this._hsvRect, width = rect.width(), height = rect.height(), handlePosition = this._hsvHandle.position();
                if (h == null) {
                    h = this._hueSlider.value();
                }
                if (s == null) {
                    s = handlePosition.left / width;
                }
                if (v == null) {
                    v = 1 - handlePosition.top / height;
                }
                if (a == null) {
                    a = this._opacitySlider ? this._opacitySlider.value() / 100 : 1;
                }
                return Color.fromHSV(h, s, v, a);
            },
            _svChange: function (s, v) {
                var color = this._getHSV(null, s, v, null);
                this._updateUI(color);
            },
            _updateUI: function (color, dontChangeInput) {
                var that = this, rect = that._hsvRect;
                if (!color) {
                    return;
                }
                this._colorAsText.attr('title', that.options.messages.previewInput);
                this._colorAsText.removeClass('k-state-error');
                that._selectedColor.css(BACKGROUNDCOLOR, color.toDisplay());
                if (!dontChangeInput) {
                    that._colorAsText.val(that._opacitySlider ? color.toCssRgba() : color.toCss());
                }
                that._triggerSelect(color);
                color = color.toHSV();
                that._hsvHandle.css({
                    left: color.s * rect.width() + 'px',
                    top: (1 - color.v) * rect.height() + 'px'
                });
                that._hueElements.css(BACKGROUNDCOLOR, Color.fromHSV(color.h, 1, 1, 1).toCss());
                that._hueSlider.value(color.h);
                if (that._opacitySlider) {
                    that._opacitySlider.value(100 * color.a);
                }
            },
            _selectOnHide: function () {
                return this.options.buttons ? null : this._getHSV();
            },
            _template: kendo.template('# if (preview) { #' + '<div class="k-selected-color"><div class="k-selected-color-display"><div class="k-color-input"><input class="k-color-value" ' + '# if (clearButton && !_standalone) { #' + 'placeholder="#: messages.noColor #" ' + '# } #' + '#= !data.input ? \'style="visibility: hidden;"\' : "" #>' + '# if (clearButton && !_standalone) { #' + '<span class="k-clear-color k-button k-bare" title="#: messages.clearColor #"></span>' + '# } #' + '</div></div></div>' + '# } #' + '# if (clearButton && !_standalone && !preview) { #' + '<div class="k-clear-color-container"><span class="k-clear-color k-button k-bare">#: messages.clearColor #</span></div>' + '# } #' + '<div class="k-hsv-rectangle"><div class="k-hsv-gradient"></div><div class="k-draghandle"></div></div>' + '<input class="k-hue-slider" />' + '# if (opacity) { #' + '<input class="k-transparency-slider" />' + '# } #' + '# if (buttons) { #' + '<div unselectable="on" class="k-controls"><button class="k-button k-primary apply">#: messages.apply #</button> <button class="k-button cancel">#: messages.cancel #</button></div>' + '# } #')
        });
        function relative(array, element, delta) {
            array = Array.prototype.slice.call(array);
            var n = array.length;
            var pos = array.indexOf(element);
            if (pos < 0) {
                return delta < 0 ? array[n - 1] : array[0];
            }
            pos += delta;
            if (pos < 0) {
                pos += n;
            } else {
                pos %= n;
            }
            return array[pos];
        }
        var ColorPicker = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element;
                var value = element.attr('value') || element.val();
                if (value) {
                    value = parseColor(value, true);
                } else {
                    value = parseColor(options.value, true);
                }
                that._value = options.value = value;
                var content = that.wrapper = $(that._template(options));
                element.hide().after(content);
                if (element.is('input')) {
                    element.appendTo(content);
                    var label = element.closest('label');
                    var id = element.attr('id');
                    if (id) {
                        label = label.add('label[for="' + id + '"]');
                    }
                    label.click(function (ev) {
                        that.open();
                        ev.preventDefault();
                    });
                }
                that._tabIndex = element.attr('tabIndex') || 0;
                that.enable(!element.attr('disabled'));
                var accesskey = element.attr('accesskey');
                if (accesskey) {
                    element.attr('accesskey', null);
                    content.attr('accesskey', accesskey);
                }
                that.bind('activate', function (ev) {
                    if (!ev.isDefaultPrevented()) {
                        that.toggle();
                    }
                });
                that._updateUI(value);
            },
            destroy: function () {
                this.wrapper.off(NS).find('*').off(NS);
                if (this._popup) {
                    this._selector.destroy();
                    this._popup.destroy();
                }
                this._selector = this._popup = this.wrapper = null;
                Widget.fn.destroy.call(this);
            },
            enable: function (enable) {
                var that = this, wrapper = that.wrapper, innerWrapper = wrapper.children('.k-picker-wrap'), arrow = innerWrapper.find('.k-select');
                if (arguments.length === 0) {
                    enable = true;
                }
                that.element.attr('disabled', !enable);
                wrapper.attr('aria-disabled', !enable);
                arrow.off(NS).on('mousedown' + NS, preventDefault);
                wrapper.addClass('k-state-disabled').removeAttr('tabIndex').add('*', wrapper).off(NS);
                if (enable) {
                    wrapper.removeClass('k-state-disabled').attr('tabIndex', that._tabIndex).on('mouseenter' + NS, function () {
                        innerWrapper.addClass('k-state-hover');
                    }).on('mouseleave' + NS, function () {
                        innerWrapper.removeClass('k-state-hover');
                    }).on('focus' + NS, function () {
                        innerWrapper.addClass('k-state-focused');
                    }).on('blur' + NS, function () {
                        innerWrapper.removeClass('k-state-focused');
                    }).on(KEYDOWN_NS, bind(that._keydown, that)).on(CLICK_NS, '.k-select', bind(that.toggle, that)).on(CLICK_NS, that.options.toolIcon ? '.k-tool-icon' : '.k-selected-color', function () {
                        that.trigger('activate');
                    });
                } else {
                    that.close();
                }
            },
            _template: kendo.template('<span role="textbox" aria-haspopup="true" class="k-widget k-colorpicker k-header">' + '<span class="k-picker-wrap k-state-default">' + '# if (toolIcon) { #' + '<span class="k-icon k-tool-icon #= toolIcon #">' + '<span class="k-selected-color"></span>' + '</span>' + '# } else { #' + '<span class="k-selected-color"><span class="k-icon k-i-line" style="display: none;"></span></span>' + '# } #' + '<span class="k-select" unselectable="on" aria-label="select">' + '<span class="k-icon k-i-arrow-60-down"></span>' + '</span>' + '</span>' + '</span>'),
            options: {
                name: 'ColorPicker',
                palette: null,
                columns: 10,
                toolIcon: null,
                value: null,
                messages: MESSAGES,
                opacity: false,
                buttons: true,
                preview: true,
                clearButton: false,
                ARIATemplate: 'Current selected color is #=data || ""#'
            },
            events: [
                'activate',
                'change',
                'select',
                'open',
                'close'
            ],
            open: function () {
                if (!this.element.prop('disabled')) {
                    this._getPopup().open();
                }
            },
            close: function () {
                var selOptions = this._selector && this._selector.options || {};
                selOptions._closing = true;
                this._getPopup().close();
                delete selOptions._closing;
            },
            toggle: function () {
                if (!this.element.prop('disabled')) {
                    this._getPopup().toggle();
                }
            },
            _noColorIcon: function () {
                return this.wrapper.find('.k-picker-wrap > .k-selected-color > .k-icon.k-i-line');
            },
            color: ColorSelector.fn.color,
            value: ColorSelector.fn.value,
            _select: ColorSelector.fn._select,
            _triggerSelect: ColorSelector.fn._triggerSelect,
            _isInputTypeColor: function () {
                var el = this.element[0];
                return /^input$/i.test(el.tagName) && /^color$/i.test(el.type);
            },
            _updateUI: function (value) {
                var formattedValue = '';
                if (value) {
                    if (this._isInputTypeColor() || value.a == 1) {
                        formattedValue = value.toCss();
                    } else {
                        formattedValue = value.toCssRgba();
                    }
                    this.element.val(formattedValue);
                }
                if (!this._ariaTemplate) {
                    this._ariaTemplate = kendo.template(this.options.ARIATemplate);
                }
                this.wrapper.attr('aria-label', this._ariaTemplate(formattedValue));
                this._triggerSelect(value);
                this.wrapper.find('.k-selected-color').css(BACKGROUNDCOLOR, value ? value.toDisplay() : WHITE);
                this._noColorIcon()[formattedValue ? 'hide' : 'show']();
            },
            _keydown: function (ev) {
                var key = ev.keyCode;
                if (this._getPopup().visible()) {
                    if (key == KEYS.ESC) {
                        this._selector._cancel();
                    } else {
                        this._selector._keydown(ev);
                    }
                    preventDefault(ev);
                } else if (key == KEYS.ENTER || key == KEYS.DOWN) {
                    this.open();
                    preventDefault(ev);
                }
            },
            _getPopup: function () {
                var that = this, popup = that._popup;
                if (!popup) {
                    var options = that.options;
                    var selectorType;
                    if (options.palette) {
                        selectorType = ColorPalette;
                    } else {
                        selectorType = FlatColorPicker;
                    }
                    options._standalone = false;
                    delete options.select;
                    delete options.change;
                    delete options.cancel;
                    var id = kendo.guid();
                    var selector = that._selector = new selectorType($('<div id="' + id + '"/>').appendTo(document.body), options);
                    that.wrapper.attr('aria-owns', id);
                    that._popup = popup = selector.wrapper.kendoPopup({
                        anchor: that.wrapper,
                        adjustSize: {
                            width: 5,
                            height: 0
                        }
                    }).data('kendoPopup');
                    selector.element.find('.k-clear-color').kendoButton({
                        icon: 'reset-color',
                        click: function (e) {
                            selector.options._clearedColor = true;
                            that.value(null);
                            that.element.val(null);
                            that._updateUI(null);
                            selector._colorAsText.val('');
                            selector._hsvHandle.css({
                                top: '0px',
                                left: '0px'
                            });
                            selector._selectedColor.css(BACKGROUNDCOLOR, WHITE);
                            that.trigger('change', { value: that.value() });
                            e.preventDefault();
                        }
                    });
                    selector.bind({
                        select: function (ev) {
                            that._updateUI(parseColor(ev.value));
                            delete selector.options._clearedColor;
                        },
                        change: function () {
                            if (!selector.options._clearedColor) {
                                that._select(selector.color());
                            }
                            that.close();
                        },
                        cancel: function () {
                            if (selector.options._clearedColor && !that.value() && selector.value()) {
                                that._select(selector.color(), true);
                            }
                            that.close();
                        }
                    });
                    popup.bind({
                        close: function (ev) {
                            if (that.trigger('close')) {
                                ev.preventDefault();
                                return;
                            }
                            that.wrapper.children('.k-picker-wrap').removeClass('k-state-focused');
                            var color = selector._selectOnHide();
                            var selectorColor = selector.value();
                            var value = that.value();
                            var options = selector.options;
                            if (!color) {
                                setTimeout(function () {
                                    if (that.wrapper) {
                                        that.wrapper.focus();
                                    }
                                });
                                if (!options._closing && options._clearedColor && !value && selectorColor) {
                                    that._select(selectorColor, true);
                                } else {
                                    that._updateUI(that.color());
                                }
                            } else if (!(options._clearedColor && !value)) {
                                that._select(color);
                            }
                        },
                        open: function (ev) {
                            if (that.trigger('open')) {
                                ev.preventDefault();
                            } else {
                                that.wrapper.children('.k-picker-wrap').addClass('k-state-focused');
                            }
                        },
                        activate: function () {
                            selector._select(that.color(), true);
                            selector.focus();
                            that.wrapper.children('.k-picker-wrap').addClass('k-state-focused');
                        }
                    });
                }
                return popup;
            }
        });
        function preventDefault(ev) {
            ev.preventDefault();
        }
        function bind(callback, obj) {
            return function () {
                return callback.apply(obj, arguments);
            };
        }
        ui.plugin(ColorPalette);
        ui.plugin(FlatColorPicker);
        ui.plugin(ColorPicker);
    }(jQuery, parseInt));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.numerictextbox', [
        'kendo.core',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'numerictextbox',
        name: 'NumericTextBox',
        category: 'web',
        description: 'The NumericTextBox widget can format and display numeric, percentage or currency textbox.',
        depends: [
            'core',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, caret = kendo.caret, keys = kendo.keys, ui = kendo.ui, Widget = ui.Widget, activeElement = kendo._activeElement, extractFormat = kendo._extractFormat, parse = kendo.parseFloat, placeholderSupported = kendo.support.placeholder, getCulture = kendo.getCulture, CHANGE = 'change', DISABLED = 'disabled', READONLY = 'readonly', INPUT = 'k-input', SPIN = 'spin', ns = '.kendoNumericTextBox', TOUCHEND = 'touchend', MOUSELEAVE = 'mouseleave' + ns, HOVEREVENTS = 'mouseenter' + ns + ' ' + MOUSELEAVE, DEFAULT = 'k-state-default', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', FOCUS = 'focus', POINT = '.', CLASS_ICON = 'k-icon', SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', STATE_INVALID = 'k-state-invalid', ARIA_DISABLED = 'aria-disabled', INTEGER_REGEXP = /^(-)?(\d*)$/, NULL = null, proxy = $.proxy, extend = $.extend;
        var NumericTextBox = Widget.extend({
            init: function (element, options) {
                var that = this, isStep = options && options.step !== undefined, min, max, step, value, disabled;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element.on('focusout' + ns, proxy(that._focusout, that)).attr('role', 'spinbutton');
                options.placeholder = options.placeholder || element.attr('placeholder');
                that._initialOptions = extend({}, options);
                min = that.min(element.attr('min'));
                max = that.max(element.attr('max'));
                step = that._parse(element.attr('step'));
                if (options.min === NULL && min !== NULL) {
                    options.min = min;
                }
                if (options.max === NULL && max !== NULL) {
                    options.max = max;
                }
                if (!isStep && step !== NULL) {
                    options.step = step;
                }
                that._reset();
                that._wrapper();
                that._arrows();
                that._validation();
                that._input();
                if (!kendo.support.mobileOS) {
                    that._text.on(FOCUS + ns, proxy(that._click, that));
                } else {
                    that._text.on(TOUCHEND + ns + ' ' + FOCUS + ns, function () {
                        if (kendo.support.browser.edge) {
                            that._text.one(FOCUS + ns, function () {
                                that._toggleText(false);
                                element.focus();
                            });
                        } else {
                            that._toggleText(false);
                            element.focus();
                        }
                    });
                }
                element.attr('aria-valuemin', options.min !== NULL ? options.min * options.factor : options.min).attr('aria-valuemax', options.max !== NULL ? options.max * options.factor : options.max);
                options.format = extractFormat(options.format);
                value = options.value;
                that.value(value !== NULL ? value : element.val());
                disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                kendo.notify(that);
            },
            options: {
                name: 'NumericTextBox',
                decimals: NULL,
                restrictDecimals: false,
                min: NULL,
                max: NULL,
                value: NULL,
                step: 1,
                round: true,
                culture: '',
                format: 'n',
                spinners: true,
                placeholder: '',
                factor: 1,
                upArrowText: 'Increase value',
                downArrowText: 'Decrease value'
            },
            events: [
                CHANGE,
                SPIN
            ],
            _editable: function (options) {
                var that = this, element = that.element, disable = options.disable, readonly = options.readonly, text = that._text.add(element), wrapper = that._inputWrapper.off(HOVEREVENTS);
                that._toggleText(true);
                that._upArrowEventHandler.unbind('press');
                that._downArrowEventHandler.unbind('press');
                element.off('keydown' + ns).off('keypress' + ns).off('keyup' + ns).off('paste' + ns);
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    text.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false);
                    that._upArrowEventHandler.bind('press', function (e) {
                        e.preventDefault();
                        that._spin(1);
                        that._upArrow.addClass(SELECTED);
                    });
                    that._downArrowEventHandler.bind('press', function (e) {
                        e.preventDefault();
                        that._spin(-1);
                        that._downArrow.addClass(SELECTED);
                    });
                    that.element.on('keydown' + ns, proxy(that._keydown, that)).on('keypress' + ns, proxy(that._keypress, that)).on('keyup' + ns, proxy(that._keyup, that)).on('paste' + ns, proxy(that._paste, that));
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    text.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            destroy: function () {
                var that = this;
                that.element.add(that._text).add(that._upArrow).add(that._downArrow).add(that._inputWrapper).off(ns);
                that._upArrowEventHandler.destroy();
                that._downArrowEventHandler.destroy();
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
                Widget.fn.destroy.call(that);
            },
            min: function (value) {
                return this._option('min', value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            step: function (value) {
                return this._option('step', value);
            },
            value: function (value) {
                var that = this, adjusted;
                if (value === undefined) {
                    return that._value;
                }
                value = that._parse(value);
                adjusted = that._adjust(value);
                if (value !== adjusted) {
                    return;
                }
                that._update(value);
                that._old = that._value;
            },
            focus: function () {
                this._focusin();
            },
            _adjust: function (value) {
                var that = this, options = that.options, min = options.min, max = options.max;
                if (value === NULL) {
                    return value;
                }
                if (min !== NULL && value < min) {
                    value = min;
                } else if (max !== NULL && value > max) {
                    value = max;
                }
                return value;
            },
            _arrows: function () {
                var that = this, arrows, _release = function () {
                        clearTimeout(that._spinning);
                        arrows.removeClass(SELECTED);
                    }, options = that.options, spinners = options.spinners, element = that.element;
                arrows = element.siblings('.' + CLASS_ICON);
                if (!arrows[0]) {
                    arrows = $(buttonHtml('increase', options.upArrowText) + buttonHtml('decrease', options.downArrowText)).insertAfter(element);
                    arrows.wrapAll('<span class="k-select"/>');
                }
                if (!spinners) {
                    arrows.parent().toggle(spinners);
                    that._inputWrapper.addClass('k-expand-padding');
                }
                that._upArrow = arrows.eq(0);
                that._upArrowEventHandler = new kendo.UserEvents(that._upArrow, { release: _release });
                that._downArrow = arrows.eq(1);
                that._downArrowEventHandler = new kendo.UserEvents(that._downArrow, { release: _release });
            },
            _validation: function () {
                var that = this;
                var element = that.element;
                that._validationIcon = $('<span class=\'' + CLASS_ICON + ' k-i-warning\'></span>').hide().insertAfter(element);
            },
            _blur: function () {
                var that = this;
                that._toggleText(true);
                that._change(that.element.val());
            },
            _click: function (e) {
                var that = this;
                clearTimeout(that._focusing);
                that._focusing = setTimeout(function () {
                    var input = e.target, idx = caret(input)[0], value = input.value.substring(0, idx), format = that._format(that.options.format), group = format[','], result, groupRegExp, extractRegExp, caretPosition = 0;
                    if (group) {
                        groupRegExp = new RegExp('\\' + group, 'g');
                        extractRegExp = new RegExp('([\\d\\' + group + ']+)(\\' + format[POINT] + ')?(\\d+)?');
                    }
                    if (extractRegExp) {
                        result = extractRegExp.exec(value);
                    }
                    if (result) {
                        caretPosition = result[0].replace(groupRegExp, '').length;
                        if (value.indexOf('(') != -1 && that._value < 0) {
                            caretPosition++;
                        }
                    }
                    that._focusin();
                    caret(that.element[0], caretPosition);
                });
            },
            _change: function (value) {
                var that = this, factor = that.options.factor;
                if (factor && factor !== 1) {
                    value = parseFloat(value);
                    if (value !== null) {
                        value = value / factor;
                    }
                }
                that._update(value);
                value = that._value;
                if (that._old != value) {
                    that._old = value;
                    if (!that._typing) {
                        that.element.trigger(CHANGE);
                    }
                    that.trigger(CHANGE);
                }
                that._typing = false;
            },
            _culture: function (culture) {
                return culture || getCulture(this.options.culture);
            },
            _focusin: function () {
                var that = this;
                that._inputWrapper.addClass(FOCUSED);
                that._toggleText(false);
                that.element[0].focus();
            },
            _focusout: function () {
                var that = this;
                clearTimeout(that._focusing);
                that._inputWrapper.removeClass(FOCUSED).removeClass(HOVER);
                that._blur();
                that._removeInvalidState();
            },
            _format: function (format, culture) {
                var numberFormat = this._culture(culture).numberFormat;
                format = format.toLowerCase();
                if (format.indexOf('c') > -1) {
                    numberFormat = numberFormat.currency;
                } else if (format.indexOf('p') > -1) {
                    numberFormat = numberFormat.percent;
                }
                return numberFormat;
            },
            _input: function () {
                var that = this, options = that.options, CLASSNAME = 'k-formatted-value', element = that.element.addClass(INPUT).show()[0], accessKey = element.accessKey, wrapper = that.wrapper, text;
                text = wrapper.find(POINT + CLASSNAME);
                if (!text[0]) {
                    text = $('<input type="text"/>').insertBefore(element).addClass(CLASSNAME);
                }
                try {
                    element.setAttribute('type', 'text');
                } catch (e) {
                    element.type = 'text';
                }
                that._initialTitle = element.title;
                text[0].title = element.title;
                text[0].tabIndex = element.tabIndex;
                text[0].style.cssText = element.style.cssText;
                text.prop('placeholder', options.placeholder);
                if (accessKey) {
                    text.attr('accesskey', accessKey);
                    element.accessKey = '';
                }
                that._text = text.addClass(element.className).attr({
                    'role': 'spinbutton',
                    'aria-valuemin': options.min !== NULL ? options.min * options.factor : options.min,
                    'aria-valuemax': options.max !== NULL ? options.max * options.factor : options.max
                });
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode;
                that._key = key;
                if (key == keys.DOWN) {
                    that._step(-1);
                } else if (key == keys.UP) {
                    that._step(1);
                } else if (key == keys.ENTER) {
                    that._change(that.element.val());
                } else {
                    that._typing = true;
                }
            },
            _keypress: function (e) {
                if (e.which === 0 || e.metaKey || e.ctrlKey || e.keyCode === keys.BACKSPACE || e.keyCode === keys.ENTER) {
                    return;
                }
                var that = this;
                var min = that.options.min;
                var element = that.element;
                var selection = caret(element);
                var selectionStart = selection[0];
                var selectionEnd = selection[1];
                var character = String.fromCharCode(e.which);
                var numberFormat = that._format(that.options.format);
                var isNumPadDecimal = that._key === keys.NUMPAD_DOT;
                var value = element.val();
                var isValid;
                if (isNumPadDecimal) {
                    character = numberFormat[POINT];
                }
                value = value.substring(0, selectionStart) + character + value.substring(selectionEnd);
                isValid = that._numericRegex(numberFormat).test(value);
                if (isValid && isNumPadDecimal) {
                    element.val(value);
                    caret(element, selectionStart + character.length);
                    e.preventDefault();
                } else if (min !== null && min >= 0 && value.charAt(0) === '-' || !isValid) {
                    that._addInvalidState();
                    e.preventDefault();
                }
                that._key = 0;
            },
            _keyup: function () {
                this._removeInvalidState();
            },
            _addInvalidState: function () {
                var that = this;
                that._inputWrapper.addClass(STATE_INVALID);
                that._validationIcon.show();
            },
            _removeInvalidState: function () {
                var that = this;
                that._inputWrapper.removeClass(STATE_INVALID);
                that._validationIcon.hide();
            },
            _numericRegex: function (numberFormat) {
                var that = this;
                var separator = numberFormat[POINT];
                var precision = that.options.decimals;
                var fractionRule = '*';
                if (separator === POINT) {
                    separator = '\\' + separator;
                }
                if (precision === NULL) {
                    precision = numberFormat.decimals;
                }
                if (precision === 0) {
                    return INTEGER_REGEXP;
                }
                if (that.options.restrictDecimals) {
                    fractionRule = '{0,' + precision + '}';
                }
                if (that._separator !== separator) {
                    that._separator = separator;
                    that._floatRegExp = new RegExp('^(-)?(((\\d+(' + separator + '\\d' + fractionRule + ')?)|(' + separator + '\\d' + fractionRule + ')))?$');
                }
                return that._floatRegExp;
            },
            _paste: function (e) {
                var that = this;
                var element = e.target;
                var value = element.value;
                var numberFormat = that._format(that.options.format);
                setTimeout(function () {
                    var result = that._parse(element.value);
                    var isValid = that._numericRegex(numberFormat).test(element.value);
                    if (result === NULL || that._adjust(result) !== result || !isValid) {
                        that._update(value);
                    }
                });
            },
            _option: function (option, value) {
                var that = this, element = that.element, options = that.options;
                if (value === undefined) {
                    return options[option];
                }
                value = that._parse(value);
                if (!value && option === 'step') {
                    return;
                }
                options[option] = value;
                element.add(that._text).attr('aria-value' + option, value);
                element.attr(option, value);
            },
            _spin: function (step, timeout) {
                var that = this;
                timeout = timeout || 500;
                clearTimeout(that._spinning);
                that._spinning = setTimeout(function () {
                    that._spin(step, 50);
                }, timeout);
                that._step(step);
            },
            _step: function (step) {
                var that = this, element = that.element, value = that._parse(element.val()) || 0;
                if (activeElement() != element[0]) {
                    that._focusin();
                }
                if (that.options.factor && value) {
                    value = value / that.options.factor;
                }
                value += that.options.step * step;
                that._update(that._adjust(value));
                that._typing = false;
                that.trigger(SPIN);
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _toggleText: function (toggle) {
                var that = this;
                that._text.toggle(toggle);
                that.element.toggle(!toggle);
            },
            _parse: function (value, culture) {
                return parse(value, this._culture(culture), this.options.format);
            },
            _round: function (value, precision) {
                var rounder = this.options.round ? kendo._round : truncate;
                return rounder(value, precision);
            },
            _update: function (value) {
                var that = this, options = that.options, factor = options.factor, format = options.format, decimals = options.decimals, culture = that._culture(), numberFormat = that._format(format, culture), isNotNull;
                if (decimals === NULL) {
                    decimals = numberFormat.decimals;
                }
                value = that._parse(value, culture);
                isNotNull = value !== NULL;
                if (isNotNull) {
                    value = parseFloat(that._round(value, decimals), 10);
                }
                that._value = value = that._adjust(value);
                that._placeholder(kendo.toString(value, format, culture));
                if (isNotNull) {
                    if (factor) {
                        value = parseFloat(that._round(value * factor, decimals), 10);
                    }
                    value = value.toString();
                    if (value.indexOf('e') !== -1) {
                        value = that._round(+value, decimals);
                    }
                    value = value.replace(POINT, numberFormat[POINT]);
                } else {
                    value = null;
                }
                that.element.val(value);
                that.element.add(that._text).attr('aria-valuenow', value);
            },
            _placeholder: function (value) {
                var input = this._text;
                input.val(value);
                if (!placeholderSupported && !value) {
                    input.val(this.options.placeholder);
                }
                input.attr('title', this._initialTitle || input.val());
            },
            _wrapper: function () {
                var that = this, element = that.element, DOMElement = element[0], wrapper;
                wrapper = element.parents('.k-numerictextbox');
                if (!wrapper.is('span.k-numerictextbox')) {
                    wrapper = element.hide().wrap('<span class="k-numeric-wrap k-state-default" />').parent();
                    wrapper = wrapper.wrap('<span/>').parent();
                }
                wrapper[0].style.cssText = DOMElement.style.cssText;
                DOMElement.style.width = '';
                that.wrapper = wrapper.addClass('k-widget k-numerictextbox').addClass(DOMElement.className).css('display', '');
                that._inputWrapper = $(wrapper[0].firstChild);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(element[0].value);
                            that.max(that._initialOptions.max);
                            that.min(that._initialOptions.min);
                        });
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            }
        });
        function buttonHtml(direction, text) {
            var className = 'k-i-arrow-' + (direction === 'increase' ? '60-up' : '60-down');
            return '<span unselectable="on" class="k-link k-link-' + direction + '" aria-label="' + text + '" title="' + text + '">' + '<span unselectable="on" class="' + CLASS_ICON + ' ' + className + '"></span>' + '</span>';
        }
        function truncate(value, precision) {
            var parts = parseFloat(value, 10).toString().split(POINT);
            if (parts[1]) {
                parts[1] = parts[1].substring(0, precision);
            }
            return parts.join(POINT);
        }
        ui.plugin(NumericTextBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.filtermenu', [
        'kendo.datepicker',
        'kendo.numerictextbox',
        'kendo.dropdownlist',
        'kendo.binder'
    ], f);
}(function () {
    var __meta__ = {
        id: 'filtermenu',
        name: 'Filtering Menu',
        category: 'framework',
        depends: [
            'datepicker',
            'numerictextbox',
            'dropdownlist',
            'binder'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, proxy = $.proxy, POPUP = 'kendoPopup', INIT = 'init', OPEN = 'open', REFRESH = 'refresh', CHANGE = 'change', NS = '.kendoFilterMenu', EQ = 'Is equal to', NEQ = 'Is not equal to', roles = {
                'number': 'numerictextbox',
                'date': 'datepicker'
            }, mobileRoles = {
                'string': 'text',
                'number': 'number',
                'date': 'date'
            }, isFunction = kendo.isFunction, Widget = ui.Widget;
        var booleanTemplate = '<div>' + '<div class="k-filter-help-text">#=messages.info#</div>' + '<label>' + '<input type="radio" data-#=ns#bind="checked: filters[0].value" value="true" name="filters[0].value"/>' + '#=messages.isTrue#' + '</label>' + '<label>' + '<input type="radio" data-#=ns#bind="checked: filters[0].value" value="false" name="filters[0].value"/>' + '#=messages.isFalse#' + '</label>' + '<div>' + '<button type="submit" class="k-button k-primary">#=messages.filter#</button>' + '<button type="reset" class="k-button">#=messages.clear#</button>' + '</div>' + '</div>';
        var defaultTemplate = '<div>' + '<div class="k-filter-help-text">#=messages.info#</div>' + '<select title="#=messages.operator#" data-#=ns#bind="value: filters[0].operator" data-#=ns#role="dropdownlist">' + '#for(var op in operators){#' + '<option value="#=op#">#=operators[op]#</option>' + '#}#' + '</select>' + '#if(values){#' + '<select title="#=messages.value#" data-#=ns#bind="value:filters[0].value" data-#=ns#text-field="text" data-#=ns#value-field="value" data-#=ns#source=\'#=kendo.stringify(values).replace(/\'/g,"&\\#39;")#\' data-#=ns#role="dropdownlist" data-#=ns#option-label="#=messages.selectValue#" data-#=ns#value-primitive="true">' + '</select>' + '#}else{#' + '<input title="#=messages.value#" data-#=ns#bind="value:filters[0].value" class="k-textbox" type="text" #=role ? "data-" + ns + "role=\'" + role + "\'" : ""# />' + '#}#' + '#if(extra){#' + '<select title="#=messages.logic#" class="k-filter-and" data-#=ns#bind="value: logic" data-#=ns#role="dropdownlist">' + '<option value="and">#=messages.and#</option>' + '<option value="or">#=messages.or#</option>' + '</select>' + '<select title="#=messages.additionalOperator#" data-#=ns#bind="value: filters[1].operator" data-#=ns#role="dropdownlist">' + '#for(var op in operators){#' + '<option value="#=op#">#=operators[op]#</option>' + '#}#' + '</select>' + '#if(values){#' + '<select title="#=messages.additionalValue#" data-#=ns#bind="value:filters[1].value" data-#=ns#text-field="text" data-#=ns#value-field="value" data-#=ns#source=\'#=kendo.stringify(values).replace(/\'/g,"&\\#39;")#\' data-#=ns#role="dropdownlist" data-#=ns#option-label="#=messages.selectValue#" data-#=ns#value-primitive="true">' + '</select>' + '#}else{#' + '<input title="#=messages.additionalValue#" data-#=ns#bind="value: filters[1].value" class="k-textbox" type="text" #=role ? "data-" + ns + "role=\'" + role + "\'" : ""#/>' + '#}#' + '#}#' + '<div>' + '<button type="submit" class="k-button k-primary">#=messages.filter#</button>' + '<button type="reset" class="k-button">#=messages.clear#</button>' + '</div>' + '</div>';
        var defaultMobileTemplate = '<div data-#=ns#role="view" data-#=ns#init-widgets="false" data-#=ns#use-native-scrolling="true" class="k-grid-filter-menu">' + '<div data-#=ns#role="header" class="k-header">' + '<button class="k-button k-i-cancel">#=messages.cancel#</button>' + '#=title#' + '<button type="submit" class="k-button k-submit">#=messages.filter#</button>' + '</div>' + '<form title="#=messages.info#" class="k-filter-menu k-mobile-list">' + '<ul class="k-filter-help-text"><li><span class="k-link">#=messages.info#</span>' + '<ul>' + '<li class="k-item"><label class="k-label">#=messages.operator#' + '<select data-#=ns#bind="value: filters[0].operator">' + '#for(var op in operators){#' + '<option value="#=op#">#=operators[op]#</option>' + '#}#' + '</select>' + '</label></li>' + '<li class="k-item"><label class="k-label">#=messages.value#' + '#if(values){#' + '<select data-#=ns#bind="value:filters[0].value">' + '<option value="">#=messages.selectValue#</option>' + '#for(var val in values){#' + '<option value="#=values[val].value#">#=values[val].text#</option>' + '#}#' + '</select>' + '#}else{#' + '<input data-#=ns#bind="value:filters[0].value" class="k-textbox" type="#=inputType#" ' + '#=useRole ? "data-" + ns + "role=\'" + role + "\'" : ""# />' + '#}#' + '</label></li>' + '#if(extra){#' + '</ul>' + '<ul class="k-filter-help-text"><li><span class="k-link"></span>' + '<li class="k-item"><label class="k-label"><input type="radio" name="logic" class="k-check" data-#=ns#bind="checked: logic" value="and" />#=messages.and#</label></li>' + '<li class="k-item"><label class="k-label"><input type="radio" name="logic" class="k-check" data-#=ns#bind="checked: logic" value="or" />#=messages.or#</label></li>' + '</ul>' + '<ul class="k-filter-help-text"><li><span class="k-link"></span>' + '<li class="k-item"><label class="k-label">#=messages.additionalOperator#' + '<select data-#=ns#bind="value: filters[1].operator">' + '#for(var op in operators){#' + '<option value="#=op#">#=operators[op]#</option>' + '#}#' + '</select>' + '</label></li>' + '<li class="k-item"><label class="k-label">#=messages.additionalValue#' + '#if(values){#' + '<select data-#=ns#bind="value:filters[1].value">' + '<option value="">#=messages.selectValue#</option>' + '#for(var val in values){#' + '<option value="#=values[val].value#">#=values[val].text#</option>' + '#}#' + '</select>' + '#}else{#' + '<input data-#=ns#bind="value:filters[1].value" class="k-textbox" type="#=inputType#" ' + '#=useRole ? "data-" + ns + "role=\'" + role + "\'" : ""# />' + '#}#' + '</label></li>' + '#}#' + '</ul>' + '</li><li class="k-button-container">' + '<button type="reset" class="k-button">#=messages.clear#</button>' + '</li></ul>' + '</div>' + '</form>' + '</div>';
        var booleanMobileTemplate = '<div data-#=ns#role="view" data-#=ns#init-widgets="false" data-#=ns#use-native-scrolling="true" class="k-grid-filter-menu">' + '<div data-#=ns#role="header" class="k-header">' + '<button class="k-button k-i-cancel">#=messages.cancel#</button>' + '#=title#' + '<button type="submit" class="k-button k-submit">#=messages.filter#</button>' + '</div>' + '<form title="#=messages.info#" class="k-filter-menu k-mobile-list">' + '<ul class="k-filter-help-text"><li><span class="k-link">#=messages.info#</span>' + '<ul>' + '<li class="k-item"><label class="k-label">' + '<input class="k-check" type="radio" data-#=ns#bind="checked: filters[0].value" value="true" name="filters[0].value"/>' + '#=messages.isTrue#' + '</label></li>' + '<li class="k-item"><label class="k-label">' + '<input class="k-check" type="radio" data-#=ns#bind="checked: filters[0].value" value="false" name="filters[0].value"/>' + '#=messages.isFalse#' + '</label></li>' + '</ul>' + '</li><li class="k-button-container">' + '<button type="reset" class="k-button">#=messages.clear#</button>' + '</li></ul>' + '</form>' + '</div>';
        function removeFiltersForField(expression, field) {
            if (expression.filters) {
                expression.filters = $.grep(expression.filters, function (filter) {
                    removeFiltersForField(filter, field);
                    if (filter.filters) {
                        return filter.filters.length;
                    } else {
                        return filter.field != field;
                    }
                });
            }
        }
        function convertItems(items) {
            var idx, length, item, value, text, result;
            if (items && items.length) {
                result = [];
                for (idx = 0, length = items.length; idx < length; idx++) {
                    item = items[idx];
                    text = item.text !== '' ? item.text || item.value || item : item.text;
                    value = item.value == null ? item.text || item : item.value;
                    result[idx] = {
                        text: text,
                        value: value
                    };
                }
            }
            return result;
        }
        function clearFilter(filters, field) {
            return $.grep(filters, function (expr) {
                if (expr.filters) {
                    expr.filters = $.grep(expr.filters, function (nested) {
                        return nested.field != field;
                    });
                    return expr.filters.length;
                }
                return expr.field != field;
            });
        }
        var FilterMenu = Widget.extend({
            init: function (element, options) {
                var that = this, type = 'string', operators, initial, link, field;
                Widget.fn.init.call(that, element, options);
                operators = that.operators = options.operators || {};
                element = that.element;
                options = that.options;
                if (!options.appendToElement) {
                    link = element.addClass('k-with-icon k-filterable').find('.k-grid-filter');
                    if (!link[0]) {
                        link = element.prepend('<a class="k-grid-filter" href="#" title="' + options.messages.filter + '" aria-label="' + options.messages.filter + '"><span class="k-icon k-i-filter"></span></a>').find('.k-grid-filter');
                    }
                    link.attr('tabindex', -1).on('click' + NS, proxy(that._click, that));
                }
                that.link = link || $();
                that.dataSource = DataSource.create(options.dataSource);
                that.field = options.field || element.attr(kendo.attr('field'));
                that.model = that.dataSource.reader.model;
                that._parse = function (value) {
                    return value != null ? value + '' : value;
                };
                if (that.model && that.model.fields) {
                    field = that.model.fields[that.field];
                    if (field) {
                        type = field.type || 'string';
                        if (field.parse) {
                            that._parse = proxy(field.parse, field);
                        }
                    }
                }
                if (options.values) {
                    type = 'enums';
                }
                that.type = type;
                operators = operators[type] || options.operators[type];
                for (initial in operators) {
                    break;
                }
                that._defaultFilter = function () {
                    return {
                        field: that.field,
                        operator: initial || 'eq',
                        value: ''
                    };
                };
                that._refreshHandler = proxy(that.refresh, that);
                that.dataSource.bind(CHANGE, that._refreshHandler);
                if (options.appendToElement) {
                    that._init();
                } else {
                    that.refresh();
                }
            },
            _init: function () {
                var that = this, ui = that.options.ui, setUI = isFunction(ui), role;
                that.pane = that.options.pane;
                if (that.pane) {
                    that._isMobile = true;
                }
                if (!setUI) {
                    role = ui || roles[that.type];
                }
                if (that._isMobile) {
                    that._createMobileForm(role);
                } else {
                    that._createForm(role);
                }
                that.form.on('submit' + NS, proxy(that._submit, that)).on('reset' + NS, proxy(that._reset, that));
                if (setUI) {
                    that.form.find('.k-textbox').removeClass('k-textbox').each(function () {
                        ui($(this));
                    });
                }
                that.form.find('[' + kendo.attr('role') + '=numerictextbox]').removeClass('k-textbox').end().find('[' + kendo.attr('role') + '=datetimepicker]').removeClass('k-textbox').end().find('[' + kendo.attr('role') + '=timepicker]').removeClass('k-textbox').end().find('[' + kendo.attr('role') + '=datepicker]').removeClass('k-textbox');
                that.refresh();
                that.trigger(INIT, {
                    field: that.field,
                    container: that.form
                });
                kendo.cycleForm(that.form);
            },
            _createForm: function (role) {
                var that = this, options = that.options, operators = that.operators || {}, type = that.type;
                operators = operators[type] || options.operators[type];
                that.form = $('<form title="' + that.options.messages.info + '" class="k-filter-menu"/>').html(kendo.template(type === 'boolean' ? booleanTemplate : defaultTemplate)({
                    field: that.field,
                    format: options.format,
                    ns: kendo.ns,
                    messages: options.messages,
                    extra: options.extra,
                    operators: operators,
                    type: type,
                    role: role,
                    values: convertItems(options.values)
                }));
                if (!options.appendToElement) {
                    that.popup = that.form[POPUP]({
                        anchor: that.link,
                        open: proxy(that._open, that),
                        activate: proxy(that._activate, that),
                        close: function () {
                            if (that.options.closeCallback) {
                                that.options.closeCallback(that.element);
                            }
                        }
                    }).data(POPUP);
                } else {
                    that.element.append(that.form);
                    that.popup = that.element.closest('.k-popup').data(POPUP);
                }
                that.form.on('keydown' + NS, proxy(that._keydown, that));
            },
            _createMobileForm: function (role) {
                var that = this, options = that.options, operators = that.operators || {}, type = that.type;
                operators = operators[type] || options.operators[type];
                that.form = $('<div />').html(kendo.template(type === 'boolean' ? booleanMobileTemplate : defaultMobileTemplate)({
                    field: that.field,
                    title: options.title || that.field,
                    format: options.format,
                    ns: kendo.ns,
                    messages: options.messages,
                    extra: options.extra,
                    operators: operators,
                    type: type,
                    role: role,
                    useRole: !kendo.support.input.date && type === 'date' || type === 'number',
                    inputType: mobileRoles[type],
                    values: convertItems(options.values)
                }));
                that.view = that.pane.append(that.form.html());
                that.form = that.view.element.find('form');
                that.view.element.on('click', '.k-submit', function (e) {
                    that.form.submit();
                    e.preventDefault();
                }).on('click', '.k-i-cancel', function (e) {
                    that._closeForm();
                    e.preventDefault();
                });
            },
            refresh: function () {
                var that = this, expression = that.dataSource.filter() || {
                        filters: [],
                        logic: 'and'
                    };
                var defaultFilters = [that._defaultFilter()];
                var defaultOperator = that._defaultFilter().operator;
                if (that.options.extra || defaultOperator !== 'isnull' && defaultOperator !== 'isnotnull') {
                    defaultFilters.push(that._defaultFilter());
                }
                that.filterModel = kendo.observable({
                    logic: 'and',
                    filters: defaultFilters
                });
                if (that.form) {
                    kendo.bind(that.form.children().first(), that.filterModel);
                }
                if (that._bind(expression)) {
                    that.link.addClass('k-state-active');
                } else {
                    that.link.removeClass('k-state-active');
                }
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                if (that.form) {
                    kendo.unbind(that.form);
                    kendo.destroy(that.form);
                    that.form.unbind(NS);
                    if (that.popup) {
                        that.popup.destroy();
                        that.popup = null;
                    }
                    that.form = null;
                }
                if (that.view) {
                    that.view.purge();
                    that.view = null;
                }
                that.link.unbind(NS);
                if (that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    that.dataSource = null;
                }
                that.element = that.link = that._refreshHandler = that.filterModel = null;
            },
            _bind: function (expression) {
                var that = this, filters = expression.filters, idx, length, found = false, current = 0, filterModel = that.filterModel, currentFilter, filter;
                for (idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    if (filter.field == that.field) {
                        filterModel.set('logic', expression.logic);
                        currentFilter = filterModel.filters[current];
                        if (!currentFilter) {
                            filterModel.filters.push({ field: that.field });
                            currentFilter = filterModel.filters[current];
                        }
                        currentFilter.set('value', that._parse(filter.value));
                        currentFilter.set('operator', filter.operator);
                        current++;
                        found = true;
                    } else if (filter.filters) {
                        found = found || that._bind(filter);
                    }
                }
                return found;
            },
            _stripFilters: function (filters) {
                return $.grep(filters, function (filter) {
                    return filter.value !== '' && filter.value != null || (filter.operator === 'isnull' || filter.operator === 'isnotnull' || filter.operator === 'isempty' || filter.operator === 'isnotempty');
                });
            },
            _merge: function (expression) {
                var that = this, logic = expression.logic || 'and', filters = this._stripFilters(expression.filters), filter, result = that.dataSource.filter() || {
                        filters: [],
                        logic: 'and'
                    }, idx, length;
                removeFiltersForField(result, that.field);
                for (idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    filter.value = that._parse(filter.value);
                }
                if (filters.length) {
                    if (result.filters.length) {
                        expression.filters = filters;
                        if (result.logic !== 'and') {
                            result.filters = [{
                                    logic: result.logic,
                                    filters: result.filters
                                }];
                            result.logic = 'and';
                        }
                        if (filters.length > 1) {
                            result.filters.push(expression);
                        } else {
                            result.filters.push(filters[0]);
                        }
                    } else {
                        result.filters = filters;
                        result.logic = logic;
                    }
                }
                return result;
            },
            filter: function (expression) {
                var filters = this._stripFilters(expression.filters);
                if (filters.length && this.trigger('change', {
                        filter: {
                            logic: expression.logic,
                            filters: filters
                        },
                        field: this.field
                    })) {
                    return;
                }
                expression = this._merge(expression);
                if (expression.filters.length) {
                    this.dataSource.filter(expression);
                }
            },
            clear: function () {
                var that = this, expression = that.dataSource.filter() || { filters: [] };
                if (this.trigger('change', {
                        filter: null,
                        field: that.field
                    })) {
                    return;
                }
                expression.filters = $.grep(expression.filters, function (filter) {
                    if (filter.filters) {
                        filter.filters = clearFilter(filter.filters, that.field);
                        return filter.filters.length;
                    }
                    return filter.field != that.field;
                });
                if (!expression.filters.length) {
                    expression = null;
                }
                that.dataSource.filter(expression);
            },
            _submit: function (e) {
                e.preventDefault();
                e.stopPropagation();
                this.filter(this.filterModel.toJSON());
                this._closeForm();
            },
            _reset: function () {
                this.clear();
                if (this.options.search && this.container) {
                    this.container.find('label').parent().show();
                }
                this._closeForm();
            },
            _closeForm: function () {
                if (this._isMobile) {
                    this.pane.navigate('', this.options.animations.right);
                } else {
                    this.popup.close();
                }
            },
            _click: function (e) {
                e.preventDefault();
                e.stopPropagation();
                if (!this.popup && !this.pane) {
                    this._init();
                }
                if (this._isMobile) {
                    this.pane.navigate(this.view, this.options.animations.left);
                } else {
                    this.popup.toggle();
                }
            },
            _open: function () {
                var popup;
                $('.k-filter-menu').not(this.form).each(function () {
                    popup = $(this).data(POPUP);
                    if (popup) {
                        popup.close();
                    }
                });
            },
            _activate: function () {
                this.form.find(':kendoFocusable:first').focus();
                this.trigger(OPEN, {
                    field: this.field,
                    container: this.form
                });
            },
            _keydown: function (e) {
                if (e.keyCode == kendo.keys.ESC) {
                    this.popup.close();
                }
            },
            events: [
                INIT,
                'change',
                OPEN
            ],
            options: {
                name: 'FilterMenu',
                extra: true,
                appendToElement: false,
                type: 'string',
                operators: {
                    string: {
                        eq: EQ,
                        neq: NEQ,
                        startswith: 'Starts with',
                        contains: 'Contains',
                        doesnotcontain: 'Does not contain',
                        endswith: 'Ends with',
                        isnull: 'Is null',
                        isnotnull: 'Is not null',
                        isempty: 'Is empty',
                        isnotempty: 'Is not empty'
                    },
                    number: {
                        eq: EQ,
                        neq: NEQ,
                        gte: 'Is greater than or equal to',
                        gt: 'Is greater than',
                        lte: 'Is less than or equal to',
                        lt: 'Is less than',
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    },
                    date: {
                        eq: EQ,
                        neq: NEQ,
                        gte: 'Is after or equal to',
                        gt: 'Is after',
                        lte: 'Is before or equal to',
                        lt: 'Is before',
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    },
                    enums: {
                        eq: EQ,
                        neq: NEQ,
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    }
                },
                messages: {
                    info: 'Show items with value that:',
                    isTrue: 'is true',
                    isFalse: 'is false',
                    filter: 'Filter',
                    clear: 'Clear',
                    and: 'And',
                    or: 'Or',
                    selectValue: '-Select value-',
                    operator: 'Operator',
                    value: 'Value',
                    additionalValue: 'Additional value',
                    additionalOperator: 'Additional operator',
                    logic: 'Filters logic',
                    cancel: 'Cancel'
                },
                animations: {
                    left: 'slide',
                    right: 'slide:right'
                }
            }
        });
        var multiCheckNS = '.kendoFilterMultiCheck';
        function filterValuesForField(expression, field) {
            if (expression.filters) {
                expression.filters = $.grep(expression.filters, function (filter) {
                    filterValuesForField(filter, field);
                    if (filter.filters) {
                        return filter.filters.length;
                    } else {
                        return filter.field == field && filter.operator == 'eq';
                    }
                });
            }
        }
        function flatFilterValues(expression) {
            if (expression.logic == 'and' && expression.filters.length > 1) {
                return [];
            }
            if (expression.filters) {
                return $.map(expression.filters, function (filter) {
                    return flatFilterValues(filter);
                });
            } else if (expression.value !== null && expression.value !== undefined) {
                return [expression.value];
            } else {
                return [];
            }
        }
        function distinct(items, field) {
            var getter = kendo.getter(field, true), result = [], index = 0, seen = {};
            while (index < items.length) {
                var item = items[index++], text = getter(item);
                if (text !== undefined && text !== null && !seen.hasOwnProperty(text)) {
                    result.push(item);
                    seen[text] = true;
                }
            }
            return result;
        }
        function removeDuplicates(dataSelector, dataTextField) {
            return function (e) {
                var items = dataSelector(e);
                return distinct(items, dataTextField);
            };
        }
        var DataSource = kendo.data.DataSource;
        var multiCkeckMobileTemplate = '<div data-#=ns#role="view" data-#=ns#init-widgets="false" class="k-grid-filter-menu">' + '<div data-#=ns#role="header" class="k-header">' + '<button class="k-button k-i-cancel">#=messages.cancel#</button>' + '#=title#' + '<button type="submit" class="k-button k-submit">#=messages.filter#</button>' + '</div>' + '<form class="k-filter-menu k-mobile-list">' + '#if(search){#' + '<div class=\'k-textbox k-space-right\'>' + '<input placeholder=\'#=messages.search#\'/>' + '<span class=\'k-icon k-i-zoom\' />' + '</div>' + '#}#' + '<ul class="k-multicheck-wrap"></ul>' + '</li><li class="k-button-container">' + '#if(messages.selectedItemsFormat){#<div class=\'k-filter-selected-items\'></div>#}#' + '<button type="reset" class="k-button">#=messages.clear#</button>' + '</li></ul>' + '</form>' + '</div>';
        var FilterMultiCheck = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                options = this.options;
                this.element = $(element);
                var field = this.field = this.options.field || this.element.attr(kendo.attr('field'));
                var checkSource = options.checkSource;
                if (this._foreignKeyValues()) {
                    this.checkSource = DataSource.create(options.values);
                    this.checkSource.fetch();
                } else if (options.forceUnique) {
                    checkSource = options.dataSource.options;
                    delete checkSource.pageSize;
                    this.checkSource = DataSource.create(checkSource);
                    this.checkSource.reader.data = removeDuplicates(this.checkSource.reader.data, this.field);
                } else {
                    this.checkSource = DataSource.create(checkSource);
                }
                this.dataSource = options.dataSource;
                this.model = this.dataSource.reader.model;
                this._parse = function (value) {
                    return value + '';
                };
                if (this.model && this.model.fields) {
                    field = this.model.fields[this.field];
                    if (field) {
                        if (field.type == 'number') {
                            this._parse = parseFloat;
                        } else if (field.parse) {
                            this._parse = proxy(field.parse, field);
                        }
                        this.type = field.type || 'string';
                    }
                }
                if (!options.appendToElement) {
                    this._createLink();
                } else {
                    this._init();
                }
                this._refreshHandler = proxy(this.refresh, this);
                this.dataSource.bind(CHANGE, this._refreshHandler);
            },
            _createLink: function () {
                var element = this.element;
                var link = element.addClass('k-with-icon k-filterable').find('.k-grid-filter');
                if (!link[0]) {
                    link = element.prepend('<a class="k-grid-filter" href="#" aria-label="' + this.options.messages.filter + '"><span class="k-icon k-i-filter"/></a>').find('.k-grid-filter');
                }
                this._link = link.attr('tabindex', -1).on('click' + NS, proxy(this._click, this));
            },
            _init: function () {
                var that = this;
                var forceUnique = this.options.forceUnique;
                var options = this.options;
                this.pane = options.pane;
                if (this.pane) {
                    this._isMobile = true;
                }
                this._createForm();
                if (this._foreignKeyValues()) {
                    this.refresh();
                } else if (forceUnique && !this.checkSource.options.serverPaging && this.dataSource.data().length) {
                    this.checkSource.data(distinct(this.dataSource.data(), this.field));
                    this.refresh();
                } else {
                    this._attachProgress();
                    this.checkSource.fetch(function () {
                        that.refresh.call(that);
                    });
                }
                if (!this.options.forceUnique) {
                    this.checkChangeHandler = function () {
                        that.container.empty();
                        that.refresh();
                    };
                    this.checkSource.bind(CHANGE, this.checkChangeHandler);
                }
                this.form.on('keydown' + multiCheckNS, proxy(this._keydown, this)).on('submit' + multiCheckNS, proxy(this._filter, this)).on('reset' + multiCheckNS, proxy(this._reset, this));
                this.trigger(INIT, {
                    field: this.field,
                    container: this.form
                });
            },
            _attachProgress: function () {
                var that = this;
                this._progressHandler = function () {
                    ui.progress(that.container, true);
                };
                this._progressHideHandler = function () {
                    ui.progress(that.container, false);
                };
                this.checkSource.bind('progress', this._progressHandler).bind('change', this._progressHideHandler);
            },
            _input: function () {
                var that = this;
                that._clearTypingTimeout();
                that._typingTimeout = setTimeout(function () {
                    that.search();
                }, 100);
            },
            _clearTypingTimeout: function () {
                if (this._typingTimeout) {
                    clearTimeout(this._typingTimeout);
                    this._typingTimeout = null;
                }
            },
            search: function () {
                var ignoreCase = this.options.ignoreCase;
                var searchString = this.searchTextBox[0].value;
                var labels = this.container.find('label');
                if (ignoreCase) {
                    searchString = searchString.toLowerCase();
                }
                var i = 0;
                if (this.options.checkAll && labels.length) {
                    labels[0].parentNode.style.display = searchString ? 'none' : '';
                    i++;
                }
                while (i < labels.length) {
                    var label = labels[i];
                    var labelText = label.textContent || label.innerText;
                    if (ignoreCase) {
                        labelText = labelText.toLowerCase();
                    }
                    label.parentNode.style.display = labelText.indexOf(searchString) >= 0 ? '' : 'none';
                    i++;
                }
            },
            _activate: function () {
                this.form.find(':kendoFocusable:first').focus();
                this.trigger(OPEN, {
                    field: this.field,
                    container: this.form
                });
            },
            _createForm: function () {
                var options = this.options;
                var html = '';
                if (!this._isMobile) {
                    if (options.search) {
                        html += '<div class=\'k-textbox k-space-right\'>' + '<input placeholder=\'' + options.messages.search + '\'/>' + '<span class=\'k-icon k-i-zoom\' />' + '</div>';
                    }
                    html += '<ul class=\'k-reset k-multicheck-wrap\'></ul>';
                    if (options.messages.selectedItemsFormat) {
                        html += '<div class=\'k-filter-selected-items\'>' + kendo.format(options.messages.selectedItemsFormat, 0) + '</div>';
                    }
                    html += '<button type=\'submit\' class=\'k-button k-primary\'>' + options.messages.filter + '</button>';
                    html += '<button type=\'reset\' class=\'k-button\'>' + options.messages.clear + '</button>';
                    this.form = $('<form class="k-filter-menu"/>').html(html);
                    this.container = this.form.find('.k-multicheck-wrap');
                }
                if (this._isMobile) {
                    var that = this;
                    that.form = $('<div />').html(kendo.template(multiCkeckMobileTemplate)({
                        field: that.field,
                        title: options.title || that.field,
                        ns: kendo.ns,
                        messages: options.messages,
                        search: options.search
                    }));
                    that.view = that.pane.append(that.form.html());
                    that.form = that.view.element.find('form');
                    var element = this.view.element;
                    this.container = element.find('.k-multicheck-wrap');
                    element.on('click', '.k-submit', function (e) {
                        that.form.submit();
                        e.preventDefault();
                    }).on('click', '.k-i-cancel', function (e) {
                        that._closeForm();
                        e.preventDefault();
                    });
                } else {
                    if (!options.appendToElement) {
                        this.popup = this.form.kendoPopup({
                            anchor: this._link,
                            activate: proxy(this._activate, this)
                        }).data(POPUP);
                    } else {
                        this.popup = this.element.closest('.k-popup').data(POPUP);
                        this.element.append(this.form);
                    }
                }
                if (options.search) {
                    this.searchTextBox = this.form.find('.k-textbox > input');
                    this.searchTextBox.on('input', proxy(this._input, this));
                }
            },
            createCheckAllItem: function () {
                var options = this.options;
                var template = kendo.template(options.itemTemplate({
                    field: 'all',
                    mobile: this._isMobile
                }));
                var checkAllContainer = $(template({ all: options.messages.checkAll }));
                this.container.prepend(checkAllContainer);
                this.checkBoxAll = checkAllContainer.find(':checkbox').eq(0).addClass('k-check-all');
                this.checkAllHandler = proxy(this.checkAll, this);
                this.checkBoxAll.on(CHANGE + multiCheckNS, this.checkAllHandler);
            },
            updateCheckAllState: function () {
                if (this.options.messages.selectedItemsFormat) {
                    this.form.find('.k-filter-selected-items').text(kendo.format(this.options.messages.selectedItemsFormat, this.container.find(':checked:not(.k-check-all)').length));
                }
                if (this.checkBoxAll) {
                    var state = this.container.find(':checkbox:not(.k-check-all)').length == this.container.find(':checked:not(.k-check-all)').length;
                    this.checkBoxAll.prop('checked', state);
                }
            },
            refresh: function (e) {
                var forceUnique = this.options.forceUnique;
                var dataSource = this.dataSource;
                var filters = this.getFilterArray();
                if (this._link) {
                    this._link.toggleClass('k-state-active', filters.length !== 0);
                }
                if (this.form) {
                    if (e && forceUnique && e.sender === dataSource && !dataSource.options.serverPaging && (e.action == 'itemchange' || e.action == 'add' || e.action == 'remove' || dataSource.options.autoSync && e.action === 'sync') && !this._foreignKeyValues()) {
                        this.checkSource.data(distinct(this.dataSource.data(), this.field));
                        this.container.empty();
                    }
                    if (this.container.is(':empty')) {
                        this.createCheckBoxes();
                    }
                    this.checkValues(filters);
                    this.trigger(REFRESH);
                }
            },
            getFilterArray: function () {
                var expression = $.extend(true, {}, {
                    filters: [],
                    logic: 'and'
                }, this.dataSource.filter());
                filterValuesForField(expression, this.field);
                var flatValues = flatFilterValues(expression);
                return flatValues;
            },
            createCheckBoxes: function () {
                var options = this.options;
                var data;
                var templateOptions = {
                    field: this.field,
                    format: options.format,
                    mobile: this._isMobile,
                    type: this.type
                };
                if (!this.options.forceUnique) {
                    data = this.checkSource.view();
                } else if (this._foreignKeyValues()) {
                    data = this.checkSource.data();
                    templateOptions.valueField = 'value';
                    templateOptions.field = 'text';
                } else {
                    data = this.checkSource.data();
                }
                var template = kendo.template(options.itemTemplate(templateOptions));
                var itemsHtml = kendo.render(template, data);
                if (options.checkAll) {
                    this.createCheckAllItem();
                }
                this.container.on(CHANGE + multiCheckNS, ':checkbox', proxy(this.updateCheckAllState, this));
                this.container.append(itemsHtml);
            },
            checkAll: function () {
                var state = this.checkBoxAll.is(':checked');
                this.container.find(':checkbox').prop('checked', state);
            },
            checkValues: function (values) {
                var that = this;
                $($.grep(this.container.find(':checkbox').prop('checked', false), function (ele) {
                    var found = false;
                    if ($(ele).is('.k-check-all')) {
                        return;
                    }
                    var checkBoxVal = that._parse($(ele).val());
                    for (var i = 0; i < values.length; i++) {
                        if (that.type == 'date') {
                            found = values[i].getTime() == checkBoxVal.getTime();
                        } else {
                            found = values[i] == checkBoxVal;
                        }
                        if (found) {
                            return found;
                        }
                    }
                })).prop('checked', true);
                this.updateCheckAllState();
            },
            _filter: function (e) {
                e.preventDefault();
                e.stopPropagation();
                var expression = { logic: 'or' };
                var that = this;
                expression.filters = $.map(this.form.find(':checkbox:checked:not(.k-check-all)'), function (item) {
                    return {
                        value: $(item).val(),
                        operator: 'eq',
                        field: that.field
                    };
                });
                if (expression.filters.length && this.trigger('change', {
                        filter: expression,
                        field: that.field
                    })) {
                    return;
                }
                expression = this._merge(expression);
                if (expression.filters.length) {
                    this.dataSource.filter(expression);
                }
                this._closeForm();
            },
            _stripFilters: function (filters) {
                return $.grep(filters, function (filter) {
                    return filter.value != null;
                });
            },
            _foreignKeyValues: function () {
                var options = this.options;
                return options.values && !options.checkSource;
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                if (that.form) {
                    kendo.unbind(that.form);
                    kendo.destroy(that.form);
                    that.form.unbind(multiCheckNS);
                    if (that.popup) {
                        that.popup.destroy();
                        that.popup = null;
                    }
                    that.form = null;
                    if (that.container) {
                        that.container.unbind(multiCheckNS);
                        that.container = null;
                    }
                    if (that.checkBoxAll) {
                        that.checkBoxAll.unbind(multiCheckNS);
                    }
                }
                if (that.view) {
                    that.view.purge();
                    that.view = null;
                }
                if (that._link) {
                    that._link.unbind(NS);
                }
                if (that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    that.dataSource = null;
                }
                if (that.checkChangeHandler) {
                    that.checkSource.unbind(CHANGE, that.checkChangeHandler);
                }
                if (that._progressHandler) {
                    that.checkSource.unbind('progress', that._progressHandler);
                }
                if (that._progressHideHandler) {
                    that.checkSource.unbind('change', that._progressHideHandler);
                }
                this._clearTypingTimeout();
                this.searchTextBox = null;
                that.element = that.checkSource = that.container = that.checkBoxAll = that._link = that._refreshHandler = that.checkAllHandler = null;
            },
            options: {
                name: 'FilterMultiCheck',
                itemTemplate: function (options) {
                    var field = options.field;
                    var format = options.format;
                    var valueField = options.valueField;
                    var mobile = options.mobile;
                    var valueFormat = '';
                    if (valueField === undefined) {
                        valueField = field;
                    }
                    if (options.type == 'date') {
                        valueFormat = ':yyyy-MM-ddTHH:mm:sszzz';
                    }
                    return '<li class=\'k-item\'>' + '<label class=\'k-label\'>' + '<input type=\'checkbox\' class=\'' + (mobile ? 'k-check' : '') + '\'  value=\'#:kendo.format(\'{0' + valueFormat + '}\',' + valueField + ')#\'/>' + '#:kendo.format(\'' + (format ? format : '{0}') + '\', ' + field + ')#' + '</label>' + '</li>';
                },
                checkAll: true,
                search: false,
                ignoreCase: true,
                appendToElement: false,
                messages: {
                    checkAll: 'Select All',
                    clear: 'Clear',
                    filter: 'Filter',
                    search: 'Search',
                    cancel: 'Cancel',
                    selectedItemsFormat: '{0} items selected'
                },
                forceUnique: true,
                animations: {
                    left: 'slide',
                    right: 'slide:right'
                }
            },
            events: [
                INIT,
                REFRESH,
                'change',
                OPEN
            ]
        });
        $.extend(FilterMultiCheck.fn, {
            _click: FilterMenu.fn._click,
            _keydown: FilterMenu.fn._keydown,
            _reset: FilterMenu.fn._reset,
            _closeForm: FilterMenu.fn._closeForm,
            clear: FilterMenu.fn.clear,
            _merge: FilterMenu.fn._merge
        });
        ui.plugin(FilterMenu);
        ui.plugin(FilterMultiCheck);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.menu', ['kendo.popup'], f);
}(function () {
    var __meta__ = {
        id: 'menu',
        name: 'Menu',
        category: 'web',
        description: 'The Menu widget displays hierarchical data as a multi-level menu.',
        depends: ['popup']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, activeElement = kendo._activeElement, touch = kendo.support.touch && kendo.support.mobileOS, MOUSEDOWN = 'mousedown', CLICK = 'click', DELAY = 30, SCROLLSPEED = 50, extend = $.extend, proxy = $.proxy, each = $.each, template = kendo.template, keys = kendo.keys, Widget = ui.Widget, excludedNodesRegExp = /^(ul|a|div)$/i, NS = '.kendoMenu', IMG = 'img', OPEN = 'open', MENU = 'k-menu', LINK = 'k-link', LAST = 'k-last', CLOSE = 'close', TIMER = 'timer', FIRST = 'k-first', IMAGE = 'k-image', SELECT = 'select', ZINDEX = 'zIndex', ACTIVATE = 'activate', DEACTIVATE = 'deactivate', POINTERDOWN = 'touchstart' + NS + ' MSPointerDown' + NS + ' pointerdown' + NS, pointers = kendo.support.pointers, msPointers = kendo.support.msPointers, allPointers = msPointers || pointers, MOUSEENTER = pointers ? 'pointerenter' : msPointers ? 'MSPointerEnter' : 'mouseenter', MOUSELEAVE = pointers ? 'pointerleave' : msPointers ? 'MSPointerLeave' : 'mouseleave', MOUSEWHEEL = 'DOMMouseScroll' + NS + ' mousewheel' + NS, RESIZE = kendo.support.resize + NS, SCROLLWIDTH = 'scrollWidth', SCROLLHEIGHT = 'scrollHeight', OFFSETWIDTH = 'offsetWidth', OFFSETHEIGHT = 'offsetHeight', POPUP_ID_ATTR = 'group', POPUP_OPENER_ATTR = 'groupparent', DOCUMENT_ELEMENT = $(document.documentElement), KENDOPOPUP = 'kendoPopup', DEFAULTSTATE = 'k-state-default', HOVERSTATE = 'k-state-hover', FOCUSEDSTATE = 'k-state-focused', DISABLEDSTATE = 'k-state-disabled', SELECTEDSTATE = 'k-state-selected', menuSelector = '.k-menu', groupSelector = '.k-menu-group', animationContainerSelector = '.k-animation-container', popupSelector = groupSelector + ',' + animationContainerSelector, allItemsSelector = ':not(.k-list) > .k-item', disabledSelector = '.k-item.k-state-disabled', itemSelector = '.k-item:not(.k-state-disabled)', linkSelector = '.k-item:not(.k-state-disabled) > .k-link', exclusionSelector = ':not(.k-item.k-separator)', nextSelector = exclusionSelector + ':eq(0)', lastSelector = exclusionSelector + ':last', templateSelector = 'div:not(.k-animation-container,.k-list-container)', scrollButtonSelector = '.k-menu-scroll-button', touchPointerTypes = {
                '2': 1,
                'touch': 1
            }, templates = {
                content: template('<div #= contentCssAttributes(item) # tabindex=\'-1\'>#= content(item) #</div>'),
                group: template('<ul class=\'#= groupCssClass(group) #\'#= groupAttributes(group) # role=\'menu\' aria-hidden=\'true\'>' + '#= renderItems(data) #' + '</ul>'),
                itemWrapper: template('<#= tag(item) # class=\'#= textClass(item) #\'#= textAttributes(item) #>' + '#= image(data) ##= sprite(item) ##= text(item) #' + '#= arrow(data) #' + '</#= tag(item) #>'),
                item: template('<li class=\'#= wrapperCssClass(group, item) #\' #= itemCssAttributes(item) # role=\'menuitem\'  #=item.items ? "aria-haspopup=\'true\'": ""#' + '#=item.enabled === false ? "aria-disabled=\'true\'" : \'\'#>' + '#= itemWrapper(data) #' + '# if (item.items) { #' + '#= subGroup({ items: item.items, menu: menu, group: { expanded: item.expanded } }) #' + '# } else if (item.content || item.contentUrl) { #' + '#= renderContent(data) #' + '# } #' + '</li>'),
                scrollButton: template('<span class=\'k-button k-button-icon k-menu-scroll-button k-scroll-#= direction #\' unselectable=\'on\'>' + '<span class=\'k-icon k-i-arrow-60-#= direction #\'></span></span>'),
                image: template('<img #= imageCssAttributes(item) # alt=\'\' src=\'#= item.imageUrl #\' />'),
                arrow: template('<span class=\'#= arrowClass(item, group) #\'></span>'),
                sprite: template('<span class=\'k-sprite #= spriteCssClass #\'></span>'),
                empty: template('')
            }, rendering = {
                wrapperCssClass: function (group, item) {
                    var result = 'k-item', index = item.index;
                    if (item.enabled === false) {
                        result += ' k-state-disabled';
                    } else {
                        result += ' k-state-default';
                    }
                    if (group.firstLevel && index === 0) {
                        result += ' k-first';
                    }
                    if (index == group.length - 1) {
                        result += ' k-last';
                    }
                    if (item.cssClass) {
                        result += ' ' + item.cssClass;
                    }
                    if (item.attr && item.attr.hasOwnProperty('class')) {
                        result += ' ' + item.attr['class'];
                    }
                    if (item.selected) {
                        result += ' ' + SELECTEDSTATE;
                    }
                    return result;
                },
                itemCssAttributes: function (item) {
                    var result = '';
                    var attributes = item.attr || {};
                    for (var attr in attributes) {
                        if (attributes.hasOwnProperty(attr) && attr !== 'class') {
                            result += attr + '="' + attributes[attr] + '" ';
                        }
                    }
                    return result;
                },
                imageCssAttributes: function (item) {
                    var result = '';
                    var attributes = item.imageAttr || {};
                    if (!attributes['class']) {
                        attributes['class'] = IMAGE;
                    } else {
                        attributes['class'] += ' ' + IMAGE;
                    }
                    for (var attr in attributes) {
                        if (attributes.hasOwnProperty(attr)) {
                            result += attr + '="' + attributes[attr] + '" ';
                        }
                    }
                    return result;
                },
                contentCssAttributes: function (item) {
                    var result = '';
                    var attributes = item.contentAttr || {};
                    var defaultClasses = 'k-content k-group k-menu-group';
                    if (!attributes['class']) {
                        attributes['class'] = defaultClasses;
                    } else {
                        attributes['class'] += ' ' + defaultClasses;
                    }
                    for (var attr in attributes) {
                        if (attributes.hasOwnProperty(attr)) {
                            result += attr + '="' + attributes[attr] + '" ';
                        }
                    }
                    return result;
                },
                textClass: function () {
                    return LINK;
                },
                textAttributes: function (item) {
                    return item.url ? ' href=\'' + item.url + '\'' : '';
                },
                arrowClass: function (item, group) {
                    var result = 'k-icon';
                    if (group.horizontal) {
                        result += ' k-i-arrow-60-down';
                    } else {
                        result += ' k-i-arrow-60-right';
                    }
                    return result;
                },
                text: function (item) {
                    return item.encoded === false ? item.text : kendo.htmlEncode(item.text);
                },
                tag: function (item) {
                    return item.url ? 'a' : 'span';
                },
                groupAttributes: function (group) {
                    return group.expanded !== true ? ' style=\'display:none\'' : '';
                },
                groupCssClass: function () {
                    return 'k-group k-menu-group';
                },
                content: function (item) {
                    return item.content ? item.content : '&nbsp;';
                }
            };
        function getEffectDirection(direction, root) {
            direction = direction.split(' ')[!root + 0] || direction;
            return direction.replace('top', 'up').replace('bottom', 'down');
        }
        function parseDirection(direction, root, isRtl) {
            direction = direction.split(' ')[!root + 0] || direction;
            var output = {
                    origin: [
                        'bottom',
                        isRtl ? 'right' : 'left'
                    ],
                    position: [
                        'top',
                        isRtl ? 'right' : 'left'
                    ]
                }, horizontal = /left|right/.test(direction);
            if (horizontal) {
                output.origin = [
                    'top',
                    direction
                ];
                output.position[1] = kendo.directions[direction].reverse;
            } else {
                output.origin[0] = direction;
                output.position[0] = kendo.directions[direction].reverse;
            }
            output.origin = output.origin.join(' ');
            output.position = output.position.join(' ');
            return output;
        }
        function contains(parent, child) {
            try {
                return $.contains(parent, child);
            } catch (e) {
                return false;
            }
        }
        function updateItemClasses(item) {
            item = $(item);
            item.addClass('k-item').children(IMG).addClass(IMAGE);
            item.children('a').addClass(LINK).children(IMG).addClass(IMAGE);
            item.filter(':not([disabled])').addClass(DEFAULTSTATE);
            item.filter('.k-separator').empty().append('&nbsp;');
            item.filter('li[disabled]').addClass(DISABLEDSTATE).removeAttr('disabled').attr('aria-disabled', true);
            if (!item.filter('[role]').length) {
                item.attr('role', 'menuitem');
            }
            if (!item.children('.' + LINK).length) {
                item.contents().filter(function () {
                    return !this.nodeName.match(excludedNodesRegExp) && !(this.nodeType == 3 && !$.trim(this.nodeValue));
                }).wrapAll('<span class=\'' + LINK + '\'/>');
            }
            updateArrow(item);
            updateFirstLast(item);
        }
        function updateArrow(item) {
            item = $(item);
            item.find('> .k-link > [class*=k-i-arrow]:not(.k-sprite)').remove();
            item.filter(':has(.k-menu-group)').children('.k-link:not(:has([class*=k-i-arrow]:not(.k-sprite)))').each(function () {
                var item = $(this), arrowCssClass = getArrowCssClass(item);
                item.append('<span class=\'k-icon ' + arrowCssClass + '\'/>');
            });
        }
        function getArrowCssClass(item) {
            var arrowCssClass, parent = item.parent().parent(), isRtl = kendo.support.isRtl(parent);
            if (parent.hasClass(MENU + '-horizontal')) {
                arrowCssClass = ' k-i-arrow-60-down';
            } else {
                if (isRtl) {
                    arrowCssClass = ' k-i-arrow-60-left';
                } else {
                    arrowCssClass = ' k-i-arrow-60-right';
                }
            }
            return arrowCssClass;
        }
        function updateFirstLast(item) {
            item = $(item);
            item.filter('.k-first:not(:first-child)').removeClass(FIRST);
            item.filter('.k-last:not(:last-child)').removeClass(LAST);
            item.filter(':first-child').addClass(FIRST);
            item.filter(':last-child').addClass(LAST);
        }
        function storeItemSelectEventHandler(element, options) {
            var selectHandler = getItemSelectEventHandler(options);
            if (selectHandler) {
                setItemData(element, selectHandler);
            }
            if (options.items) {
                $(element).children('ul').children('li').each(function (i) {
                    storeItemSelectEventHandler(this, options.items[i]);
                });
            }
        }
        function setItemData(element, selectHandler) {
            $(element).children('.k-link').data({ selectHandler: selectHandler });
        }
        function getItemSelectEventHandler(options) {
            var selectHandler = options.select, isFunction = kendo.isFunction;
            if (selectHandler && isFunction(selectHandler)) {
                return selectHandler;
            }
            return null;
        }
        function popupOpenerSelector(id) {
            return id ? 'li[data-groupparent=\'' + id + '\']' : 'li[data-groupparent]';
        }
        function popupGroupSelector(id) {
            return id ? 'ul[data-group=\'' + id + '\']' : 'ul[data-group]';
        }
        function getChildPopups(currentPopup, overflowWrapper) {
            var childPopupOpener = currentPopup.find(popupOpenerSelector());
            var result = [];
            childPopupOpener.each(function (i, opener) {
                opener = $(opener);
                var popupId = opener.data(POPUP_OPENER_ATTR);
                var popup = currentPopup;
                while (popupId) {
                    popup = overflowWrapper.find(popupGroupSelector(popupId) + ':visible');
                    if (popup.length) {
                        result.push(popup);
                    }
                    opener = popup.find(popupOpenerSelector());
                    popupId = opener.data(POPUP_OPENER_ATTR);
                }
            });
            return result;
        }
        function popupParentItem(popupElement, overflowWrapper) {
            var popupId = popupElement.data(POPUP_ID_ATTR);
            return popupId ? overflowWrapper.find(popupOpenerSelector(popupId)) : $([]);
        }
        function itemPopup(item, overflowWrapper) {
            var popupId = item.data(POPUP_OPENER_ATTR);
            return popupId ? overflowWrapper.children(animationContainerSelector).children(popupGroupSelector(popupId)) : $([]);
        }
        function overflowMenuParents(current, overflowWrapper) {
            var parents = [];
            var getParents = function (item) {
                while (item.parentNode && !overflowWrapper.is(item.parentNode)) {
                    parents.push(item.parentNode);
                    item = item.parentNode;
                }
            };
            var elem = current[0] || current;
            getParents(elem);
            var last = parents[parents.length - 1];
            while ($(last).is(animationContainerSelector)) {
                var popupElement = $(last).children('ul');
                elem = popupParentItem(popupElement, overflowWrapper)[0];
                if (!elem) {
                    break;
                }
                parents.push(elem);
                getParents(elem);
                last = parents[parents.length - 1];
            }
            return parents;
        }
        function mousewheelDelta(e) {
            var delta = 0;
            if (e.wheelDelta) {
                delta = -e.wheelDelta / 120;
                delta = delta > 0 ? Math.ceil(delta) : Math.floor(delta);
            }
            if (e.detail) {
                delta = Math.round(e.detail / 3);
            }
            return delta;
        }
        function parentsScroll(current, scrollDirection) {
            var scroll = 0;
            var parent = current.parentNode;
            while (parent && !isNaN(parent[scrollDirection])) {
                scroll += parent[scrollDirection];
                parent = parent.parentNode;
            }
            return scroll;
        }
        function isPointerTouch(e) {
            return allPointers && e.originalEvent.pointerType in touchPointerTypes;
        }
        function isTouch(e) {
            var ev = e.originalEvent;
            return touch && /touch/i.test(ev.type || '');
        }
        function removeSpacesBetweenItems(ul) {
            ul.contents().filter(function () {
                return this.nodeName != 'LI';
            }).remove();
        }
        var Menu = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                element = that.wrapper = that.element;
                options = that.options;
                that._initData(options);
                that._updateClasses();
                that._animations(options);
                that.nextItemZIndex = 100;
                that._tabindex();
                that._initOverflow(options);
                that._attachMenuEventsHandlers();
                if (options.openOnClick) {
                    that.clicked = false;
                }
                element.attr('role', 'menubar');
                if (element[0].id) {
                    that._ariaId = kendo.format('{0}_mn_active', element[0].id);
                }
                kendo.notify(that);
            },
            events: [
                OPEN,
                CLOSE,
                ACTIVATE,
                DEACTIVATE,
                SELECT
            ],
            options: {
                name: 'Menu',
                animation: {
                    open: { duration: 200 },
                    close: { duration: 100 }
                },
                orientation: 'horizontal',
                direction: 'default',
                openOnClick: false,
                closeOnClick: true,
                hoverDelay: 100,
                scrollable: false,
                popupCollision: undefined
            },
            _initData: function (options) {
                var that = this;
                if (options.dataSource) {
                    that.angular('cleanup', function () {
                        return { elements: that.element.children() };
                    });
                    that.element.empty();
                    that.append(options.dataSource, that.element);
                    that.angular('compile', function () {
                        return { elements: that.element.children() };
                    });
                }
            },
            _attachMenuEventsHandlers: function () {
                var that = this;
                var element = that.element;
                var options = that.options;
                var overflowWrapper = that._overflowWrapper();
                (overflowWrapper || element).on(POINTERDOWN, itemSelector, proxy(that._focusHandler, that)).on(CLICK + NS, disabledSelector, false).on(CLICK + NS, itemSelector, proxy(that._click, that)).on(POINTERDOWN + ' ' + MOUSEDOWN + NS, '.k-content', proxy(that._preventClose, that)).on(MOUSEENTER + NS, itemSelector, proxy(that._mouseenter, that)).on(MOUSELEAVE + NS, itemSelector, proxy(that._mouseleave, that)).on(MOUSEENTER + NS + ' ' + MOUSELEAVE + NS + ' ' + MOUSEDOWN + NS + ' ' + CLICK + NS, linkSelector, proxy(that._toggleHover, that));
                element.on('keydown' + NS, proxy(that._keydown, that)).on('focus' + NS, proxy(that._focus, that)).on('focus' + NS, '.k-content', proxy(that._focus, that)).on('blur' + NS, proxy(that._removeHoverItem, that)).on('blur' + NS, '[tabindex]', proxy(that._checkActiveElement, that));
                if (overflowWrapper) {
                    overflowWrapper.on(MOUSELEAVE + NS, popupSelector, proxy(that._mouseleavePopup, that)).on(MOUSEENTER + NS, popupSelector, proxy(that._mouseenterPopup, that));
                }
                if (options.openOnClick) {
                    that._documentClickHandler = proxy(that._documentClick, that);
                    $(document).click(that._documentClickHandler);
                }
            },
            _detachMenuEventsHandlers: function () {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                if (overflowWrapper) {
                    overflowWrapper.off(NS);
                }
                that.element.off(NS);
                if (that._documentClickHandler) {
                    $(document).unbind('click', that._documentClickHandler);
                }
            },
            _initOverflow: function (options) {
                var that = this;
                var isHorizontal = options.orientation == 'horizontal';
                var backwardBtn, forwardBtn;
                if (options.scrollable) {
                    that._openedPopups = {};
                    that._scrollWrapper = that.element.wrap('<div class=\'k-menu-scroll-wrapper ' + options.orientation + '\'></div>').parent();
                    if (isHorizontal) {
                        removeSpacesBetweenItems(that.element);
                    }
                    backwardBtn = $(templates.scrollButton({ direction: isHorizontal ? 'left' : 'up' }));
                    forwardBtn = $(templates.scrollButton({ direction: isHorizontal ? 'right' : 'down' }));
                    backwardBtn.add(forwardBtn).appendTo(that._scrollWrapper);
                    that._initScrolling(that.element, backwardBtn, forwardBtn, isHorizontal);
                    var initialWidth = that.element.outerWidth();
                    var initialCssWidth = that.element[0].style.width;
                    initialCssWidth = initialCssWidth === 'auto' ? '' : initialCssWidth;
                    if (isHorizontal) {
                        $(window).on(RESIZE, kendo.throttle(function () {
                            that._setOverflowWrapperWidth(initialWidth, initialCssWidth);
                            that._toggleScrollButtons(that.element, backwardBtn, forwardBtn, isHorizontal);
                        }, 100));
                    }
                    that._setOverflowWrapperWidth(initialWidth, initialCssWidth);
                    that._toggleScrollButtons(that.element, backwardBtn, forwardBtn, isHorizontal);
                }
            },
            _overflowWrapper: function () {
                return this._scrollWrapper || this._popupsWrapper;
            },
            _setOverflowWrapperWidth: function (initialWidth, initialCssWidth) {
                var that = this;
                var wrapperCssWidth = that._scrollWrapper.css('width');
                that._scrollWrapper.css({ width: '' });
                var wrapperWidth = that._scrollWrapper.outerWidth();
                that._scrollWrapper.css({ width: wrapperCssWidth });
                var menuWidth = that.element.outerWidth();
                var borders = that.element[0].offsetWidth - that.element[0].clientWidth;
                if (menuWidth != wrapperWidth) {
                    var width = initialCssWidth ? Math.min(initialWidth, wrapperWidth) : wrapperWidth;
                    that.element.width(width - borders);
                    that._scrollWrapper.width(width);
                }
            },
            _reinitOverflow: function (options) {
                var that = this;
                var overflowChanged = options.scrollable && !that.options.scrollable || !options.scrollable && that.options.scrollable || options.scrollable && that.options.scrollable && options.scrollable.distance != that.options.scrollable.distance || options.orientation != that.options.orientation;
                if (overflowChanged) {
                    that._detachMenuEventsHandlers();
                    that._destroyOverflow();
                    that._initOverflow(options);
                    that._attachMenuEventsHandlers();
                }
            },
            _destroyOverflow: function () {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                if (overflowWrapper) {
                    overflowWrapper.off(NS);
                    overflowWrapper.find(scrollButtonSelector).off(NS).remove();
                    overflowWrapper.children(animationContainerSelector).each(function (i, popupWrapper) {
                        var ul = $(popupWrapper).children(groupSelector);
                        ul.off(MOUSEWHEEL);
                        var popupParentLi = popupParentItem(ul, overflowWrapper);
                        if (popupParentLi.length) {
                            popupParentLi.append(popupWrapper);
                        }
                    });
                    overflowWrapper.find(popupOpenerSelector()).removeAttr('data-groupparent');
                    overflowWrapper.find(popupGroupSelector()).removeAttr('data-group');
                    that.element.off(MOUSEWHEEL);
                    $(window).off(RESIZE);
                    overflowWrapper.contents().unwrap();
                    that._scrollWrapper = that._popupsWrapper = that._openedPopups = undefined;
                }
            },
            _initScrolling: function (scrollElement, backwardBtn, forwardBtn, isHorizontal) {
                var that = this;
                var scrollable = that.options.scrollable;
                var distance = $.isNumeric(scrollable.distance) ? scrollable.distance : SCROLLSPEED;
                var mouseWheelDistance = distance / 2;
                var backward = '-=' + distance;
                var forward = '+=' + distance;
                var backwardDouble = '-=' + distance * 2;
                var forwardDouble = '+=' + distance * 2;
                var scrolling = false;
                var touchEvents = false;
                var scroll = function (value) {
                    var scrollValue = isHorizontal ? { 'scrollLeft': value } : { 'scrollTop': value };
                    scrollElement.finish().animate(scrollValue, 'fast', 'linear', function () {
                        if (scrolling) {
                            scroll(value);
                        }
                    });
                    that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal);
                };
                var mouseenterHandler = function (e) {
                    if (!scrolling && !touchEvents) {
                        scroll(e.data.direction);
                        scrolling = true;
                    }
                };
                var mousedownHandler = function (e) {
                    var scrollValue = isHorizontal ? { 'scrollLeft': e.data.direction } : { 'scrollTop': e.data.direction };
                    touchEvents = isTouch(e) || isPointerTouch(e);
                    scrollElement.stop().animate(scrollValue, 'fast', 'linear', function () {
                        if (!touchEvents) {
                            $(e.currentTarget).trigger(MOUSEENTER);
                        } else {
                            that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal);
                            scrolling = true;
                        }
                    });
                    scrolling = false;
                    e.stopPropagation();
                    e.preventDefault();
                };
                backwardBtn.on(MOUSEENTER + NS, { direction: backward }, mouseenterHandler).on(kendo.eventMap.down + NS, { direction: backwardDouble }, mousedownHandler);
                forwardBtn.on(MOUSEENTER + NS, { direction: forward }, mouseenterHandler).on(kendo.eventMap.down + NS, { direction: forwardDouble }, mousedownHandler);
                backwardBtn.add(forwardBtn).on(MOUSELEAVE + NS, function () {
                    scrollElement.stop();
                    scrolling = false;
                    that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal);
                });
                scrollElement.on(MOUSEWHEEL, function (e) {
                    if (!e.ctrlKey && !e.shiftKey && !e.altKey) {
                        var wheelDelta = mousewheelDelta(e.originalEvent);
                        var scrollSpeed = Math.abs(wheelDelta) * mouseWheelDistance;
                        var value = (wheelDelta > 0 ? '+=' : '-=') + scrollSpeed;
                        var scrollValue = isHorizontal ? { 'scrollLeft': value } : { 'scrollTop': value };
                        that._closeChildPopups(scrollElement);
                        scrollElement.finish().animate(scrollValue, 'fast', 'linear', function () {
                            that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal);
                        });
                        e.preventDefault();
                    }
                });
            },
            _toggleScrollButtons: function (scrollElement, backwardBtn, forwardBtn, horizontal) {
                var currentScroll = horizontal ? scrollElement.scrollLeft() : scrollElement.scrollTop();
                var scrollSize = horizontal ? SCROLLWIDTH : SCROLLHEIGHT;
                var offset = horizontal ? OFFSETWIDTH : OFFSETHEIGHT;
                backwardBtn.toggle(currentScroll !== 0);
                forwardBtn.toggle(currentScroll < scrollElement[0][scrollSize] - scrollElement[0][offset] - 1);
            },
            setOptions: function (options) {
                var animation = this.options.animation;
                this._animations(options);
                options.animation = extend(true, animation, options.animation);
                if ('dataSource' in options) {
                    this._initData(options);
                }
                this._updateClasses();
                this._reinitOverflow(options);
                Widget.fn.setOptions.call(this, options);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that._detachMenuEventsHandlers();
                that._destroyOverflow();
                kendo.destroy(that.element);
            },
            enable: function (element, enable) {
                this._toggleDisabled(element, enable !== false);
                return this;
            },
            disable: function (element) {
                this._toggleDisabled(element, false);
                return this;
            },
            append: function (item, referenceItem) {
                referenceItem = this.element.find(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.length ? referenceItem.find('> .k-menu-group, > .k-animation-container > .k-menu-group') : null);
                each(inserted.items, function (i) {
                    inserted.group.append(this);
                    updateArrow(this);
                    storeItemSelectEventHandler(this, item[i] || item);
                });
                updateArrow(referenceItem);
                updateFirstLast(inserted.group.find('.k-first, .k-last').add(inserted.items));
                return this;
            },
            insertBefore: function (item, referenceItem) {
                referenceItem = this.element.find(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.parent());
                each(inserted.items, function (i) {
                    referenceItem.before(this);
                    updateArrow(this);
                    updateFirstLast(this);
                    storeItemSelectEventHandler(this, item[i] || item);
                });
                updateFirstLast(referenceItem);
                return this;
            },
            insertAfter: function (item, referenceItem) {
                referenceItem = this.element.find(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.parent());
                each(inserted.items, function (i) {
                    referenceItem.after(this);
                    updateArrow(this);
                    updateFirstLast(this);
                    storeItemSelectEventHandler(this, item[i] || item);
                });
                updateFirstLast(referenceItem);
                return this;
            },
            _insert: function (item, referenceItem, parent) {
                var that = this, items, groups;
                if (!referenceItem || !referenceItem.length) {
                    parent = that.element;
                }
                var plain = $.isPlainObject(item), groupData = {
                        firstLevel: parent.hasClass(MENU),
                        horizontal: parent.hasClass(MENU + '-horizontal'),
                        expanded: true,
                        length: parent.children().length
                    };
                if (referenceItem && !parent.length) {
                    parent = $(Menu.renderGroup({ group: groupData })).appendTo(referenceItem);
                }
                if (plain || $.isArray(item)) {
                    items = $($.map(plain ? [item] : item, function (value, idx) {
                        if (typeof value === 'string') {
                            return $(value).get();
                        } else {
                            return $(Menu.renderItem({
                                group: groupData,
                                item: extend(value, { index: idx })
                            })).get();
                        }
                    }));
                } else {
                    if (typeof item == 'string' && item.charAt(0) != '<') {
                        items = that.element.find(item);
                    } else {
                        items = $(item);
                    }
                    groups = items.find('> ul').addClass('k-menu-group').attr('role', 'menu');
                    items = items.filter('li');
                    items.add(groups.find('> li')).each(function () {
                        updateItemClasses(this);
                    });
                }
                return {
                    items: items,
                    group: parent
                };
            },
            remove: function (element) {
                element = this.element.find(element);
                var that = this, parent = element.parentsUntil(that.element, allItemsSelector), group = element.parent('ul:not(.k-menu)');
                element.remove();
                if (group && !group.children(allItemsSelector).length) {
                    var container = group.parent(animationContainerSelector);
                    if (container.length) {
                        container.remove();
                    } else {
                        group.remove();
                    }
                }
                if (parent.length) {
                    parent = parent.eq(0);
                    updateArrow(parent);
                    updateFirstLast(parent);
                }
                return that;
            },
            open: function (element) {
                var that = this;
                var options = that.options;
                var horizontal = options.orientation == 'horizontal';
                var direction = options.direction;
                var isRtl = kendo.support.isRtl(that.wrapper);
                var overflowWrapper = that._overflowWrapper();
                element = (overflowWrapper || that.element).find(element);
                if (/^(top|bottom|default)$/.test(direction)) {
                    if (isRtl) {
                        direction = horizontal ? (direction + ' left').replace('default', 'bottom') : 'left';
                    } else {
                        direction = horizontal ? (direction + ' right').replace('default', 'bottom') : 'right';
                    }
                }
                var visiblePopups = '>.k-popup:visible,>.k-animation-container>.k-popup:visible';
                var closePopup = function () {
                    var popup = $(this).data(KENDOPOPUP);
                    if (popup) {
                        popup.close(true);
                    }
                };
                element.siblings().find(visiblePopups).each(closePopup);
                if (overflowWrapper) {
                    element.find(visiblePopups).each(closePopup);
                    overflowWrapper.find('.' + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
                }
                element.each(function () {
                    var li = $(this);
                    clearTimeout(li.data(TIMER));
                    li.data(TIMER, setTimeout(function () {
                        var ul = li.find('.k-menu-group:first:hidden');
                        var popup;
                        var overflowPopup;
                        if (!ul[0] && overflowWrapper) {
                            overflowPopup = that._getPopup(li);
                            ul = overflowPopup && overflowPopup.element;
                        }
                        if (ul.is(':visible')) {
                            return;
                        }
                        if (ul[0] && that._triggerEvent({
                                item: li[0],
                                type: OPEN
                            }) === false) {
                            if (!ul.find('.k-menu-group')[0] && ul.children('.k-item').length > 1) {
                                var windowHeight = $(window).height(), setScrolling = function () {
                                        ul.css({
                                            maxHeight: windowHeight - (kendo._outerHeight(ul) - ul.height()) - kendo.getShadows(ul).bottom,
                                            overflow: 'auto'
                                        });
                                    };
                                if (kendo.support.browser.msie && kendo.support.browser.version <= 7) {
                                    setTimeout(setScrolling, 0);
                                } else {
                                    setScrolling();
                                }
                            } else {
                                ul.css({
                                    maxHeight: '',
                                    overflow: ''
                                });
                            }
                            li.data(ZINDEX, li.css(ZINDEX));
                            var nextZindex = that.nextItemZIndex++;
                            li.css(ZINDEX, nextZindex);
                            if (that.options.scrollable) {
                                li.parent().siblings(scrollButtonSelector).css({ zIndex: ++nextZindex });
                            }
                            popup = ul.data(KENDOPOPUP);
                            var root = li.parent().hasClass(MENU), parentHorizontal = root && horizontal, directions = parseDirection(direction, root, isRtl), effects = options.animation.open.effects, openEffects = effects !== undefined ? effects : 'slideIn:' + getEffectDirection(direction, root);
                            if (!popup) {
                                popup = ul.kendoPopup({
                                    activate: function () {
                                        that._triggerEvent({
                                            item: this.wrapper.parent(),
                                            type: ACTIVATE
                                        });
                                    },
                                    deactivate: function (e) {
                                        e.sender.element.removeData('targetTransform').css({ opacity: '' });
                                        that._triggerEvent({
                                            item: this.wrapper.parent(),
                                            type: DEACTIVATE
                                        });
                                    },
                                    origin: directions.origin,
                                    position: directions.position,
                                    collision: options.popupCollision !== undefined ? options.popupCollision : parentHorizontal ? 'fit' : 'fit flip',
                                    anchor: li,
                                    appendTo: overflowWrapper || li,
                                    animation: {
                                        open: extend(true, { effects: openEffects }, options.animation.open),
                                        close: options.animation.close
                                    },
                                    open: proxy(that._popupOpen, that),
                                    close: function (e) {
                                        var li = e.sender.wrapper.parent();
                                        if (overflowWrapper) {
                                            var popupId = e.sender.element.data(POPUP_ID_ATTR);
                                            if (popupId) {
                                                li = (overflowWrapper || that.element).find(popupOpenerSelector(popupId));
                                            }
                                            e.sender.wrapper.children(scrollButtonSelector).hide();
                                        }
                                        if (!that._triggerEvent({
                                                item: li[0],
                                                type: CLOSE
                                            })) {
                                            li.css(ZINDEX, li.data(ZINDEX));
                                            li.removeData(ZINDEX);
                                            if (that.options.scrollable) {
                                                li.parent().siblings(scrollButtonSelector).css({ zIndex: '' });
                                            }
                                            if (touch || allPointers) {
                                                li.removeClass(HOVERSTATE);
                                                that._removeHoverItem();
                                            }
                                        } else {
                                            e.preventDefault();
                                        }
                                    }
                                }).data(KENDOPOPUP);
                            } else {
                                popup = ul.data(KENDOPOPUP);
                                popup.options.origin = directions.origin;
                                popup.options.position = directions.position;
                                popup.options.animation.open.effects = openEffects;
                            }
                            ul.removeAttr('aria-hidden');
                            that._configurePopupOverflow(popup, li);
                            popup.open();
                            that._initPopupScrolling(popup);
                        }
                    }, that.options.hoverDelay));
                });
                return that;
            },
            _configurePopupOverflow: function (popup, popupOpener) {
                var that = this;
                if (that.options.scrollable) {
                    that._wrapPopupElement(popup);
                    if (!popupOpener.attr('data-groupparent')) {
                        var groupId = new Date().getTime();
                        popupOpener.attr('data-groupparent', groupId);
                        popup.element.attr('data-group', groupId);
                    }
                }
            },
            _wrapPopupElement: function (popup) {
                if (!popup.element.parent().is(animationContainerSelector)) {
                    popup.wrapper = kendo.wrap(popup.element, popup.options.autosize).css({
                        overflow: 'hidden',
                        display: 'block',
                        position: 'absolute'
                    });
                }
            },
            _initPopupScrolling: function (popup, isHorizontal, skipMouseEvents) {
                var that = this;
                if (that.options.scrollable && popup.element[0].scrollHeight > popup.element[0].offsetHeight) {
                    that._initPopupScrollButtons(popup, isHorizontal, skipMouseEvents);
                }
            },
            _initPopupScrollButtons: function (popup, isHorizontal, skipMouseEvents) {
                var that = this;
                var scrollButtons = popup.wrapper.children(scrollButtonSelector);
                var animation = that.options.animation;
                var timeout = (animation && animation.open && animation.open.duration || 0) + DELAY;
                setTimeout(function () {
                    if (!scrollButtons.length) {
                        var backwardBtn = $(templates.scrollButton({ direction: isHorizontal ? 'left' : 'up' }));
                        var forwardBtn = $(templates.scrollButton({ direction: isHorizontal ? 'right' : 'down' }));
                        scrollButtons = backwardBtn.add(forwardBtn).appendTo(popup.wrapper);
                        that._initScrolling(popup.element, backwardBtn, forwardBtn, isHorizontal);
                        if (!skipMouseEvents) {
                            scrollButtons.on(MOUSEENTER + NS, function () {
                                var overflowWrapper = that._overflowWrapper();
                                $(getChildPopups(popup.element, overflowWrapper)).each(function (i, p) {
                                    var popupOpener = overflowWrapper.find(popupOpenerSelector(p.data(POPUP_ID_ATTR)));
                                    that.close(popupOpener);
                                });
                            }).on(MOUSELEAVE + NS, function () {
                                setTimeout(function () {
                                    if ($.isEmptyObject(that._openedPopups)) {
                                        that._closeParentPopups(popup.element);
                                    }
                                }, DELAY);
                            });
                        }
                    }
                    that._toggleScrollButtons(popup.element, scrollButtons.first(), scrollButtons.last(), isHorizontal);
                }, timeout);
            },
            _popupOpen: function (e) {
                if (this.options.scrollable) {
                    this._setPopupHeight(e.sender);
                }
            },
            _setPopupHeight: function (popup, isFixed) {
                var popupElement = popup.element;
                var popups = popupElement.add(popupElement.parent(animationContainerSelector));
                popups.height(popupElement.hasClass(MENU) && this._initialHeight || '');
                var location = popup._location(isFixed);
                var windowHeight = $(window).height();
                var popupOuterHeight = location.height;
                var popupOffsetTop = isFixed ? 0 : Math.max(location.top, 0);
                var scrollTop = isFixed ? 0 : parentsScroll(this._overflowWrapper()[0], 'scrollTop');
                var bottomScrollbar = window.innerHeight - windowHeight;
                var maxHeight = windowHeight - kendo.getShadows(popupElement).bottom + bottomScrollbar;
                var canFit = maxHeight + scrollTop > popupOuterHeight + popupOffsetTop;
                if (!canFit) {
                    var height = Math.min(maxHeight, maxHeight - popupOffsetTop + scrollTop);
                    popups.css({
                        overflow: 'hidden',
                        height: height + 'px'
                    });
                }
            },
            close: function (items, dontClearClose) {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                var element = overflowWrapper || that.element;
                items = element.find(items);
                if (!items.length) {
                    items = element.find('>.k-item');
                }
                var hasChildPopupsHovered = function (currentPopup) {
                    var result = false;
                    if ($.isEmptyObject(that._openedPopups)) {
                        return result;
                    }
                    $(getChildPopups(currentPopup, overflowWrapper)).each(function (i, popup) {
                        result = !!that._openedPopups[popup.data(POPUP_ID_ATTR).toString()];
                        return !result;
                    });
                    return result;
                };
                var isPopupMouseLeaved = function (opener) {
                    var groupId = opener.data(POPUP_OPENER_ATTR);
                    return !overflowWrapper || !groupId || !that._openedPopups[groupId.toString()];
                };
                items.each(function () {
                    var li = $(this);
                    if (!dontClearClose && that._isRootItem(li)) {
                        that.clicked = false;
                    }
                    clearTimeout(li.data(TIMER));
                    li.data(TIMER, setTimeout(function () {
                        var popup = that._getPopup(li);
                        if (popup && (isPopupMouseLeaved(li) || that._forceClose)) {
                            if (!that._forceClose && hasChildPopupsHovered(popup.element)) {
                                return;
                            }
                            popup.close();
                            popup.element.attr('aria-hidden', true);
                            if (overflowWrapper) {
                                if (that._forceClose && items.last().is(li[0])) {
                                    delete that._forceClose;
                                }
                            }
                        }
                    }, that.options.hoverDelay));
                });
                return that;
            },
            _getPopup: function (li) {
                var that = this;
                var popup = li.find('.k-menu-group:not(.k-list-container):not(.k-calendar-container):first:visible').data(KENDOPOPUP);
                var overflowWrapper = that._overflowWrapper();
                if (!popup && overflowWrapper) {
                    var groupId = li.data(POPUP_OPENER_ATTR);
                    if (groupId) {
                        var popupElement = overflowWrapper.find(popupGroupSelector(groupId));
                        popup = popupElement.data(KENDOPOPUP);
                    }
                }
                return popup;
            },
            _toggleDisabled: function (items, enable) {
                this.element.find(items).each(function () {
                    $(this).toggleClass(DEFAULTSTATE, enable).toggleClass(DISABLEDSTATE, !enable).attr('aria-disabled', !enable);
                });
            },
            _toggleHover: function (e) {
                var target = $(kendo.eventTarget(e) || e.target).closest(allItemsSelector), isEnter = e.type == MOUSEENTER || MOUSEDOWN.indexOf(e.type) !== -1;
                if (!target.parents('li.' + DISABLEDSTATE).length) {
                    target.toggleClass(HOVERSTATE, isEnter || e.type == 'mousedown' || e.type == 'click');
                }
                this._removeHoverItem();
            },
            _preventClose: function () {
                if (!this.options.closeOnClick) {
                    this._closurePrevented = true;
                }
            },
            _checkActiveElement: function (e) {
                var that = this, hoverItem = $(e ? e.currentTarget : this._hoverItem()), target = that._findRootParent(hoverItem)[0];
                if (!this._closurePrevented) {
                    setTimeout(function () {
                        if (!document.hasFocus() || !contains(target, kendo._activeElement()) && e && !contains(target, e.currentTarget)) {
                            that.close(target);
                        }
                    }, 0);
                }
                this._closurePrevented = false;
            },
            _removeHoverItem: function () {
                var oldHoverItem = this._hoverItem();
                if (oldHoverItem && oldHoverItem.hasClass(FOCUSEDSTATE)) {
                    oldHoverItem.removeClass(FOCUSEDSTATE);
                    this._oldHoverItem = null;
                }
            },
            _updateClasses: function () {
                var element = this.element, nonContentGroupsSelector = '.k-menu-init div ul', items;
                element.removeClass('k-menu-horizontal k-menu-vertical');
                element.addClass('k-widget k-reset k-header k-menu-init ' + MENU).addClass(MENU + '-' + this.options.orientation);
                element.find('li > ul').filter(function () {
                    return !kendo.support.matchesSelector.call(this, nonContentGroupsSelector);
                }).addClass('k-group k-menu-group').attr('role', 'menu').attr('aria-hidden', element.is(':visible')).end().find('li > div').addClass('k-content').attr('tabindex', '-1');
                items = element.find('> li,.k-menu-group > li');
                element.removeClass('k-menu-init');
                items.each(function () {
                    updateItemClasses(this);
                });
            },
            _mouseenter: function (e) {
                var that = this;
                var element = $(e.currentTarget);
                var hasChildren = that._itemHasChildren(element);
                var popupId = element.data(POPUP_OPENER_ATTR) || element.parent().data(POPUP_ID_ATTR);
                var pointerTouch = isPointerTouch(e);
                if (popupId) {
                    that._openedPopups[popupId.toString()] = true;
                }
                if (e.delegateTarget != element.parents(menuSelector)[0] && e.delegateTarget != element.parents('.k-menu-scroll-wrapper,.k-popups-wrapper')[0]) {
                    return;
                }
                if ((!that.options.openOnClick || that.clicked) && !touch && !(pointerTouch && that._isRootItem(element.closest(allItemsSelector)))) {
                    if (!contains(e.currentTarget, e.relatedTarget) && hasChildren) {
                        that.open(element);
                    }
                }
                if (that.options.openOnClick && that.clicked || touch) {
                    element.siblings().each(proxy(function (_, sibling) {
                        that.close(sibling, true);
                    }, that));
                }
            },
            _mouseleave: function (e) {
                var that = this;
                var element = $(e.currentTarget);
                var popupOpener = element.data(POPUP_OPENER_ATTR);
                var hasChildren = element.children(animationContainerSelector).length || element.children(groupSelector).length || popupOpener;
                var $window = $(window);
                if (popupOpener) {
                    delete that._openedPopups[popupOpener.toString()];
                }
                if (element.parentsUntil(animationContainerSelector, '.k-list-container,.k-calendar-container')[0]) {
                    e.stopImmediatePropagation();
                    return;
                }
                if (!that.options.openOnClick && !touch && !isPointerTouch(e) && !contains(e.currentTarget, e.relatedTarget || e.target) && hasChildren && !contains(e.currentTarget, kendo._activeElement())) {
                    that.close(element);
                    return;
                }
                if (!e.toElement && !e.relatedTarget || e.clientX < 0 || e.clientY < 0 || e.clientY > $window.height() || e.clientX > $window.width()) {
                    that.close(element);
                }
            },
            _mouseenterPopup: function (e) {
                var that = this;
                var popupElement = $(e.currentTarget);
                if (popupElement.parent().is(animationContainerSelector)) {
                    return;
                }
                popupElement = popupElement.children('ul');
                var popupId = popupElement.data(POPUP_ID_ATTR);
                if (popupId) {
                    that._openedPopups[popupId.toString()] = true;
                }
            },
            _mouseleavePopup: function (e) {
                var that = this;
                var popupElement = $(e.currentTarget);
                if (!isPointerTouch(e) && popupElement.is(animationContainerSelector)) {
                    that._closePopups(popupElement.children('ul'));
                }
            },
            _closePopups: function (rootPopup) {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                var popupId = rootPopup.data(POPUP_ID_ATTR);
                if (popupId) {
                    delete that._openedPopups[popupId.toString()];
                    var groupParent = overflowWrapper.find(popupOpenerSelector(popupId));
                    setTimeout(function () {
                        if (that.options.openOnClick) {
                            that._closeChildPopups(rootPopup);
                        } else {
                            if ($.isEmptyObject(that._openedPopups)) {
                                var innerPopup = that._innerPopup(rootPopup);
                                that._closeParentPopups(innerPopup);
                            } else {
                                that.close(groupParent, true);
                            }
                        }
                    }, 0);
                }
            },
            _closeChildPopups: function (current) {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                $(getChildPopups(current, overflowWrapper)).each(function () {
                    var popupOpener = overflowWrapper.find(popupOpenerSelector(this.data(POPUP_ID_ATTR)));
                    that.close(popupOpener, true);
                });
            },
            _innerPopup: function (current) {
                var overflowWrapper = this._overflowWrapper();
                var popups = getChildPopups(current, overflowWrapper);
                return popups[popups.length - 1] || current;
            },
            _closeParentPopups: function (current) {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                var popupId = current.data(POPUP_ID_ATTR);
                var popupOpener = overflowWrapper.find(popupOpenerSelector(popupId));
                popupId = popupOpener.parent().data(POPUP_ID_ATTR);
                that.close(popupOpener, true);
                while (popupId && !that._openedPopups[popupId]) {
                    if (popupOpener.parent().is(menuSelector)) {
                        break;
                    }
                    popupOpener = overflowWrapper.find(popupOpenerSelector(popupId));
                    that.close(popupOpener, true);
                    popupId = popupOpener.parent().data(POPUP_ID_ATTR);
                }
            },
            _click: function (e) {
                var that = this, openHandle, options = that.options, target = $(kendo.eventTarget(e)), targetElement = target[0], nodeName = target[0] ? target[0].nodeName.toUpperCase() : '', formNode = nodeName == 'INPUT' || nodeName == 'SELECT' || nodeName == 'BUTTON' || nodeName == 'LABEL', link = target.closest('.' + LINK), element = target.closest(allItemsSelector), itemElement = element[0], href = link.attr('href'), childGroup, childGroupVisible, targetHref = target.attr('href'), sampleHref = $('<a href=\'#\' />').attr('href'), isLink = !!href && href !== sampleHref, isLocalLink = isLink && !!href.match(/^#/), isTargetLink = !!targetHref && targetHref !== sampleHref, overflowWrapper = that._overflowWrapper(), shouldCloseTheRootItem;
                while (targetElement && targetElement.parentNode != itemElement) {
                    targetElement = targetElement.parentNode;
                }
                if ($(targetElement).is(templateSelector)) {
                    return;
                }
                if (element.hasClass(DISABLEDSTATE)) {
                    e.preventDefault();
                    return;
                }
                if (!e.handled && that._triggerSelect(target, itemElement) && !formNode) {
                    e.preventDefault();
                }
                e.handled = true;
                childGroup = element.children(popupSelector);
                if (overflowWrapper) {
                    var childPopupId = element.data(POPUP_OPENER_ATTR);
                    if (childPopupId) {
                        childGroup = overflowWrapper.find(popupGroupSelector(childPopupId));
                    }
                }
                childGroupVisible = childGroup.is(':visible');
                shouldCloseTheRootItem = options.openOnClick && childGroupVisible && that._isRootItem(element);
                if (options.closeOnClick && (!isLink || isLocalLink) && (!childGroup.length || shouldCloseTheRootItem)) {
                    element.removeClass(HOVERSTATE).css('height');
                    that._oldHoverItem = that._findRootParent(element);
                    var item = that._parentsUntil(link, that.element, allItemsSelector);
                    that._forceClose = !!overflowWrapper;
                    that.close(item);
                    that.clicked = false;
                    if ('MSPointerUp'.indexOf(e.type) != -1) {
                        e.preventDefault();
                    }
                    return;
                }
                if (isLink && e.enterKey) {
                    link[0].click();
                }
                if ((!that._isRootItem(element) || !options.openOnClick) && !kendo.support.touch && !(allPointers && that._isRootItem(element.closest(allItemsSelector)))) {
                    return;
                }
                if (!isLink && !formNode && !isTargetLink) {
                    e.preventDefault();
                }
                that.clicked = true;
                openHandle = childGroup.is(':visible') ? CLOSE : OPEN;
                if (!options.closeOnClick && openHandle == CLOSE) {
                    return;
                }
                that[openHandle](element);
            },
            _parentsUntil: function (context, top, selector) {
                var overflowWrapper = this._overflowWrapper();
                if (!overflowWrapper) {
                    return context.parentsUntil(top, selector);
                } else {
                    var parents = overflowMenuParents(context, overflowWrapper);
                    var result = [];
                    $(parents).each(function () {
                        var parent = $(this);
                        if (parent.is(top)) {
                            return false;
                        }
                        if (parent.is(selector)) {
                            result.push(this);
                        }
                    });
                    return $(result);
                }
            },
            _triggerSelect: function (target, itemElement) {
                var selectHandler = target.data('selectHandler'), itemSelectEventData;
                if (selectHandler) {
                    itemSelectEventData = this._getEventData(target);
                    selectHandler.call(this, itemSelectEventData);
                }
                var isSelectItemDefaultPrevented = itemSelectEventData && itemSelectEventData.isDefaultPrevented();
                var isSelectDefaultPrevented = this._triggerEvent({
                    item: itemElement,
                    type: SELECT
                });
                return isSelectItemDefaultPrevented || isSelectDefaultPrevented;
            },
            _getEventData: function (target) {
                var eventData = {
                    sender: this,
                    target: target,
                    _defaultPrevented: false,
                    preventDefault: function () {
                        this._defaultPrevented = true;
                    },
                    isDefaultPrevented: function () {
                        return this._defaultPrevented;
                    }
                };
                return eventData;
            },
            _documentClick: function (e) {
                var that = this;
                if (contains((that._overflowWrapper() || that.element)[0], e.target)) {
                    return;
                }
                that.clicked = false;
            },
            _focus: function (e) {
                var that = this, target = e.target, hoverItem = that._hoverItem(), active = activeElement();
                if (target != that.wrapper[0] && !$(target).is(':kendoFocusable')) {
                    e.stopPropagation();
                    $(target).closest('.k-content').closest('.k-menu-group').closest('.k-item').addClass(FOCUSEDSTATE);
                    that.wrapper.focus();
                    return;
                }
                if (active === e.currentTarget) {
                    if (hoverItem.length) {
                        that._moveHover([], hoverItem);
                    } else if (!that._oldHoverItem) {
                        that._moveHover([], that.wrapper.children().first());
                    }
                }
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, hoverItem = that._oldHoverItem, target, belongsToVertical, hasChildren, isRtl = kendo.support.isRtl(that.wrapper);
                if (e.target != e.currentTarget && key != keys.ESC) {
                    return;
                }
                if (!hoverItem) {
                    hoverItem = that._oldHoverItem = that._hoverItem();
                }
                belongsToVertical = that._itemBelongsToVertival(hoverItem);
                hasChildren = that._itemHasChildren(hoverItem);
                if (key == keys.RIGHT) {
                    target = that[isRtl ? '_itemLeft' : '_itemRight'](hoverItem, belongsToVertical, hasChildren);
                } else if (key == keys.LEFT) {
                    target = that[isRtl ? '_itemRight' : '_itemLeft'](hoverItem, belongsToVertical, hasChildren);
                } else if (key == keys.DOWN) {
                    target = that._itemDown(hoverItem, belongsToVertical, hasChildren);
                } else if (key == keys.UP) {
                    target = that._itemUp(hoverItem, belongsToVertical, hasChildren);
                } else if (key == keys.ESC) {
                    target = that._itemEsc(hoverItem, belongsToVertical);
                } else if (key == keys.ENTER || key == keys.SPACEBAR) {
                    target = hoverItem.children('.k-link');
                    if (target.length > 0) {
                        that._click({
                            target: target[0],
                            preventDefault: function () {
                            },
                            enterKey: true
                        });
                        that._moveHover(hoverItem, that._findRootParent(hoverItem));
                    }
                } else if (key == keys.TAB) {
                    target = that._findRootParent(hoverItem);
                    that._moveHover(hoverItem, target);
                    that._checkActiveElement();
                    return;
                }
                if (target && target[0]) {
                    e.preventDefault();
                    e.stopPropagation();
                }
            },
            _hoverItem: function () {
                return this.wrapper.find('.k-item.k-state-hover,.k-item.k-state-focused').filter(':visible');
            },
            _itemBelongsToVertival: function (item) {
                var menuIsVertical = this.wrapper.hasClass('k-menu-vertical');
                if (!item.length) {
                    return menuIsVertical;
                }
                return item.parent().hasClass('k-menu-group') || menuIsVertical;
            },
            _itemHasChildren: function (item) {
                if (!item || !item.length || !item[0].nodeType) {
                    return false;
                }
                return item.children('ul.k-menu-group, div.k-animation-container').length > 0 || !!item.data(POPUP_OPENER_ATTR) && !!this._overflowWrapper().children(popupGroupSelector(item.data(POPUP_OPENER_ATTR)));
            },
            _moveHover: function (item, nextItem) {
                var that = this, id = that._ariaId;
                if (item.length && nextItem.length) {
                    item.removeClass(FOCUSEDSTATE);
                }
                if (nextItem.length) {
                    if (nextItem[0].id) {
                        id = nextItem[0].id;
                    }
                    nextItem.addClass(FOCUSEDSTATE);
                    that._oldHoverItem = nextItem;
                    if (id) {
                        that.element.removeAttr('aria-activedescendant');
                        $('#' + id).removeAttr('id');
                        nextItem.attr('id', id);
                        that.element.attr('aria-activedescendant', id);
                    }
                    that._scrollToItem(nextItem);
                }
            },
            _findRootParent: function (item) {
                if (this._isRootItem(item)) {
                    return item;
                } else {
                    return this._parentsUntil(item, menuSelector, 'li.k-item').last();
                }
            },
            _isRootItem: function (item) {
                return item.parent().hasClass(MENU);
            },
            _itemRight: function (item, belongsToVertical, hasChildren) {
                var that = this, nextItem, parentItem, overflowWrapper;
                if (item.hasClass(DISABLEDSTATE)) {
                    return;
                }
                if (!belongsToVertical) {
                    nextItem = item.nextAll(nextSelector);
                    if (!nextItem.length) {
                        nextItem = item.prevAll(lastSelector);
                    }
                } else if (hasChildren) {
                    that.open(item);
                    nextItem = that._childPopupElement(item).children().first();
                } else if (that.options.orientation == 'horizontal') {
                    parentItem = that._findRootParent(item);
                    overflowWrapper = that._overflowWrapper();
                    if (overflowWrapper) {
                        var rootPopup = itemPopup(parentItem, overflowWrapper);
                        that._closeChildPopups(rootPopup);
                    }
                    that.close(parentItem);
                    nextItem = parentItem.nextAll(nextSelector);
                }
                if (nextItem && !nextItem.length) {
                    nextItem = that.wrapper.children('.k-item').first();
                } else if (!nextItem) {
                    nextItem = [];
                }
                that._moveHover(item, nextItem);
                return nextItem;
            },
            _itemLeft: function (item, belongsToVertical) {
                var that = this, nextItem, overflowWrapper;
                if (!belongsToVertical) {
                    nextItem = item.prevAll(nextSelector);
                    if (!nextItem.length) {
                        nextItem = item.nextAll(lastSelector);
                    }
                } else {
                    nextItem = item.parent().closest('.k-item');
                    overflowWrapper = that._overflowWrapper();
                    if (!nextItem.length && overflowWrapper) {
                        nextItem = popupParentItem(item.parent(), overflowWrapper);
                    }
                    that.close(nextItem);
                    if (that._isRootItem(nextItem) && that.options.orientation == 'horizontal') {
                        nextItem = nextItem.prevAll(nextSelector);
                    }
                }
                if (!nextItem.length) {
                    nextItem = that.wrapper.children('.k-item').last();
                }
                that._moveHover(item, nextItem);
                return nextItem;
            },
            _itemDown: function (item, belongsToVertical, hasChildren) {
                var that = this, nextItem;
                if (!belongsToVertical) {
                    if (!hasChildren || item.hasClass(DISABLEDSTATE)) {
                        return;
                    } else {
                        that.open(item);
                        nextItem = that._childPopupElement(item).children().first();
                    }
                } else {
                    nextItem = item.nextAll(nextSelector);
                }
                if (!nextItem.length && item.length) {
                    nextItem = item.parent().children().first();
                } else if (!item.length) {
                    nextItem = that.wrapper.children('.k-item').first();
                }
                that._moveHover(item, nextItem);
                return nextItem;
            },
            _itemUp: function (item, belongsToVertical) {
                var that = this, nextItem;
                if (!belongsToVertical) {
                    return;
                } else {
                    nextItem = item.prevAll(nextSelector);
                }
                if (!nextItem.length && item.length) {
                    nextItem = item.parent().children().last();
                } else if (!item.length) {
                    nextItem = that.wrapper.children('.k-item').last();
                }
                that._moveHover(item, nextItem);
                return nextItem;
            },
            _scrollToItem: function (item) {
                var that = this;
                if (that.options.scrollable && item && item.length) {
                    var ul = item.parent();
                    var isHorizontal = ul.hasClass(MENU) ? that.options.orientation == 'horizontal' : false;
                    var scrollDir = isHorizontal ? 'scrollLeft' : 'scrollTop';
                    var getSize = isHorizontal ? kendo._outerWidth : kendo._outerHeight;
                    var currentScrollOffset = ul[scrollDir]();
                    var itemSize = getSize(item);
                    var itemOffset = item[0][isHorizontal ? 'offsetLeft' : 'offsetTop'];
                    var ulSize = getSize(ul);
                    var scrollButtons = ul.siblings(scrollButtonSelector);
                    var scrollButtonSize = scrollButtons.length ? getSize(scrollButtons.first()) : 0;
                    var itemPosition;
                    if (currentScrollOffset + ulSize < itemOffset + itemSize + scrollButtonSize) {
                        itemPosition = itemOffset + itemSize - ulSize + scrollButtonSize;
                    } else if (currentScrollOffset > itemOffset - scrollButtonSize) {
                        itemPosition = itemOffset - scrollButtonSize;
                    }
                    if (!isNaN(itemPosition)) {
                        var scrolling = {};
                        scrolling[scrollDir] = itemPosition;
                        ul.finish().animate(scrolling, 'fast', 'linear', function () {
                            that._toggleScrollButtons(ul, scrollButtons.first(), scrollButtons.last(), isHorizontal);
                        });
                    }
                }
            },
            _itemEsc: function (item, belongsToVertical) {
                var that = this, nextItem;
                if (!belongsToVertical) {
                    return item;
                } else {
                    nextItem = item.parent().closest('.k-item');
                    that.close(nextItem);
                    that._moveHover(item, nextItem);
                }
                return nextItem;
            },
            _childPopupElement: function (item) {
                var popupElement = item.find('.k-menu-group');
                var wrapper = this._overflowWrapper();
                if (!popupElement.length && wrapper) {
                    popupElement = itemPopup(item, wrapper);
                }
                return popupElement;
            },
            _triggerEvent: function (e) {
                var that = this;
                return that.trigger(e.type, {
                    type: e.type,
                    item: e.item
                });
            },
            _focusHandler: function (e) {
                var that = this, item = $(kendo.eventTarget(e)).closest(allItemsSelector);
                if (item.hasClass(DISABLEDSTATE)) {
                    return;
                }
                setTimeout(function () {
                    that._moveHover([], item);
                    if (item.children('.k-content')[0]) {
                        item.parent().closest('.k-item').removeClass(FOCUSEDSTATE);
                    }
                }, 200);
            },
            _animations: function (options) {
                if (options && 'animation' in options && !options.animation) {
                    options.animation = {
                        open: { effects: {} },
                        close: {
                            hide: true,
                            effects: {}
                        }
                    };
                }
            }
        });
        extend(Menu, {
            renderItem: function (options) {
                options = extend({
                    menu: {},
                    group: {}
                }, options);
                var empty = templates.empty, item = options.item;
                return templates.item(extend(options, {
                    image: item.imageUrl ? templates.image : empty,
                    sprite: item.spriteCssClass ? templates.sprite : empty,
                    itemWrapper: templates.itemWrapper,
                    renderContent: Menu.renderContent,
                    arrow: item.items || item.content ? templates.arrow : empty,
                    subGroup: Menu.renderGroup
                }, rendering));
            },
            renderGroup: function (options) {
                return templates.group(extend({
                    renderItems: function (options) {
                        var html = '', i = 0, items = options.items, len = items ? items.length : 0, group = extend({ length: len }, options.group);
                        for (; i < len; i++) {
                            html += Menu.renderItem(extend(options, {
                                group: group,
                                item: extend({ index: i }, items[i])
                            }));
                        }
                        return html;
                    }
                }, options, rendering));
            },
            renderContent: function (options) {
                return templates.content(extend(options, rendering));
            }
        });
        var ContextMenu = Menu.extend({
            init: function (element, options) {
                var that = this;
                Menu.fn.init.call(that, element, options);
                that._marker = kendo.guid().substring(0, 8);
                that.target = $(that.options.target);
                that._popup();
                that._wire();
            },
            _initOverflow: function (options) {
                var that = this;
                if (options.scrollable && !that._overflowWrapper()) {
                    that._openedPopups = {};
                    that._popupsWrapper = (that.element.parent().is(animationContainerSelector) ? that.element.parent() : that.element).wrap('<div class=\'k-popups-wrapper ' + options.orientation + '\'></div>').parent();
                    if (that.options.orientation == 'horizontal') {
                        removeSpacesBetweenItems(that.element);
                    }
                    if (options.appendTo) {
                        options.appendTo.append(that._popupsWrapper);
                    }
                    that._initialHeight = that.element[0].style.height;
                    that._initialWidth = that.element[0].style.width;
                }
            },
            options: {
                name: 'ContextMenu',
                filter: null,
                showOn: 'contextmenu',
                orientation: 'vertical',
                alignToAnchor: false,
                target: 'body'
            },
            events: [
                OPEN,
                CLOSE,
                ACTIVATE,
                DEACTIVATE,
                SELECT
            ],
            setOptions: function (options) {
                var that = this;
                Menu.fn.setOptions.call(that, options);
                that.target.off(that.showOn + NS + that._marker, that._showProxy);
                if (that.userEvents) {
                    that.userEvents.destroy();
                }
                that.target = $(that.options.target);
                if (options.orientation && that.popup.wrapper[0]) {
                    that.popup.element.unwrap();
                }
                that._wire();
                Menu.fn.setOptions.call(this, options);
            },
            destroy: function () {
                var that = this;
                that.target.off(that.options.showOn + NS + that._marker);
                DOCUMENT_ELEMENT.off(kendo.support.mousedown + NS + that._marker, that._closeProxy);
                if (that.userEvents) {
                    that.userEvents.destroy();
                }
                Menu.fn.destroy.call(that);
            },
            open: function (x, y) {
                var that = this;
                x = $(x)[0];
                if (contains(that.element[0], $(x)[0]) || that._itemHasChildren($(x))) {
                    Menu.fn.open.call(that, x);
                } else {
                    if (that._triggerEvent({
                            item: that.element,
                            type: OPEN
                        }) === false) {
                        if (that.popup.visible() && that.options.filter) {
                            that.popup.close(true);
                            that.popup.element.kendoStop(true);
                        }
                        if (y !== undefined) {
                            var overflowWrapper = that._overflowWrapper();
                            if (overflowWrapper) {
                                var offset = overflowWrapper.offset();
                                x -= offset.left;
                                y -= offset.top;
                            }
                            that.popup.wrapper.hide();
                            that._configurePopupScrolling(x, y);
                            that.popup.open(x, y);
                        } else {
                            that.popup.options.anchor = (x ? x : that.popup.anchor) || that.target;
                            that.popup.element.kendoStop(true);
                            that._configurePopupScrolling();
                            that.popup.open();
                        }
                        DOCUMENT_ELEMENT.off(that.popup.downEvent, that.popup._mousedownProxy);
                        DOCUMENT_ELEMENT.on(kendo.support.mousedown + NS + that._marker, that._closeProxy);
                    }
                }
                return that;
            },
            _configurePopupScrolling: function (x, y) {
                var that = this;
                var popup = that.popup;
                var isHorizontal = that.options.orientation == 'horizontal';
                if (that.options.scrollable) {
                    that._wrapPopupElement(popup);
                    popup.element.parent().css({
                        position: '',
                        height: ''
                    });
                    popup.element.css({
                        visibility: 'hidden',
                        display: '',
                        position: ''
                    });
                    if (isHorizontal) {
                        that._setPopupWidth(popup, isNaN(x) ? undefined : {
                            isFixed: true,
                            x: x,
                            y: y
                        });
                    } else {
                        that._setPopupHeight(popup, isNaN(x) ? undefined : {
                            isFixed: true,
                            x: x,
                            y: y
                        });
                    }
                    popup.element.css({
                        visibility: '',
                        display: 'none',
                        position: 'absolute'
                    });
                    that._initPopupScrollButtons(popup, isHorizontal, true);
                    popup.element.siblings(scrollButtonSelector).hide();
                }
            },
            _setPopupWidth: function (popup, isFixed) {
                var popupElement = popup.element;
                var popups = popupElement.add(popupElement.parent(animationContainerSelector));
                popups.width(this._initialWidth || '');
                var location = popup._location(isFixed);
                var windowWidth = $(window).width();
                var popupOuterWidth = location.width;
                var popupOffsetLeft = Math.max(location.left, 0);
                var scrollLeft = isFixed ? 0 : parentsScroll(this._overflowWrapper()[0], 'scrollLeft');
                var shadow = kendo.getShadows(popupElement);
                var maxWidth = windowWidth - shadow.left - shadow.right;
                var canFit = maxWidth + scrollLeft > popupOuterWidth + popupOffsetLeft;
                if (!canFit) {
                    popups.css({
                        overflow: 'hidden',
                        width: maxWidth - popupOffsetLeft + scrollLeft + 'px'
                    });
                }
            },
            close: function () {
                var that = this;
                if (contains(that.element[0], $(arguments[0])[0]) || that._itemHasChildren(arguments[0])) {
                    Menu.fn.close.call(that, arguments[0]);
                } else {
                    if (that.popup.visible()) {
                        if (that._triggerEvent({
                                item: that.element,
                                type: CLOSE
                            }) === false) {
                            that.popup.close();
                            DOCUMENT_ELEMENT.off(kendo.support.mousedown + NS, that._closeProxy);
                            that.unbind(SELECT, that._closeTimeoutProxy);
                        }
                    }
                }
            },
            _showHandler: function (e) {
                var ev = e, offset, that = this, options = that.options;
                if (e.event) {
                    ev = e.event;
                    ev.pageX = e.x.location;
                    ev.pageY = e.y.location;
                }
                if (contains(that.element[0], e.relatedTarget || e.target)) {
                    return;
                }
                that._eventOrigin = ev;
                ev.preventDefault();
                ev.stopImmediatePropagation();
                that.element.find('.' + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
                if (options.filter && kendo.support.matchesSelector.call(ev.currentTarget, options.filter) || !options.filter) {
                    if (options.alignToAnchor) {
                        that.popup.options.anchor = ev.currentTarget;
                        that.open(ev.currentTarget);
                    } else {
                        that.popup.options.anchor = ev.currentTarget;
                        if (that._targetChild) {
                            offset = that.target.offset();
                            that.open(ev.pageX - offset.left, ev.pageY - offset.top);
                        } else {
                            that.open(ev.pageX, ev.pageY);
                        }
                    }
                }
            },
            _closeHandler: function (e) {
                var that = this, target = $(e.relatedTarget || e.target), sameTarget = target.closest(that.target.selector)[0] == that.target[0], item = target.closest(itemSelector), children = that._itemHasChildren(item), overflowWrapper = that._overflowWrapper(), containment = contains(that.element[0], target[0]) || overflowWrapper && contains(overflowWrapper[0], target[0]);
                that._eventOrigin = e;
                var normalClick = e.which !== 3;
                if (that.popup.visible() && (normalClick && sameTarget || !sameTarget) && (that.options.closeOnClick && !children && containment || !containment)) {
                    if (containment) {
                        this.unbind(SELECT, this._closeTimeoutProxy);
                        that.bind(SELECT, that._closeTimeoutProxy);
                    } else {
                        that.close();
                    }
                }
            },
            _wire: function () {
                var that = this, options = that.options, target = that.target;
                that._showProxy = proxy(that._showHandler, that);
                that._closeProxy = proxy(that._closeHandler, that);
                that._closeTimeoutProxy = proxy(that.close, that);
                if (target[0]) {
                    if (kendo.support.mobileOS && options.showOn == 'contextmenu') {
                        that.userEvents = new kendo.UserEvents(target, {
                            filter: options.filter,
                            allowSelection: false
                        });
                        target.on(options.showOn + NS + that._marker, false);
                        that.userEvents.bind('hold', that._showProxy);
                    } else {
                        if (options.filter) {
                            target.on(options.showOn + NS + that._marker, options.filter, that._showProxy);
                        } else {
                            target.on(options.showOn + NS + that._marker, that._showProxy);
                        }
                    }
                }
            },
            _triggerEvent: function (e) {
                var that = this, anchor = $(that.popup.options.anchor)[0], origin = that._eventOrigin;
                that._eventOrigin = undefined;
                return that.trigger(e.type, extend({
                    type: e.type,
                    item: e.item || this.element[0],
                    target: anchor
                }, origin ? { event: origin } : {}));
            },
            _popup: function () {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                that._triggerProxy = proxy(that._triggerEvent, that);
                that.popup = that.element.addClass('k-context-menu').kendoPopup({
                    anchor: that.target || 'body',
                    copyAnchorStyles: that.options.copyAnchorStyles,
                    collision: that.options.popupCollision || 'fit',
                    animation: that.options.animation,
                    activate: that._triggerProxy,
                    deactivate: that._triggerProxy,
                    appendTo: overflowWrapper || that.options.appendTo,
                    close: !overflowWrapper ? $.noop : function (e) {
                        $(getChildPopups(e.sender.element, overflowWrapper)).each(function (i, p) {
                            var popup = p.data(KENDOPOPUP);
                            if (popup) {
                                popup.close(true);
                            }
                        });
                    }
                }).data(KENDOPOPUP);
                that._targetChild = contains(that.target[0], that.popup.element[0]);
            }
        });
        ui.plugin(Menu);
        ui.plugin(ContextMenu);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.columnmenu', [
        'kendo.popup',
        'kendo.filtermenu',
        'kendo.menu'
    ], f);
}(function () {
    var __meta__ = {
        id: 'columnmenu',
        name: 'Column Menu',
        category: 'framework',
        depends: [
            'popup',
            'filtermenu',
            'menu'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, proxy = $.proxy, extend = $.extend, grep = $.grep, map = $.map, inArray = $.inArray, ACTIVE = 'k-state-selected', ASC = 'asc', DESC = 'desc', CHANGE = 'change', INIT = 'init', OPEN = 'open', SELECT = 'select', POPUP = 'kendoPopup', FILTERMENU = 'kendoFilterMenu', MENU = 'kendoMenu', NS = '.kendoColumnMenu', Widget = ui.Widget;
        function trim(text) {
            return $.trim(text).replace(/&nbsp;/gi, '');
        }
        function toHash(arr, key) {
            var result = {};
            var idx, len, current;
            for (idx = 0, len = arr.length; idx < len; idx++) {
                current = arr[idx];
                result[current[key]] = current;
            }
            return result;
        }
        function leafColumns(columns) {
            var result = [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (!columns[idx].columns) {
                    result.push(columns[idx]);
                    continue;
                }
                result = result.concat(leafColumns(columns[idx].columns));
            }
            return result;
        }
        var ColumnMenu = Widget.extend({
            init: function (element, options) {
                var that = this, link;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                that.owner = options.owner;
                that.dataSource = options.dataSource;
                that.field = element.attr(kendo.attr('field'));
                that.title = element.attr(kendo.attr('title'));
                link = element.find('.k-header-column-menu');
                if (!link[0]) {
                    link = element.addClass('k-with-icon').prepend('<a class="k-header-column-menu" href="#" title="' + options.messages.settings + '" aria-label="' + options.messages.settings + '"><span class="k-icon k-i-more-vertical"></span></a>').find('.k-header-column-menu');
                }
                that.link = link.attr('tabindex', -1).on('click' + NS, proxy(that._click, that));
                that.wrapper = $('<div class="k-column-menu"/>');
                that._refreshHandler = proxy(that.refresh, that);
                that.dataSource.bind(CHANGE, that._refreshHandler);
            },
            _init: function () {
                var that = this;
                that.pane = that.options.pane;
                if (that.pane) {
                    that._isMobile = true;
                }
                if (that._isMobile) {
                    that._createMobileMenu();
                } else {
                    that._createMenu();
                }
                that.owner._muteAngularRebind(function () {
                    that._angularItems('compile');
                });
                that._sort();
                that._columns();
                that._filter();
                that._lockColumns();
                that.trigger(INIT, {
                    field: that.field,
                    container: that.wrapper
                });
            },
            events: [
                INIT,
                OPEN,
                'sort',
                'filtering'
            ],
            options: {
                name: 'ColumnMenu',
                messages: {
                    sortAscending: 'Sort Ascending',
                    sortDescending: 'Sort Descending',
                    filter: 'Filter',
                    columns: 'Columns',
                    done: 'Done',
                    settings: 'Column Settings',
                    lock: 'Lock',
                    unlock: 'Unlock'
                },
                filter: '',
                columns: true,
                sortable: true,
                filterable: true,
                animations: { left: 'slide' }
            },
            _createMenu: function () {
                var that = this, options = that.options;
                that.wrapper.html(kendo.template(template)({
                    uid: kendo.guid(),
                    ns: kendo.ns,
                    messages: options.messages,
                    sortable: options.sortable,
                    filterable: options.filterable,
                    columns: that._ownerColumns(),
                    showColumns: options.columns,
                    lockedColumns: options.lockedColumns
                }));
                that.popup = that.wrapper[POPUP]({
                    anchor: that.link,
                    open: proxy(that._open, that),
                    activate: proxy(that._activate, that),
                    close: function () {
                        if (that.options.closeCallback) {
                            that.options.closeCallback(that.element);
                        }
                    }
                }).data(POPUP);
                that.menu = that.wrapper.children()[MENU]({
                    orientation: 'vertical',
                    closeOnClick: false
                }).data(MENU);
            },
            _createMobileMenu: function () {
                var that = this, options = that.options;
                var html = kendo.template(mobileTemplate)({
                    ns: kendo.ns,
                    field: that.field,
                    title: that.title || that.field,
                    messages: options.messages,
                    sortable: options.sortable,
                    filterable: options.filterable,
                    columns: that._ownerColumns(),
                    showColumns: options.columns,
                    lockedColumns: options.lockedColumns
                });
                that.view = that.pane.append(html);
                that.wrapper = that.view.element.find('.k-column-menu');
                that.menu = new MobileMenu(that.wrapper.children(), { pane: that.pane });
                that.view.element.on('click', '.k-done', function (e) {
                    that.close();
                    e.preventDefault();
                });
                if (that.options.lockedColumns) {
                    that.view.bind('show', function () {
                        that._updateLockedColumns();
                    });
                }
            },
            _angularItems: function (action) {
                var that = this;
                that.angular(action, function () {
                    var items = that.wrapper.find('.k-columns-item input[' + kendo.attr('field') + ']').map(function () {
                        return $(this).closest('li');
                    });
                    var data = map(that._ownerColumns(), function (col) {
                        return { column: col._originalObject };
                    });
                    return {
                        elements: items,
                        data: data
                    };
                });
            },
            destroy: function () {
                var that = this;
                that._angularItems('cleanup');
                Widget.fn.destroy.call(that);
                if (that.filterMenu) {
                    that.filterMenu.destroy();
                }
                if (that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                }
                if (that.options.columns && that.owner) {
                    if (that._updateColumnsMenuHandler) {
                        that.owner.unbind('columnShow', that._updateColumnsMenuHandler);
                        that.owner.unbind('columnHide', that._updateColumnsMenuHandler);
                    }
                    if (that._updateColumnsLockedStateHandler) {
                        that.owner.unbind('columnLock', that._updateColumnsLockedStateHandler);
                        that.owner.unbind('columnUnlock', that._updateColumnsLockedStateHandler);
                    }
                }
                if (that.menu) {
                    that.menu.element.off(NS);
                    that.menu.destroy();
                }
                that.wrapper.off(NS);
                if (that.popup) {
                    that.popup.destroy();
                }
                if (that.view) {
                    that.view.purge();
                }
                that.link.off(NS);
                that.owner = null;
                that.wrapper = null;
                that.element = null;
            },
            close: function () {
                this.menu.close();
                if (this.popup) {
                    this.popup.close();
                    this.popup.element.off('keydown' + NS);
                }
            },
            _click: function (e) {
                e.preventDefault();
                e.stopPropagation();
                var options = this.options;
                if (options.filter && this.element.is(!options.filter)) {
                    return;
                }
                if (!this.popup && !this.pane) {
                    this._init();
                }
                if (this._isMobile) {
                    this.pane.navigate(this.view, this.options.animations.left);
                } else {
                    this.popup.toggle();
                }
            },
            _open: function () {
                var that = this;
                $('.k-column-menu').not(that.wrapper).each(function () {
                    $(this).data(POPUP).close();
                });
                that.popup.element.on('keydown' + NS, function (e) {
                    if (e.keyCode == kendo.keys.ESC) {
                        that.close();
                    }
                });
                if (that.options.lockedColumns) {
                    that._updateLockedColumns();
                }
            },
            _activate: function () {
                this.menu.element.focus();
                this.trigger(OPEN, {
                    field: this.field,
                    container: this.wrapper
                });
            },
            _ownerColumns: function () {
                var columns = leafColumns(this.owner.columns), menuColumns = grep(columns, function (col) {
                        var result = true, title = trim(col.title || '');
                        if (col.menu === false || !col.field && !title.length) {
                            result = false;
                        }
                        return result;
                    });
                return map(menuColumns, function (col) {
                    return {
                        originalField: col.field,
                        field: col.field || col.title,
                        title: col.title || col.field,
                        hidden: col.hidden,
                        index: inArray(col, columns),
                        locked: !!col.locked,
                        _originalObject: col
                    };
                });
            },
            _sort: function () {
                var that = this;
                if (that.options.sortable) {
                    that.refresh();
                    that.menu.bind(SELECT, function (e) {
                        var item = $(e.item), dir;
                        if (item.hasClass('k-sort-asc')) {
                            dir = ASC;
                        } else if (item.hasClass('k-sort-desc')) {
                            dir = DESC;
                        }
                        if (!dir) {
                            return;
                        }
                        item.parent().find('.k-sort-' + (dir == ASC ? DESC : ASC)).removeClass(ACTIVE);
                        that._sortDataSource(item, dir);
                        that.close();
                    });
                }
            },
            _sortDataSource: function (item, dir) {
                var that = this, sortable = that.options.sortable, compare = sortable.compare === null ? undefined : sortable.compare, dataSource = that.dataSource, idx, length, sort = dataSource.sort() || [];
                var removeClass = item.hasClass(ACTIVE) && sortable && sortable.allowUnsort !== false;
                dir = !removeClass ? dir : undefined;
                if (that.trigger('sort', {
                        sort: {
                            field: that.field,
                            dir: dir,
                            compare: compare
                        }
                    })) {
                    return;
                }
                if (removeClass) {
                    item.removeClass(ACTIVE);
                } else {
                    item.addClass(ACTIVE);
                }
                if (sortable.mode === 'multiple') {
                    for (idx = 0, length = sort.length; idx < length; idx++) {
                        if (sort[idx].field === that.field) {
                            sort.splice(idx, 1);
                            break;
                        }
                    }
                    sort.push({
                        field: that.field,
                        dir: dir,
                        compare: compare
                    });
                } else {
                    sort = [{
                            field: that.field,
                            dir: dir,
                            compare: compare
                        }];
                }
                dataSource.sort(sort);
            },
            _columns: function () {
                var that = this;
                if (that.options.columns) {
                    that._updateColumnsMenu();
                    that._updateColumnsMenuHandler = proxy(that._updateColumnsMenu, that);
                    that.owner.bind([
                        'columnHide',
                        'columnShow'
                    ], that._updateColumnsMenuHandler);
                    that._updateColumnsLockedStateHandler = proxy(that._updateColumnsLockedState, that);
                    that.owner.bind([
                        'columnUnlock',
                        'columnLock'
                    ], that._updateColumnsLockedStateHandler);
                    that.menu.bind(SELECT, function (e) {
                        var item = $(e.item), input, column, columns = leafColumns(that.owner.columns), field;
                        if (that._isMobile) {
                            e.preventDefault();
                        }
                        if (!item.parent().closest('li.k-columns-item')[0]) {
                            return;
                        }
                        input = item.find(':checkbox');
                        if (input.attr('disabled')) {
                            return;
                        }
                        field = input.attr(kendo.attr('field'));
                        column = grep(columns, function (column) {
                            return column.field == field || column.title == field;
                        })[0];
                        if (column.hidden === true) {
                            that.owner.showColumn(column);
                        } else {
                            that.owner.hideColumn(column);
                        }
                    });
                }
            },
            _updateColumnsMenu: function () {
                var idx, length, current, checked, locked;
                var fieldAttr = kendo.attr('field'), lockedAttr = kendo.attr('locked'), visible = grep(this._ownerColumns(), function (field) {
                        return !field.hidden;
                    }), visibleDataFields = grep(visible, function (field) {
                        return field.originalField;
                    }), lockedCount = grep(visibleDataFields, function (col) {
                        return col.locked === true;
                    }).length, nonLockedCount = grep(visibleDataFields, function (col) {
                        return col.locked !== true;
                    }).length;
                visible = map(visible, function (col) {
                    return col.field;
                });
                this.wrapper.find('[role=\'menuitemcheckbox\']').attr('aria-checked', false);
                var checkboxes = this.wrapper.find('.k-columns-item input[' + fieldAttr + ']').prop('disabled', false).prop('checked', false);
                for (idx = 0, length = checkboxes.length; idx < length; idx++) {
                    current = checkboxes.eq(idx);
                    locked = current.attr(lockedAttr) === 'true';
                    checked = false;
                    if (inArray(current.attr(fieldAttr), visible) > -1) {
                        checked = true;
                        current.prop('checked', checked);
                    }
                    current.closest('[role=\'menuitemcheckbox\']').attr('aria-checked', checked);
                    if (checked) {
                        if (lockedCount == 1 && locked) {
                            current.prop('disabled', true);
                        }
                        if (nonLockedCount == 1 && !locked) {
                            current.prop('disabled', true);
                        }
                    }
                }
            },
            _updateColumnsLockedState: function () {
                var idx, length, current, column;
                var fieldAttr = kendo.attr('field');
                var lockedAttr = kendo.attr('locked');
                var columns = toHash(this._ownerColumns(), 'field');
                var checkboxes = this.wrapper.find('.k-columns-item input[type=checkbox]');
                for (idx = 0, length = checkboxes.length; idx < length; idx++) {
                    current = checkboxes.eq(idx);
                    column = columns[current.attr(fieldAttr)];
                    if (column) {
                        current.attr(lockedAttr, column.locked);
                    }
                }
                this._updateColumnsMenu();
            },
            _filter: function () {
                var that = this, widget = FILTERMENU, options = that.options;
                if (options.filterable !== false) {
                    if (options.filterable.multi) {
                        widget = 'kendoFilterMultiCheck';
                        if (options.filterable.dataSource) {
                            options.filterable.checkSource = options.filterable.dataSource;
                            delete options.filterable.dataSource;
                        }
                    }
                    that.filterMenu = that.wrapper.find('.k-filterable')[widget](extend(true, {}, {
                        appendToElement: true,
                        dataSource: options.dataSource,
                        values: options.values,
                        field: that.field,
                        title: that.title,
                        change: function (e) {
                            if (that.trigger('filtering', {
                                    filter: e.filter,
                                    field: e.field
                                })) {
                                e.preventDefault();
                            }
                        }
                    }, options.filterable)).data(widget);
                    if (that._isMobile) {
                        that.menu.bind(SELECT, function (e) {
                            var item = $(e.item);
                            if (item.hasClass('k-filter-item')) {
                                that.pane.navigate(that.filterMenu.view, that.options.animations.left);
                            }
                        });
                    }
                }
            },
            _lockColumns: function () {
                var that = this;
                that.menu.bind(SELECT, function (e) {
                    var item = $(e.item);
                    if (item.hasClass('k-lock')) {
                        that.owner.lockColumn(that.field);
                        that.close();
                    } else if (item.hasClass('k-unlock')) {
                        that.owner.unlockColumn(that.field);
                        that.close();
                    }
                });
            },
            _updateLockedColumns: function () {
                var field = this.field;
                var columns = this.owner.columns;
                var column = grep(columns, function (column) {
                    return column.field == field || column.title == field;
                })[0];
                if (!column) {
                    return;
                }
                var locked = column.locked === true;
                var length = grep(columns, function (column) {
                    return !column.hidden && (column.locked && locked || !column.locked && !locked);
                }).length;
                var lockItem = this.wrapper.find('.k-lock').removeClass('k-state-disabled');
                var unlockItem = this.wrapper.find('.k-unlock').removeClass('k-state-disabled');
                if (locked || length == 1) {
                    lockItem.addClass('k-state-disabled');
                }
                if (!locked || length == 1) {
                    unlockItem.addClass('k-state-disabled');
                }
                this._updateColumnsLockedState();
            },
            refresh: function () {
                var that = this, sort = that.options.dataSource.sort() || [], descriptor, field = that.field, idx, length;
                that.wrapper.find('.k-sort-asc, .k-sort-desc').removeClass(ACTIVE);
                for (idx = 0, length = sort.length; idx < length; idx++) {
                    descriptor = sort[idx];
                    if (field == descriptor.field) {
                        that.wrapper.find('.k-sort-' + descriptor.dir).addClass(ACTIVE);
                    }
                }
                that.link[that._filterExist(that.dataSource.filter()) ? 'addClass' : 'removeClass']('k-state-active');
            },
            _filterExist: function (filters) {
                var found = false;
                var filter;
                if (!filters) {
                    return;
                }
                filters = filters.filters;
                for (var idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    if (filter.field == this.field) {
                        found = true;
                    } else if (filter.filters) {
                        found = found || this._filterExist(filter);
                    }
                }
                return found;
            }
        });
        var template = '<ul id="#=uid#">' + '#if(sortable){#' + '<li class="k-item k-sort-asc"><span class="k-link"><span class="k-icon k-i-sort-asc-sm"></span>${messages.sortAscending}</span></li>' + '<li class="k-item k-sort-desc"><span class="k-link"><span class="k-icon k-i-sort-desc-sm"></span>${messages.sortDescending}</span></li>' + '#if(showColumns || filterable){#' + '<li class="k-separator" role="presentation"></li>' + '#}#' + '#}#' + '#if(showColumns){#' + '<li class="k-item k-columns-item" aria-haspopup="true"><span class="k-link"><span class="k-icon k-i-columns"></span>${messages.columns}</span><ul>' + '#for (var idx = 0; idx < columns.length; idx++) {#' + '<li role="menuitemcheckbox" aria-checked="false"><input type="checkbox" data-#=ns#field="#=columns[idx].field.replace(/"/g,"&\\#34;")#" data-#=ns#index="#=columns[idx].index#" data-#=ns#locked="#=columns[idx].locked#"/>#=columns[idx].title#</li>' + '#}#' + '</ul></li>' + '#if(filterable || lockedColumns){#' + '<li class="k-separator" role="presentation"></li>' + '#}#' + '#}#' + '#if(filterable){#' + '<li class="k-item k-filter-item" aria-haspopup="true"><span class="k-link"><span class="k-icon k-i-filter"></span>${messages.filter}</span><ul>' + '<li><div class="k-filterable"></div></li>' + '</ul></li>' + '#if(lockedColumns){#' + '<li class="k-separator" role="presentation"></li>' + '#}#' + '#}#' + '#if(lockedColumns){#' + '<li class="k-item k-lock"><span class="k-link"><span class="k-icon k-i-lock"></span>${messages.lock}</span></li>' + '<li class="k-item k-unlock"><span class="k-link"><span class="k-icon k-i-unlock"></span>${messages.unlock}</span></li>' + '#}#' + '</ul>';
        var mobileTemplate = '<div data-#=ns#role="view" data-#=ns#init-widgets="false" data-#=ns#use-native-scrolling="true" class="k-grid-column-menu">' + '<div data-#=ns#role="header" class="k-header">' + '${messages.settings}' + '<button class="k-button k-done">#=messages.done#</button>' + '</div>' + '<div class="k-column-menu k-mobile-list"><ul><li>' + '<span class="k-link">${title}</span><ul>' + '#if(sortable){#' + '<li class="k-item k-sort-asc"><span class="k-link"><span class="k-icon k-i-sort-asc-sm"></span>${messages.sortAscending}</span></li>' + '<li class="k-item k-sort-desc"><span class="k-link"><span class="k-icon k-i-sort-desc-sm"></span>${messages.sortDescending}</span></li>' + '#}#' + '#if(lockedColumns){#' + '<li class="k-item k-lock"><span class="k-link"><span class="k-icon k-i-lock"></span>${messages.lock}</span></li>' + '<li class="k-item k-unlock"><span class="k-link"><span class="k-icon k-i-unlock"></span>${messages.unlock}</span></li>' + '#}#' + '#if(filterable){#' + '<li class="k-item k-filter-item">' + '<span class="k-link k-filterable">' + '<span class="k-icon k-i-filter"></span>' + '${messages.filter}</span>' + '</li>' + '#}#' + '</ul></li>' + '#if(showColumns){#' + '<li class="k-columns-item"><span class="k-link">${messages.columns}</span><ul>' + '#for (var idx = 0; idx < columns.length; idx++) {#' + '<li class="k-item"><label class="k-label"><input type="checkbox" class="k-check" data-#=ns#field="#=columns[idx].field.replace(/"/g,"&\\#34;")#" data-#=ns#index="#=columns[idx].index#" data-#=ns#locked="#=columns[idx].locked#"/>#=columns[idx].title#</label></li>' + '#}#' + '</ul></li>' + '#}#' + '</ul></div>' + '</div>';
        var MobileMenu = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.element.on('click' + NS, 'li.k-item:not(.k-separator):not(.k-state-disabled)', '_click');
            },
            events: [SELECT],
            _click: function (e) {
                if (!$(e.target).is('[type=checkbox]')) {
                    e.preventDefault();
                }
                this.trigger(SELECT, { item: e.currentTarget });
            },
            close: function () {
                this.options.pane.navigate('');
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.off(NS);
            }
        });
        ui.plugin(ColumnMenu);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.columnsorter', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'columnsorter',
        name: 'Column Sorter',
        category: 'framework',
        depends: ['core'],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var ui = kendo.ui;
        var Widget = ui.Widget;
        var DIR = 'dir';
        var ASC = 'asc';
        var SINGLE = 'single';
        var FIELD = 'field';
        var DESC = 'desc';
        var sorterNS = '.kendoColumnSorter';
        var TLINK = '.k-link';
        var ARIASORT = 'aria-sort';
        var proxy = $.proxy;
        var ColumnSorter = Widget.extend({
            init: function (element, options) {
                var that = this, link;
                Widget.fn.init.call(that, element, options);
                that._refreshHandler = proxy(that.refresh, that);
                that.dataSource = that.options.dataSource.bind('change', that._refreshHandler);
                that.directions = that.options.initialDirection === ASC ? [
                    ASC,
                    DESC
                ] : [
                    DESC,
                    ASC
                ];
                link = that.element.find(TLINK);
                if (!link[0]) {
                    link = that.element.wrapInner('<a class="k-link" href="#"/>').find(TLINK);
                }
                that.link = link;
                that.element.on('click' + sorterNS, proxy(that._click, that));
            },
            options: {
                name: 'ColumnSorter',
                mode: SINGLE,
                allowUnsort: true,
                compare: null,
                filter: '',
                initialDirection: ASC,
                showIndexes: false
            },
            events: ['change'],
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.element.off(sorterNS);
                that.dataSource.unbind('change', that._refreshHandler);
                that._refreshHandler = that.element = that.link = that.dataSource = null;
            },
            refresh: function () {
                var that = this, sort = that.dataSource.sort() || [], idx, length, descriptor, dir, element = that.element, field = element.attr(kendo.attr(FIELD)), sortOrder;
                element.removeAttr(kendo.attr(DIR));
                element.removeAttr(ARIASORT);
                for (idx = 0, length = sort.length; idx < length; idx++) {
                    descriptor = sort[idx];
                    if (field == descriptor.field) {
                        element.attr(kendo.attr(DIR), descriptor.dir);
                        sortOrder = idx + 1;
                    }
                }
                dir = element.attr(kendo.attr(DIR));
                element.find('.k-i-sort-asc-sm,.k-i-sort-desc-sm,.k-sort-order').remove();
                if (dir === ASC) {
                    $('<span class="k-icon k-i-sort-asc-sm" />').appendTo(that.link);
                    element.attr(ARIASORT, 'ascending');
                } else if (dir === DESC) {
                    $('<span class="k-icon k-i-sort-desc-sm" />').appendTo(that.link);
                    element.attr(ARIASORT, 'descending');
                }
                if (that.options.showIndexes && sort.length > 1 && sortOrder) {
                    $('<span class="k-sort-order" />').html(sortOrder).appendTo(that.link);
                }
            },
            _toggleSortDirection: function (dir) {
                var directions = this.directions;
                if (dir === directions[directions.length - 1] && this.options.allowUnsort) {
                    return undefined;
                }
                return directions[0] === dir ? directions[1] : directions[0];
            },
            _click: function (e) {
                var that = this, element = that.element, field = element.attr(kendo.attr(FIELD)), dir = element.attr(kendo.attr(DIR)), options = that.options, compare = that.options.compare === null ? undefined : that.options.compare, sort = that.dataSource.sort() || [], idx, length;
                e.preventDefault();
                if (options.filter && !element.is(options.filter)) {
                    return;
                }
                dir = this._toggleSortDirection(dir);
                if (this.trigger('change', {
                        sort: {
                            field: field,
                            dir: dir,
                            compare: compare
                        }
                    })) {
                    return;
                }
                if (options.mode === SINGLE) {
                    sort = [{
                            field: field,
                            dir: dir,
                            compare: compare
                        }];
                } else if (options.mode === 'multiple') {
                    for (idx = 0, length = sort.length; idx < length; idx++) {
                        if (sort[idx].field === field) {
                            sort.splice(idx, 1);
                            break;
                        }
                    }
                    sort.push({
                        field: field,
                        dir: dir,
                        compare: compare
                    });
                }
                this.dataSource.sort(sort);
            }
        });
        ui.plugin(ColumnSorter);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.editable', [
        'kendo.datepicker',
        'kendo.numerictextbox',
        'kendo.validator',
        'kendo.binder'
    ], f);
}(function () {
    var __meta__ = {
        id: 'editable',
        name: 'Editable',
        category: 'framework',
        depends: [
            'datepicker',
            'numerictextbox',
            'validator',
            'binder'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, extend = $.extend, oldIE = kendo.support.browser.msie && kendo.support.browser.version < 9, isFunction = kendo.isFunction, isPlainObject = $.isPlainObject, inArray = $.inArray, nameSpecialCharRegExp = /("|\%|'|\[|\]|\$|\.|\,|\:|\;|\+|\*|\&|\!|\#|\(|\)|<|>|\=|\?|\@|\^|\{|\}|\~|\/|\||`)/g, ERRORTEMPLATE = '<div class="k-widget k-tooltip k-tooltip-validation" style="margin:0.5em"><span class="k-icon k-i-warning"> </span>' + '#=message#<div class="k-callout k-callout-n"></div></div>', CHANGE = 'change';
        var specialRules = [
            'url',
            'email',
            'number',
            'date',
            'boolean'
        ];
        function fieldType(field) {
            field = field != null ? field : '';
            return field.type || $.type(field) || 'string';
        }
        function convertToValueBinding(container) {
            container.find(':input:not(:button, [' + kendo.attr('role') + '=upload], [' + kendo.attr('skip') + '], [type=file]), select').each(function () {
                var bindAttr = kendo.attr('bind'), binding = this.getAttribute(bindAttr) || '', bindingName = this.type === 'checkbox' || this.type === 'radio' ? 'checked:' : 'value:', fieldName = this.name;
                if (binding.indexOf(bindingName) === -1 && fieldName) {
                    binding += (binding.length ? ',' : '') + bindingName + fieldName;
                    $(this).attr(bindAttr, binding);
                }
            });
        }
        function createAttributes(options) {
            var field = (options.model.fields || options.model)[options.field], type = fieldType(field), validation = field ? field.validation : {}, ruleName, DATATYPE = kendo.attr('type'), BINDING = kendo.attr('bind'), rule, attr = {
                    name: options.field,
                    title: options.title
                };
            for (ruleName in validation) {
                rule = validation[ruleName];
                if (inArray(ruleName, specialRules) >= 0) {
                    attr[DATATYPE] = ruleName;
                } else if (!isFunction(rule)) {
                    attr[ruleName] = isPlainObject(rule) ? rule.value || ruleName : rule;
                }
                attr[kendo.attr(ruleName + '-msg')] = rule.message;
            }
            if (inArray(type, specialRules) >= 0) {
                attr[DATATYPE] = type;
            }
            attr[BINDING] = (type === 'boolean' ? 'checked:' : 'value:') + options.field;
            return attr;
        }
        function convertItems(items) {
            var idx, length, item, value, text, result;
            if (items && items.length) {
                result = [];
                for (idx = 0, length = items.length; idx < length; idx++) {
                    item = items[idx];
                    text = item.text || item.value || item;
                    value = item.value == null ? item.text || item : item.value;
                    result[idx] = {
                        text: text,
                        value: value
                    };
                }
            }
            return result;
        }
        var editors = {
            'number': function (container, options) {
                var attr = createAttributes(options);
                $('<input type="text"/>').attr(attr).appendTo(container).kendoNumericTextBox({ format: options.format });
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            },
            'date': function (container, options) {
                var attr = createAttributes(options), format = options.format;
                if (format) {
                    format = kendo._extractFormat(format);
                }
                attr[kendo.attr('format')] = format;
                $('<input type="text"/>').attr(attr).appendTo(container).kendoDatePicker({ format: options.format });
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            },
            'string': function (container, options) {
                var attr = createAttributes(options);
                $('<input type="text" class="k-input k-textbox"/>').attr(attr).appendTo(container);
            },
            'boolean': function (container, options) {
                var attr = createAttributes(options);
                $('<input type="checkbox" />').attr(attr).appendTo(container);
            },
            'values': function (container, options) {
                var attr = createAttributes(options);
                var items = kendo.stringify(convertItems(options.values));
                $('<select ' + kendo.attr('text-field') + '="text"' + kendo.attr('value-field') + '="value"' + kendo.attr('source') + '=\'' + (items ? items.replace(/\'/g, '&apos;') : items) + '\'' + kendo.attr('role') + '="dropdownlist"/>').attr(attr).appendTo(container);
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            }
        };
        function addValidationRules(modelField, rules) {
            var validation = modelField ? modelField.validation || {} : {}, rule, descriptor;
            for (rule in validation) {
                descriptor = validation[rule];
                if (isPlainObject(descriptor) && descriptor.value) {
                    descriptor = descriptor.value;
                }
                if (isFunction(descriptor)) {
                    rules[rule] = descriptor;
                }
            }
        }
        var Editable = Widget.extend({
            init: function (element, options) {
                var that = this;
                if (options.target) {
                    options.$angular = options.target.options.$angular;
                }
                Widget.fn.init.call(that, element, options);
                that._validateProxy = $.proxy(that._validate, that);
                that.refresh();
            },
            events: [CHANGE],
            options: {
                name: 'Editable',
                editors: editors,
                clearContainer: true,
                errorTemplate: ERRORTEMPLATE
            },
            editor: function (field, modelField) {
                var that = this, editors = that.options.editors, isObject = isPlainObject(field), fieldName = isObject ? field.field : field, model = that.options.model || {}, isValuesEditor = isObject && field.values, type = isValuesEditor ? 'values' : fieldType(modelField), isCustomEditor = isObject && field.editor, editor = isCustomEditor ? field.editor : editors[type], container = that.element.find('[' + kendo.attr('container-for') + '=' + fieldName.replace(nameSpecialCharRegExp, '\\$1') + ']');
                editor = editor ? editor : editors.string;
                if (isCustomEditor && typeof field.editor === 'string') {
                    editor = function (container) {
                        container.append(field.editor);
                    };
                }
                container = container.length ? container : that.element;
                editor(container, extend(true, {}, isObject ? field : { field: fieldName }, { model: model }));
            },
            _validate: function (e) {
                var that = this, input, value = e.value, preventChangeTrigger = that._validationEventInProgress, values = {}, bindAttribute = kendo.attr('bind'), fieldName = e.field.replace(nameSpecialCharRegExp, '\\$1'), bindingRegex = new RegExp('(value|checked)\\s*:\\s*' + fieldName + '\\s*(,|$)');
                values[e.field] = e.value;
                input = $(':input[' + bindAttribute + '*="' + fieldName + '"]', that.element).filter('[' + kendo.attr('validate') + '!=\'false\']').filter(function () {
                    return bindingRegex.test($(this).attr(bindAttribute));
                });
                if (input.length > 1) {
                    input = input.filter(function () {
                        var element = $(this);
                        return !element.is(':radio') || element.val() == value;
                    });
                }
                try {
                    that._validationEventInProgress = true;
                    if (!that.validatable.validateInput(input) || !preventChangeTrigger && that.trigger(CHANGE, { values: values })) {
                        e.preventDefault();
                    }
                } finally {
                    that._validationEventInProgress = false;
                }
            },
            end: function () {
                return this.validatable.validate();
            },
            destroy: function () {
                var that = this;
                that.angular('cleanup', function () {
                    return { elements: that.element };
                });
                Widget.fn.destroy.call(that);
                that.options.model.unbind('set', that._validateProxy);
                kendo.unbind(that.element);
                if (that.validatable) {
                    that.validatable.destroy();
                }
                kendo.destroy(that.element);
                that.element.removeData('kendoValidator');
                if (that.element.is('[' + kendo.attr('role') + '=editable]')) {
                    that.element.removeAttr(kendo.attr('role'));
                }
            },
            refresh: function () {
                var that = this, idx, length, fields = that.options.fields || [], container = that.options.clearContainer ? that.element.empty() : that.element, model = that.options.model || {}, rules = {}, field, isObject, fieldName, modelField, modelFields;
                if (!$.isArray(fields)) {
                    fields = [fields];
                }
                for (idx = 0, length = fields.length; idx < length; idx++) {
                    field = fields[idx];
                    isObject = isPlainObject(field);
                    fieldName = isObject ? field.field : field;
                    modelField = (model.fields || model)[fieldName];
                    addValidationRules(modelField, rules);
                    that.editor(field, modelField);
                }
                if (that.options.target) {
                    that.angular('compile', function () {
                        return {
                            elements: container,
                            data: container.map(function () {
                                return { dataItem: model };
                            })
                        };
                    });
                }
                if (!length) {
                    modelFields = model.fields || model;
                    for (fieldName in modelFields) {
                        addValidationRules(modelFields[fieldName], rules);
                    }
                }
                convertToValueBinding(container);
                if (that.validatable) {
                    that.validatable.destroy();
                }
                kendo.bind(container, that.options.model);
                that.options.model.unbind('set', that._validateProxy);
                that.options.model.bind('set', that._validateProxy);
                that.validatable = new kendo.ui.Validator(container, {
                    validateOnBlur: false,
                    errorTemplate: that.options.errorTemplate || undefined,
                    rules: rules
                });
                var focusable = container.find(':kendoFocusable').eq(0).focus();
                if (oldIE) {
                    focusable.focus();
                }
            }
        });
        ui.plugin(Editable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.window', [
        'kendo.draganddrop',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'window',
        name: 'Window',
        category: 'web',
        description: 'The Window widget displays content in a modal or non-modal HTML window.',
        depends: [
            'draganddrop',
            'popup'
        ],
        features: [{
                id: 'window-fx',
                name: 'Animation',
                description: 'Support for animation',
                depends: ['fx']
            }]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, TabKeyTrap = kendo.ui.Popup.TabKeyTrap, Draggable = kendo.ui.Draggable, isPlainObject = $.isPlainObject, activeElement = kendo._activeElement, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, proxy = $.proxy, extend = $.extend, each = $.each, template = kendo.template, BODY = 'body', templates, NS = '.kendoWindow', KWINDOW = '.k-window', KWINDOWTITLE = '.k-window-title', KWINDOWTITLEBAR = KWINDOWTITLE + 'bar', KWINDOWCONTENT = '.k-window-content', KWINDOWRESIZEHANDLES = '.k-resize-handle', KOVERLAY = '.k-overlay', KCONTENTFRAME = 'k-content-frame', LOADING = 'k-i-loading', KHOVERSTATE = 'k-state-hover', KFOCUSEDSTATE = 'k-state-focused', MAXIMIZEDSTATE = 'k-window-maximized', VISIBLE = ':visible', HIDDEN = 'hidden', CURSOR = 'cursor', OPEN = 'open', ACTIVATE = 'activate', DEACTIVATE = 'deactivate', CLOSE = 'close', REFRESH = 'refresh', MINIMIZE = 'minimize', MAXIMIZE = 'maximize', RESIZESTART = 'resizeStart', RESIZE = 'resize', RESIZEEND = 'resizeEnd', DRAGSTART = 'dragstart', DRAGEND = 'dragend', ERROR = 'error', OVERFLOW = 'overflow', ZINDEX = 'zIndex', MINIMIZE_MAXIMIZE = '.k-window-actions .k-i-window-minimize,.k-window-actions .k-i-window-maximize', KPIN = '.k-i-pin', KUNPIN = '.k-i-unpin', PIN_UNPIN = KPIN + ',' + KUNPIN, TITLEBAR_BUTTONS = '.k-window-titlebar .k-window-action', REFRESHICON = '.k-window-titlebar .k-i-refresh', isLocalUrl = kendo.isLocalUrl;
        function defined(x) {
            return typeof x != 'undefined';
        }
        function constrain(value, low, high) {
            return Math.max(Math.min(parseInt(value, 10), high === Infinity ? high : parseInt(high, 10)), parseInt(low, 10));
        }
        function executableScript() {
            return !this.type || this.type.toLowerCase().indexOf('script') >= 0;
        }
        var Window = Widget.extend({
            init: function (element, options) {
                var that = this, wrapper, offset = {}, visibility, display, position, isVisible = false, content, windowContent, suppressActions = options && options.actions && !options.actions.length, id;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                position = options.position;
                element = that.element;
                content = options.content;
                if (suppressActions) {
                    options.actions = [];
                }
                that.appendTo = $(options.appendTo);
                if (content && !isPlainObject(content)) {
                    content = options.content = { url: content };
                }
                element.find('script').filter(executableScript).remove();
                if (!element.parent().is(that.appendTo) && (position.top === undefined || position.left === undefined)) {
                    if (element.is(VISIBLE)) {
                        offset = element.offset();
                        isVisible = true;
                    } else {
                        visibility = element.css('visibility');
                        display = element.css('display');
                        element.css({
                            visibility: HIDDEN,
                            display: ''
                        });
                        offset = element.offset();
                        element.css({
                            visibility: visibility,
                            display: display
                        });
                    }
                    if (position.top === undefined) {
                        position.top = offset.top;
                    }
                    if (position.left === undefined) {
                        position.left = offset.left;
                    }
                }
                if (!defined(options.visible) || options.visible === null) {
                    options.visible = element.is(VISIBLE);
                }
                wrapper = that.wrapper = element.closest(KWINDOW);
                if (!element.is('.k-content') || !wrapper[0]) {
                    element.addClass('k-window-content k-content');
                    that._createWindow(element, options);
                    wrapper = that.wrapper = element.closest(KWINDOW);
                    that._dimensions();
                }
                that._position();
                if (options.pinned) {
                    that.pin(true);
                }
                if (content) {
                    that.refresh(content);
                }
                if (options.visible) {
                    that.toFront();
                }
                windowContent = wrapper.children(KWINDOWCONTENT);
                that._tabindex(windowContent);
                if (options.visible && options.modal) {
                    that._overlay(wrapper.is(VISIBLE)).css({ opacity: 0.5 });
                }
                wrapper.on('mouseenter' + NS, TITLEBAR_BUTTONS, proxy(that._buttonEnter, that)).on('mouseleave' + NS, TITLEBAR_BUTTONS, proxy(that._buttonLeave, that)).on('click' + NS, '> ' + TITLEBAR_BUTTONS, proxy(that._windowActionHandler, that));
                windowContent.on('keydown' + NS, proxy(that._keydown, that)).on('focus' + NS, proxy(that._focus, that)).on('blur' + NS, proxy(that._blur, that));
                this._resizable();
                this._draggable();
                id = element.attr('id');
                if (id) {
                    id = id + '_wnd_title';
                    wrapper.children(KWINDOWTITLEBAR).children(KWINDOWTITLE).attr('id', id);
                    windowContent.attr({
                        'role': 'dialog',
                        'aria-labelledby': id
                    });
                }
                wrapper.add(wrapper.children('.k-resize-handle,' + KWINDOWTITLEBAR)).on('mousedown' + NS, proxy(that.toFront, that));
                that.touchScroller = kendo.touchScroller(element);
                that._resizeHandler = proxy(that._onDocumentResize, that);
                that._marker = kendo.guid().substring(0, 8);
                $(window).on('resize' + NS + that._marker, that._resizeHandler);
                if (options.visible) {
                    that.trigger(OPEN);
                    that.trigger(ACTIVATE);
                }
                kendo.notify(that);
                if (this.options.modal) {
                    this._tabKeyTrap = new TabKeyTrap(wrapper);
                    this._tabKeyTrap.trap();
                    this._tabKeyTrap.shouldTrap = function () {
                        return windowContent.data('isFront');
                    };
                }
            },
            _buttonEnter: function (e) {
                $(e.currentTarget).addClass(KHOVERSTATE);
            },
            _buttonLeave: function (e) {
                $(e.currentTarget).removeClass(KHOVERSTATE);
            },
            _focus: function () {
                this.wrapper.addClass(KFOCUSEDSTATE);
            },
            _blur: function () {
                this.wrapper.removeClass(KFOCUSEDSTATE);
            },
            _dimensions: function () {
                var wrapper = this.wrapper;
                var options = this.options;
                var width = options.width;
                var height = options.height;
                var maxHeight = options.maxHeight;
                var dimensions = [
                    'minWidth',
                    'minHeight',
                    'maxWidth',
                    'maxHeight'
                ];
                this.title(options.title);
                for (var i = 0; i < dimensions.length; i++) {
                    var value = options[dimensions[i]] || '';
                    if (value != Infinity) {
                        wrapper.css(dimensions[i], value);
                    }
                }
                if (maxHeight != Infinity) {
                    this.element.css('maxHeight', maxHeight);
                }
                if (width) {
                    if (width.toString().indexOf('%') > 0) {
                        wrapper.width(width);
                    } else {
                        wrapper.width(constrain(width, options.minWidth, options.maxWidth));
                    }
                } else {
                    wrapper.width('');
                }
                if (height) {
                    if (height.toString().indexOf('%') > 0) {
                        wrapper.height(height);
                    } else {
                        wrapper.height(constrain(height, options.minHeight, options.maxHeight));
                    }
                } else {
                    wrapper.height('');
                }
                if (!options.visible) {
                    wrapper.hide();
                }
            },
            _position: function () {
                var wrapper = this.wrapper, position = this.options.position;
                if (position.top === 0) {
                    position.top = position.top.toString();
                }
                if (position.left === 0) {
                    position.left = position.left.toString();
                }
                wrapper.css({
                    top: position.top || '',
                    left: position.left || ''
                });
            },
            _animationOptions: function (id) {
                var animation = this.options.animation;
                var basicAnimation = {
                    open: { effects: {} },
                    close: {
                        hide: true,
                        effects: {}
                    }
                };
                return animation && animation[id] || basicAnimation[id];
            },
            _resize: function () {
                kendo.resize(this.element.children());
            },
            _resizable: function () {
                var resizable = this.options.resizable;
                var wrapper = this.wrapper;
                if (this.resizing) {
                    wrapper.off('dblclick' + NS).children(KWINDOWRESIZEHANDLES).remove();
                    this.resizing.destroy();
                    this.resizing = null;
                }
                if (resizable) {
                    wrapper.on('dblclick' + NS, KWINDOWTITLEBAR, proxy(function (e) {
                        if (!$(e.target).closest('.k-window-action').length) {
                            this.toggleMaximization();
                        }
                    }, this));
                    each('n e s w se sw ne nw'.split(' '), function (index, handler) {
                        wrapper.append(templates.resizeHandle(handler));
                    });
                    this.resizing = new WindowResizing(this);
                }
                wrapper = null;
            },
            _draggable: function () {
                var draggable = this.options.draggable;
                if (this.dragging) {
                    this.dragging.destroy();
                    this.dragging = null;
                }
                if (draggable) {
                    this.dragging = new WindowDragging(this, draggable.dragHandle || KWINDOWTITLEBAR);
                }
            },
            _actions: function () {
                var actions = this.options.actions;
                var titlebar = this.wrapper.children(KWINDOWTITLEBAR);
                var container = titlebar.find('.k-window-actions');
                var windowSpecificCommands = [
                    'maximize',
                    'minimize'
                ];
                actions = $.map(actions, function (action) {
                    return { name: windowSpecificCommands.indexOf(action.toLowerCase()) > -1 ? 'window-' + action : action };
                });
                container.html(kendo.render(templates.action, actions));
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                var scrollable = this.options.scrollable !== false;
                this.restore();
                this._dimensions();
                this._position();
                this._resizable();
                this._draggable();
                this._actions();
                if (typeof options.modal !== 'undefined') {
                    var visible = this.options.visible !== false;
                    this._overlay(options.modal && visible);
                }
                this.element.css(OVERFLOW, scrollable ? '' : 'hidden');
            },
            events: [
                OPEN,
                ACTIVATE,
                DEACTIVATE,
                CLOSE,
                MINIMIZE,
                MAXIMIZE,
                REFRESH,
                RESIZESTART,
                RESIZE,
                RESIZEEND,
                DRAGSTART,
                DRAGEND,
                ERROR
            ],
            options: {
                name: 'Window',
                animation: {
                    open: {
                        effects: {
                            zoom: { direction: 'in' },
                            fade: { direction: 'in' }
                        },
                        duration: 350
                    },
                    close: {
                        effects: {
                            zoom: {
                                direction: 'out',
                                properties: { scale: 0.7 }
                            },
                            fade: { direction: 'out' }
                        },
                        duration: 350,
                        hide: true
                    }
                },
                title: '',
                actions: ['Close'],
                autoFocus: true,
                modal: false,
                resizable: true,
                draggable: true,
                minWidth: 90,
                minHeight: 50,
                maxWidth: Infinity,
                maxHeight: Infinity,
                pinned: false,
                scrollable: true,
                position: {},
                content: null,
                visible: null,
                height: null,
                width: null,
                appendTo: 'body',
                isMaximized: false,
                isMinimized: false
            },
            _closable: function () {
                return $.inArray('close', $.map(this.options.actions, function (x) {
                    return x.toLowerCase();
                })) > -1;
            },
            _keydown: function (e) {
                var that = this, options = that.options, keys = kendo.keys, keyCode = e.keyCode, wrapper = that.wrapper, offset, handled, distance = 10, isMaximized = that.options.isMaximized, newWidth, newHeight, w, h;
                if (keyCode == keys.ESC && that._closable()) {
                    that._close(false);
                }
                if (e.target != e.currentTarget || that._closing) {
                    return;
                }
                if (options.draggable && !e.ctrlKey && !isMaximized) {
                    offset = kendo.getOffset(wrapper);
                    if (keyCode == keys.UP) {
                        handled = wrapper.css('top', offset.top - distance);
                    } else if (keyCode == keys.DOWN) {
                        handled = wrapper.css('top', offset.top + distance);
                    } else if (keyCode == keys.LEFT) {
                        handled = wrapper.css('left', offset.left - distance);
                    } else if (keyCode == keys.RIGHT) {
                        handled = wrapper.css('left', offset.left + distance);
                    }
                }
                if (options.resizable && e.ctrlKey && !isMaximized) {
                    if (keyCode == keys.UP) {
                        handled = true;
                        newHeight = wrapper.height() - distance;
                    } else if (keyCode == keys.DOWN) {
                        handled = true;
                        newHeight = wrapper.height() + distance;
                    }
                    if (keyCode == keys.LEFT) {
                        handled = true;
                        newWidth = wrapper.width() - distance;
                    } else if (keyCode == keys.RIGHT) {
                        handled = true;
                        newWidth = wrapper.width() + distance;
                    }
                    if (handled) {
                        w = constrain(newWidth, options.minWidth, options.maxWidth);
                        h = constrain(newHeight, options.minHeight, options.maxHeight);
                        if (!isNaN(w)) {
                            wrapper.width(w);
                            that.options.width = w + 'px';
                        }
                        if (!isNaN(h)) {
                            wrapper.height(h);
                            that.options.height = h + 'px';
                        }
                        that.resize();
                    }
                }
                if (handled) {
                    e.preventDefault();
                }
            },
            _overlay: function (visible) {
                var overlay = this.appendTo.children(KOVERLAY), wrapper = this.wrapper;
                if (!overlay.length) {
                    overlay = $('<div class=\'k-overlay\' />');
                }
                overlay.insertBefore(wrapper[0]).toggle(visible).css(ZINDEX, parseInt(wrapper.css(ZINDEX), 10) - 1);
                return overlay;
            },
            _actionForIcon: function (icon) {
                var iconClass = /\bk-i(-\w+)+\b/.exec(icon[0].className)[0];
                return {
                    'k-i-close': '_close',
                    'k-i-window-maximize': 'maximize',
                    'k-i-window-minimize': 'minimize',
                    'k-i-window-restore': 'restore',
                    'k-i-refresh': 'refresh',
                    'k-i-pin': 'pin',
                    'k-i-unpin': 'unpin'
                }[iconClass];
            },
            _windowActionHandler: function (e) {
                if (this._closing) {
                    return;
                }
                var icon = $(e.target).closest('.k-window-action').find('.k-icon');
                var action = this._actionForIcon(icon);
                if (action) {
                    e.preventDefault();
                    this[action]();
                    return false;
                }
            },
            _modals: function () {
                var that = this;
                var zStack = $(KWINDOW).filter(function () {
                    var dom = $(this);
                    var object = that._object(dom);
                    var options = object && object.options;
                    return options && options.modal && options.visible && options.appendTo === that.options.appendTo && dom.is(VISIBLE);
                }).sort(function (a, b) {
                    return +$(a).css('zIndex') - +$(b).css('zIndex');
                });
                that = null;
                return zStack;
            },
            _object: function (element) {
                var content = element.children(KWINDOWCONTENT);
                var widget = kendo.widgetInstance(content);
                if (widget) {
                    return widget;
                }
                return undefined;
            },
            center: function () {
                var that = this, position = that.options.position, wrapper = that.wrapper, documentWindow = $(window), scrollTop = 0, scrollLeft = 0, newTop, newLeft;
                if (that.options.isMaximized) {
                    return that;
                }
                if (!that.options.pinned) {
                    scrollTop = documentWindow.scrollTop();
                    scrollLeft = documentWindow.scrollLeft();
                }
                newLeft = scrollLeft + Math.max(0, (documentWindow.width() - wrapper.width()) / 2);
                newTop = scrollTop + Math.max(0, (documentWindow.height() - wrapper.height() - parseInt(wrapper.css('paddingTop'), 10)) / 2);
                wrapper.css({
                    left: newLeft,
                    top: newTop
                });
                position.top = newTop;
                position.left = newLeft;
                return that;
            },
            title: function (text) {
                var that = this, wrapper = that.wrapper, options = that.options, titleBar = wrapper.children(KWINDOWTITLEBAR), title = titleBar.children(KWINDOWTITLE), titleBarHeight;
                if (!arguments.length) {
                    return title.html();
                }
                if (text === false) {
                    wrapper.addClass('k-window-titleless');
                    titleBar.remove();
                } else {
                    if (!titleBar.length) {
                        wrapper.prepend(templates.titlebar(options));
                        that._actions();
                        titleBar = wrapper.children(KWINDOWTITLEBAR);
                    } else {
                        title.html(kendo.htmlEncode(text));
                    }
                    titleBarHeight = parseInt(outerHeight(titleBar), 10);
                    wrapper.css('padding-top', titleBarHeight);
                    titleBar.css('margin-top', -titleBarHeight);
                }
                that.options.title = text;
                return that;
            },
            content: function (html, data) {
                var content = this.wrapper.children(KWINDOWCONTENT), scrollContainer = content.children('.km-scroll-container');
                content = scrollContainer[0] ? scrollContainer : content;
                if (!defined(html)) {
                    return content.html();
                }
                this.angular('cleanup', function () {
                    return { elements: content.children() };
                });
                kendo.destroy(this.element.children());
                content.empty().html(html);
                this.angular('compile', function () {
                    var a = [];
                    for (var i = content.length; --i >= 0;) {
                        a.push({ dataItem: data });
                    }
                    return {
                        elements: content.children(),
                        data: a
                    };
                });
                return this;
            },
            open: function () {
                var that = this, wrapper = that.wrapper, options = that.options, showOptions = this._animationOptions('open'), contentElement = wrapper.children(KWINDOWCONTENT), overlay, otherModalsVisible, doc = $(document);
                if (!that.trigger(OPEN)) {
                    if (that._closing) {
                        wrapper.kendoStop(true, true);
                    }
                    that._closing = false;
                    that.toFront();
                    if (options.autoFocus) {
                        that.element.focus();
                    }
                    options.visible = true;
                    if (options.modal) {
                        otherModalsVisible = !!that._modals().length;
                        overlay = that._overlay(otherModalsVisible);
                        overlay.kendoStop(true, true);
                        if (showOptions.duration && kendo.effects.Fade && !otherModalsVisible) {
                            var overlayFx = kendo.fx(overlay).fadeIn();
                            overlayFx.duration(showOptions.duration || 0);
                            overlayFx.endValue(0.5);
                            overlayFx.play();
                        } else {
                            overlay.css('opacity', 0.5);
                        }
                        overlay.show();
                        $(window).on('focus', function () {
                            if (contentElement.data('isFront')) {
                                that.element.focus();
                            }
                        });
                    }
                    if (!wrapper.is(VISIBLE)) {
                        contentElement.css(OVERFLOW, HIDDEN);
                        wrapper.show().kendoStop().kendoAnimate({
                            effects: showOptions.effects,
                            duration: showOptions.duration,
                            complete: proxy(this._activate, this)
                        });
                    }
                }
                if (options.isMaximized) {
                    that._documentScrollTop = doc.scrollTop();
                    that._documentScrollLeft = doc.scrollLeft();
                    $('html, body').css(OVERFLOW, HIDDEN);
                }
                return that;
            },
            _activate: function () {
                var scrollable = this.options.scrollable !== false;
                if (this.options.autoFocus) {
                    this.element.focus();
                }
                this.element.css(OVERFLOW, scrollable ? '' : 'hidden');
                kendo.resize(this.element.children());
                this.trigger(ACTIVATE);
            },
            _removeOverlay: function (suppressAnimation) {
                var modals = this._modals();
                var options = this.options;
                var hideOverlay = options.modal && !modals.length;
                var overlay = options.modal ? this._overlay(true) : $(undefined);
                var hideOptions = this._animationOptions('close');
                if (hideOverlay) {
                    if (!suppressAnimation && hideOptions.duration && kendo.effects.Fade) {
                        var overlayFx = kendo.fx(overlay).fadeOut();
                        overlayFx.duration(hideOptions.duration || 0);
                        overlayFx.startValue(0.5);
                        overlayFx.play();
                    } else {
                        this._overlay(false).remove();
                    }
                } else if (modals.length) {
                    this._object(modals.last())._overlay(true);
                }
            },
            _close: function (systemTriggered) {
                var that = this, wrapper = that.wrapper, options = that.options, showOptions = this._animationOptions('open'), hideOptions = this._animationOptions('close'), doc = $(document);
                if (wrapper.is(VISIBLE) && !that.trigger(CLOSE, { userTriggered: !systemTriggered })) {
                    if (that._closing) {
                        return;
                    }
                    that._closing = true;
                    options.visible = false;
                    $(KWINDOW).each(function (i, element) {
                        var contentElement = $(element).children(KWINDOWCONTENT);
                        if (element != wrapper && contentElement.find('> .' + KCONTENTFRAME).length > 0) {
                            contentElement.children(KOVERLAY).remove();
                        }
                    });
                    this._removeOverlay();
                    wrapper.kendoStop().kendoAnimate({
                        effects: hideOptions.effects || showOptions.effects,
                        reverse: hideOptions.reverse === true,
                        duration: hideOptions.duration,
                        complete: proxy(this._deactivate, this)
                    });
                }
                if (that.options.isMaximized) {
                    $('html, body').css(OVERFLOW, '');
                    if (that._documentScrollTop && that._documentScrollTop > 0) {
                        doc.scrollTop(that._documentScrollTop);
                    }
                    if (that._documentScrollLeft && that._documentScrollLeft > 0) {
                        doc.scrollLeft(that._documentScrollLeft);
                    }
                }
            },
            _deactivate: function () {
                var that = this;
                that.wrapper.hide().css('opacity', '');
                that.trigger(DEACTIVATE);
                if (that.options.modal) {
                    var lastModal = that._object(that._modals().last());
                    if (lastModal) {
                        lastModal.toFront();
                    }
                }
            },
            close: function () {
                this._close(true);
                return this;
            },
            _actionable: function (element) {
                return $(element).is(TITLEBAR_BUTTONS + ',' + TITLEBAR_BUTTONS + ' .k-icon,:input,a');
            },
            _shouldFocus: function (target) {
                var active = activeElement(), element = this.element;
                return this.options.autoFocus && !$(active).is(element) && !this._actionable(target) && (!element.find(active).length || !element.find(target).length);
            },
            toFront: function (e) {
                var that = this, wrapper = that.wrapper, currentWindow = wrapper[0], zIndex = +wrapper.css(ZINDEX), originalZIndex = zIndex, target = e && e.target || null;
                $(KWINDOW).each(function (i, element) {
                    var windowObject = $(element), zIndexNew = windowObject.css(ZINDEX), contentElement = windowObject.children(KWINDOWCONTENT);
                    if (!isNaN(zIndexNew)) {
                        zIndex = Math.max(+zIndexNew, zIndex);
                    }
                    contentElement.data('isFront', element == currentWindow);
                    if (element != currentWindow && contentElement.find('> .' + KCONTENTFRAME).length > 0) {
                        contentElement.append(templates.overlay);
                    }
                });
                if (!wrapper[0].style.zIndex || originalZIndex < zIndex) {
                    wrapper.css(ZINDEX, zIndex + 2);
                }
                that.element.find('> .k-overlay').remove();
                if (that._shouldFocus(target)) {
                    that.element.focus();
                    var scrollTop = $(window).scrollTop(), windowTop = parseInt(wrapper.position().top, 10);
                    if (!that.options.pinned && windowTop > 0 && windowTop < scrollTop) {
                        if (scrollTop > 0) {
                            $(window).scrollTop(windowTop);
                        } else {
                            wrapper.css('top', scrollTop);
                        }
                    }
                }
                wrapper = null;
                return that;
            },
            toggleMaximization: function () {
                if (this._closing) {
                    return this;
                }
                return this[this.options.isMaximized ? 'restore' : 'maximize']();
            },
            restore: function () {
                var that = this;
                var options = that.options;
                var minHeight = options.minHeight;
                var restoreOptions = that.restoreOptions;
                var doc = $(document);
                if (!options.isMaximized && !options.isMinimized) {
                    return that;
                }
                if (minHeight && minHeight != Infinity) {
                    that.wrapper.css('min-height', minHeight);
                }
                that.wrapper.css({
                    position: options.pinned ? 'fixed' : 'absolute',
                    left: restoreOptions.left,
                    top: restoreOptions.top,
                    width: restoreOptions.width,
                    height: restoreOptions.height
                }).removeClass(MAXIMIZEDSTATE).find('.k-window-content,.k-resize-handle').show().end().find('.k-window-titlebar .k-i-window-restore').parent().remove().end().end().find(MINIMIZE_MAXIMIZE).parent().show().end().end().find(PIN_UNPIN).parent().show();
                that.options.width = restoreOptions.width;
                that.options.height = restoreOptions.height;
                $('html, body').css(OVERFLOW, '');
                if (this._documentScrollTop && this._documentScrollTop > 0) {
                    doc.scrollTop(this._documentScrollTop);
                }
                if (this._documentScrollLeft && this._documentScrollLeft > 0) {
                    doc.scrollLeft(this._documentScrollLeft);
                }
                options.isMaximized = options.isMinimized = false;
                that.resize();
                return that;
            },
            _sizingAction: function (actionId, callback) {
                var that = this, wrapper = that.wrapper, style = wrapper[0].style, options = that.options;
                if (options.isMaximized || options.isMinimized) {
                    return that;
                }
                that.restoreOptions = {
                    width: style.width,
                    height: style.height
                };
                wrapper.children(KWINDOWRESIZEHANDLES).hide().end().children(KWINDOWTITLEBAR).find(MINIMIZE_MAXIMIZE).parent().hide().eq(0).before(templates.action({ name: 'window-restore' }));
                callback.call(that);
                that.wrapper.children(KWINDOWTITLEBAR).find(PIN_UNPIN).parent().toggle(actionId !== 'maximize');
                that.trigger(actionId);
                return that;
            },
            maximize: function () {
                this._sizingAction('maximize', function () {
                    var that = this, wrapper = that.wrapper, position = wrapper.position(), doc = $(document);
                    extend(that.restoreOptions, {
                        left: position.left,
                        top: position.top
                    });
                    wrapper.css({
                        left: 0,
                        top: 0,
                        position: 'fixed'
                    }).addClass(MAXIMIZEDSTATE);
                    this._documentScrollTop = doc.scrollTop();
                    this._documentScrollLeft = doc.scrollLeft();
                    $('html, body').css(OVERFLOW, HIDDEN);
                    that.options.isMaximized = true;
                    that._onDocumentResize();
                });
                return this;
            },
            isMaximized: function () {
                return this.options.isMaximized;
            },
            minimize: function () {
                this._sizingAction('minimize', function () {
                    var that = this;
                    that.wrapper.css({
                        height: '',
                        minHeight: ''
                    });
                    that.element.hide();
                    that.options.isMinimized = true;
                });
                return this;
            },
            isMinimized: function () {
                return this.options.isMinimized;
            },
            pin: function (force) {
                var that = this, win = $(window), wrapper = that.wrapper, top = parseInt(wrapper.css('top'), 10), left = parseInt(wrapper.css('left'), 10);
                if (force || !that.options.pinned && !that.options.isMaximized) {
                    wrapper.css({
                        position: 'fixed',
                        top: top - win.scrollTop(),
                        left: left - win.scrollLeft()
                    });
                    wrapper.children(KWINDOWTITLEBAR).find(KPIN).addClass('k-i-unpin').removeClass('k-i-pin');
                    that.options.pinned = true;
                }
            },
            unpin: function () {
                var that = this, win = $(window), wrapper = that.wrapper, top = parseInt(wrapper.css('top'), 10), left = parseInt(wrapper.css('left'), 10);
                if (that.options.pinned && !that.options.isMaximized) {
                    wrapper.css({
                        position: '',
                        top: top + win.scrollTop(),
                        left: left + win.scrollLeft()
                    });
                    wrapper.children(KWINDOWTITLEBAR).find(KUNPIN).addClass('k-i-pin').removeClass('k-i-unpin');
                    that.options.pinned = false;
                }
            },
            _onDocumentResize: function () {
                var that = this, wrapper = that.wrapper, wnd = $(window), zoomLevel = kendo.support.zoomLevel(), w, h;
                if (!that.options.isMaximized) {
                    return;
                }
                w = wnd.width() / zoomLevel;
                h = wnd.height() / zoomLevel - parseInt(wrapper.css('padding-top'), 10);
                wrapper.css({
                    width: w,
                    height: h
                });
                that.options.width = w;
                that.options.height = h;
                that.resize();
            },
            refresh: function (options) {
                var that = this, initOptions = that.options, element = $(that.element), iframe, showIframe, url;
                if (!isPlainObject(options)) {
                    options = { url: options };
                }
                options = extend({}, initOptions.content, options);
                showIframe = defined(initOptions.iframe) ? initOptions.iframe : options.iframe;
                url = options.url;
                if (url) {
                    if (!defined(showIframe)) {
                        showIframe = !isLocalUrl(url);
                    }
                    if (!showIframe) {
                        that._ajaxRequest(options);
                    } else {
                        iframe = element.find('.' + KCONTENTFRAME)[0];
                        if (iframe) {
                            iframe.src = url || iframe.src;
                        } else {
                            element.html(templates.contentFrame(extend({}, initOptions, { content: options })));
                        }
                        element.find('.' + KCONTENTFRAME).unbind('load' + NS).on('load' + NS, proxy(this._triggerRefresh, this));
                    }
                } else {
                    if (options.template) {
                        that.content(template(options.template)({}));
                    }
                    that.trigger(REFRESH);
                }
                element.toggleClass('k-window-iframecontent', !!showIframe);
                return that;
            },
            _triggerRefresh: function () {
                this.trigger(REFRESH);
            },
            _ajaxComplete: function () {
                clearTimeout(this._loadingIconTimeout);
                this.wrapper.find(REFRESHICON).removeClass(LOADING);
            },
            _ajaxError: function (xhr, status) {
                this.trigger(ERROR, {
                    status: status,
                    xhr: xhr
                });
            },
            _ajaxSuccess: function (contentTemplate) {
                return function (data) {
                    var html = data;
                    if (contentTemplate) {
                        html = template(contentTemplate)(data || {});
                    }
                    this.content(html, data);
                    this.element.prop('scrollTop', 0);
                    this.trigger(REFRESH);
                };
            },
            _showLoading: function () {
                this.wrapper.find(REFRESHICON).addClass(LOADING);
            },
            _ajaxRequest: function (options) {
                this._loadingIconTimeout = setTimeout(proxy(this._showLoading, this), 100);
                $.ajax(extend({
                    type: 'GET',
                    dataType: 'html',
                    cache: false,
                    error: proxy(this._ajaxError, this),
                    complete: proxy(this._ajaxComplete, this),
                    success: proxy(this._ajaxSuccess(options.template), this)
                }, options));
            },
            _destroy: function () {
                if (this.resizing) {
                    this.resizing.destroy();
                }
                if (this.dragging) {
                    this.dragging.destroy();
                }
                this.wrapper.off(NS).children(KWINDOWCONTENT).off(NS).end().find('.k-resize-handle,.k-window-titlebar').off(NS);
                $(window).off('resize' + NS + this._marker);
                clearTimeout(this._loadingIconTimeout);
                Widget.fn.destroy.call(this);
                this.unbind(undefined);
                kendo.destroy(this.wrapper);
                this._removeOverlay(true);
            },
            destroy: function () {
                this._destroy();
                this.wrapper.empty().remove();
                this.wrapper = this.appendTo = this.element = $();
            },
            _createWindow: function () {
                var contentHtml = this.element, options = this.options, iframeSrcAttributes, wrapper, isRtl = kendo.support.isRtl(contentHtml);
                if (options.scrollable === false) {
                    contentHtml.css('overflow', 'hidden');
                }
                wrapper = $(templates.wrapper(options));
                iframeSrcAttributes = contentHtml.find('iframe:not(.k-content)').map(function () {
                    var src = this.getAttribute('src');
                    this.src = '';
                    return src;
                });
                wrapper.toggleClass('k-rtl', isRtl).appendTo(this.appendTo).append(contentHtml).find('iframe:not(.k-content)').each(function (index) {
                    this.src = iframeSrcAttributes[index];
                });
                wrapper.find('.k-window-title').css(isRtl ? 'left' : 'right', outerWidth(wrapper.find('.k-window-actions')) + 10);
                contentHtml.css('visibility', '').show();
                contentHtml.find('[data-role=editor]').each(function () {
                    var editor = $(this).data('kendoEditor');
                    if (editor) {
                        editor.refresh();
                    }
                });
                wrapper = contentHtml = null;
            }
        });
        templates = {
            wrapper: template('<div class=\'k-widget k-window\' />'),
            action: template('<a role=\'button\' href=\'\\#\' class=\'k-button k-bare k-button-icon k-window-action\' aria-label=\'#= name #\'>' + '<span class=\'k-icon k-i-#= name.toLowerCase() #\'></span>' + '</a>'),
            titlebar: template('<div class=\'k-window-titlebar k-header\'>&nbsp;' + '<span class=\'k-window-title\'>#: title #</span>' + '<div class=\'k-window-actions\' />' + '</div>'),
            overlay: '<div class=\'k-overlay\' />',
            contentFrame: template('<iframe frameborder=\'0\' title=\'#= title #\' class=\'' + KCONTENTFRAME + '\' ' + 'src=\'#= content.url #\'>' + 'This page requires frames in order to show content' + '</iframe>'),
            resizeHandle: template('<div class=\'k-resize-handle k-resize-#= data #\'></div>')
        };
        function WindowResizing(wnd) {
            var that = this;
            that.owner = wnd;
            that._preventDragging = false;
            that._draggable = new Draggable(wnd.wrapper, {
                filter: '>' + KWINDOWRESIZEHANDLES,
                group: wnd.wrapper.id + '-resizing',
                dragstart: proxy(that.dragstart, that),
                drag: proxy(that.drag, that),
                dragend: proxy(that.dragend, that)
            });
            that._draggable.userEvents.bind('press', proxy(that.addOverlay, that));
            that._draggable.userEvents.bind('release', proxy(that.removeOverlay, that));
        }
        WindowResizing.prototype = {
            addOverlay: function () {
                this.owner.wrapper.append(templates.overlay);
            },
            removeOverlay: function () {
                this.owner.wrapper.find(KOVERLAY).remove();
            },
            dragstart: function (e) {
                var that = this;
                var wnd = that.owner;
                var wrapper = wnd.wrapper;
                that._preventDragging = wnd.trigger(RESIZESTART);
                if (that._preventDragging) {
                    return;
                }
                that.elementPadding = parseInt(wrapper.css('padding-top'), 10);
                that.initialPosition = kendo.getOffset(wrapper, 'position');
                that.resizeDirection = e.currentTarget.prop('className').replace('k-resize-handle k-resize-', '');
                that.initialSize = {
                    width: wrapper.width(),
                    height: wrapper.height()
                };
                that.containerOffset = kendo.getOffset(wnd.appendTo, 'position');
                wrapper.children(KWINDOWRESIZEHANDLES).not(e.currentTarget).hide();
                $(BODY).css(CURSOR, e.currentTarget.css(CURSOR));
            },
            drag: function (e) {
                if (this._preventDragging) {
                    return;
                }
                var that = this, wnd = that.owner, wrapper = wnd.wrapper, options = wnd.options, direction = that.resizeDirection, containerOffset = that.containerOffset, initialPosition = that.initialPosition, initialSize = that.initialSize, newWidth, newHeight, windowBottom, windowRight, x = Math.max(e.x.location, 0), y = Math.max(e.y.location, 0);
                if (direction.indexOf('e') >= 0) {
                    newWidth = x - initialPosition.left - containerOffset.left;
                    wrapper.width(constrain(newWidth, options.minWidth, options.maxWidth));
                } else if (direction.indexOf('w') >= 0) {
                    windowRight = initialPosition.left + initialSize.width + containerOffset.left;
                    newWidth = constrain(windowRight - x, options.minWidth, options.maxWidth);
                    wrapper.css({
                        left: windowRight - newWidth - containerOffset.left,
                        width: newWidth
                    });
                }
                var newWindowTop = y;
                if (wnd.options.pinned) {
                    newWindowTop -= $(window).scrollTop();
                }
                if (direction.indexOf('s') >= 0) {
                    newHeight = newWindowTop - initialPosition.top - that.elementPadding - containerOffset.top;
                    wrapper.height(constrain(newHeight, options.minHeight, options.maxHeight));
                } else if (direction.indexOf('n') >= 0) {
                    windowBottom = initialPosition.top + initialSize.height + containerOffset.top;
                    newHeight = constrain(windowBottom - newWindowTop, options.minHeight, options.maxHeight);
                    wrapper.css({
                        top: windowBottom - newHeight - containerOffset.top,
                        height: newHeight
                    });
                }
                if (newWidth) {
                    wnd.options.width = newWidth + 'px';
                }
                if (newHeight) {
                    wnd.options.height = newHeight + 'px';
                }
                wnd.resize();
            },
            dragend: function (e) {
                if (this._preventDragging) {
                    return;
                }
                var that = this, wnd = that.owner, wrapper = wnd.wrapper;
                wrapper.children(KWINDOWRESIZEHANDLES).not(e.currentTarget).show();
                $(BODY).css(CURSOR, '');
                if (wnd.touchScroller) {
                    wnd.touchScroller.reset();
                }
                if (e.keyCode == 27) {
                    wrapper.css(that.initialPosition).css(that.initialSize);
                }
                wnd.trigger(RESIZEEND);
                return false;
            },
            destroy: function () {
                if (this._draggable) {
                    this._draggable.destroy();
                }
                this._draggable = this.owner = null;
            }
        };
        function WindowDragging(wnd, dragHandle) {
            var that = this;
            that.owner = wnd;
            that._preventDragging = false;
            that._draggable = new Draggable(wnd.wrapper, {
                filter: dragHandle,
                group: wnd.wrapper.id + '-moving',
                dragstart: proxy(that.dragstart, that),
                drag: proxy(that.drag, that),
                dragend: proxy(that.dragend, that),
                dragcancel: proxy(that.dragcancel, that)
            });
            that._draggable.userEvents.stopPropagation = false;
        }
        WindowDragging.prototype = {
            dragstart: function (e) {
                var wnd = this.owner, element = wnd.element, actions = element.find('.k-window-actions'), containerOffset = kendo.getOffset(wnd.appendTo);
                this._preventDragging = wnd.trigger(DRAGSTART);
                if (this._preventDragging) {
                    return;
                }
                wnd.initialWindowPosition = kendo.getOffset(wnd.wrapper, 'position');
                wnd.initialPointerPosition = {
                    left: e.x.client,
                    top: e.y.client
                };
                wnd.startPosition = {
                    left: e.x.client - wnd.initialWindowPosition.left,
                    top: e.y.client - wnd.initialWindowPosition.top
                };
                if (actions.length > 0) {
                    wnd.minLeftPosition = outerWidth(actions) + parseInt(actions.css('right'), 10) - outerWidth(element);
                } else {
                    wnd.minLeftPosition = 20 - outerWidth(element);
                }
                wnd.minLeftPosition -= containerOffset.left;
                wnd.minTopPosition = -containerOffset.top;
                wnd.wrapper.append(templates.overlay).children(KWINDOWRESIZEHANDLES).hide();
                $(BODY).css(CURSOR, e.currentTarget.css(CURSOR));
            },
            drag: function (e) {
                if (this._preventDragging) {
                    return;
                }
                var wnd = this.owner;
                var position = wnd.options.position;
                position.top = Math.max(e.y.client - wnd.startPosition.top, wnd.minTopPosition);
                position.left = Math.max(e.x.client - wnd.startPosition.left, wnd.minLeftPosition);
                if (kendo.support.transforms) {
                    $(wnd.wrapper).css('transform', 'translate(' + (e.x.client - wnd.initialPointerPosition.left) + 'px, ' + (e.y.client - wnd.initialPointerPosition.top) + 'px)');
                } else {
                    $(wnd.wrapper).css(position);
                }
            },
            _finishDrag: function () {
                var wnd = this.owner;
                wnd.wrapper.children(KWINDOWRESIZEHANDLES).toggle(!wnd.options.isMinimized).end().find(KOVERLAY).remove();
                $(BODY).css(CURSOR, '');
            },
            dragcancel: function (e) {
                if (this._preventDragging) {
                    return;
                }
                this._finishDrag();
                e.currentTarget.closest(KWINDOW).css(this.owner.initialWindowPosition);
            },
            dragend: function () {
                if (this._preventDragging) {
                    return;
                }
                $(this.owner.wrapper).css(this.owner.options.position).css('transform', '');
                this._finishDrag();
                this.owner.trigger(DRAGEND);
                return false;
            },
            destroy: function () {
                if (this._draggable) {
                    this._draggable.destroy();
                }
                this._draggable = this.owner = null;
            }
        };
        kendo.ui.plugin(Window);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.view', [
        'kendo.core',
        'kendo.fx',
        'kendo.mobile.scroller',
        'kendo.view'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.view',
        name: 'View',
        category: 'mobile',
        description: 'Mobile View',
        depends: [
            'core',
            'fx',
            'mobile.scroller',
            'view'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, attr = kendo.attr, Widget = ui.Widget, ViewClone = kendo.ViewClone, INIT = 'init', UI_OVERLAY = '<div style="height: 100%; width: 100%; position: absolute; top: 0; left: 0; z-index: 20000; display: none" />', BEFORE_SHOW = 'beforeShow', SHOW = 'show', AFTER_SHOW = 'afterShow', BEFORE_HIDE = 'beforeHide', TRANSITION_END = 'transitionEnd', TRANSITION_START = 'transitionStart', HIDE = 'hide', DESTROY = 'destroy', attrValue = kendo.attrValue, roleSelector = kendo.roleSelector, directiveSelector = kendo.directiveSelector, compileMobileDirective = kendo.compileMobileDirective;
        function initPopOvers(element) {
            var popovers = element.find(roleSelector('popover')), idx, length, roles = ui.roles;
            for (idx = 0, length = popovers.length; idx < length; idx++) {
                kendo.initWidget(popovers[idx], {}, roles);
            }
        }
        function preventScrollIfNotInput(e) {
            if (!kendo.triggeredByInput(e)) {
                e.preventDefault();
            }
        }
        var View = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.params = {};
                $.extend(this, options);
                this.transition = this.transition || this.defaultTransition;
                this._id();
                if (!this.options.$angular) {
                    this._layout();
                    this._overlay();
                    this._scroller();
                    this._model();
                } else {
                    this._overlay();
                }
            },
            events: [
                INIT,
                BEFORE_SHOW,
                SHOW,
                AFTER_SHOW,
                BEFORE_HIDE,
                HIDE,
                DESTROY,
                TRANSITION_START,
                TRANSITION_END
            ],
            options: {
                name: 'View',
                title: '',
                layout: null,
                getLayout: $.noop,
                reload: false,
                transition: '',
                defaultTransition: '',
                useNativeScrolling: false,
                stretch: false,
                zoom: false,
                model: null,
                modelScope: window,
                scroller: {},
                initWidgets: true
            },
            enable: function (enable) {
                if (typeof enable == 'undefined') {
                    enable = true;
                }
                if (enable) {
                    this.overlay.hide();
                } else {
                    this.overlay.show();
                }
            },
            destroy: function () {
                if (this.layout) {
                    this.layout.detach(this);
                }
                this.trigger(DESTROY);
                Widget.fn.destroy.call(this);
                if (this.scroller) {
                    this.scroller.destroy();
                }
                if (this.options.$angular) {
                    this.element.scope().$destroy();
                }
                kendo.destroy(this.element);
            },
            purge: function () {
                this.destroy();
                this.element.remove();
            },
            triggerBeforeShow: function () {
                if (this.trigger(BEFORE_SHOW, { view: this })) {
                    return false;
                }
                return true;
            },
            triggerBeforeHide: function () {
                if (this.trigger(BEFORE_HIDE, { view: this })) {
                    return false;
                }
                return true;
            },
            showStart: function () {
                var element = this.element;
                element.css('display', '');
                if (!this.inited) {
                    this.inited = true;
                    this.trigger(INIT, { view: this });
                } else {
                    this._invokeNgController();
                }
                if (this.layout) {
                    this.layout.attach(this);
                }
                this._padIfNativeScrolling();
                this.trigger(SHOW, { view: this });
                kendo.resize(element);
            },
            showEnd: function () {
                this.trigger(AFTER_SHOW, { view: this });
                this._padIfNativeScrolling();
            },
            hideEnd: function () {
                var that = this;
                that.element.hide();
                that.trigger(HIDE, { view: that });
                if (that.layout) {
                    that.layout.trigger(HIDE, {
                        view: that,
                        layout: that.layout
                    });
                }
            },
            beforeTransition: function (type) {
                this.trigger(TRANSITION_START, { type: type });
            },
            afterTransition: function (type) {
                this.trigger(TRANSITION_END, { type: type });
            },
            _padIfNativeScrolling: function () {
                if (mobile.appLevelNativeScrolling()) {
                    var isAndroid = kendo.support.mobileOS && kendo.support.mobileOS.android, skin = mobile.application.skin() || '', isAndroidForced = mobile.application.os.android || skin.indexOf('android') > -1, hasPlatformIndependentSkin = skin === 'flat' || skin.indexOf('material') > -1, topContainer = (isAndroid || isAndroidForced) && !hasPlatformIndependentSkin ? 'footer' : 'header', bottomContainer = (isAndroid || isAndroidForced) && !hasPlatformIndependentSkin ? 'header' : 'footer';
                    this.content.css({
                        paddingTop: this[topContainer].height(),
                        paddingBottom: this[bottomContainer].height()
                    });
                }
            },
            contentElement: function () {
                var that = this;
                return that.options.stretch ? that.content : that.scrollerContent;
            },
            clone: function () {
                return new ViewClone(this);
            },
            _scroller: function () {
                var that = this;
                if (mobile.appLevelNativeScrolling()) {
                    return;
                }
                if (that.options.stretch) {
                    that.content.addClass('km-stretched-view');
                } else {
                    that.content.kendoMobileScroller($.extend(that.options.scroller, {
                        zoom: that.options.zoom,
                        useNative: that.options.useNativeScrolling
                    }));
                    that.scroller = that.content.data('kendoMobileScroller');
                    that.scrollerContent = that.scroller.scrollElement;
                }
                if (kendo.support.kineticScrollNeeded) {
                    $(that.element).on('touchmove', '.km-header', preventScrollIfNotInput);
                    if (!that.options.useNativeScrolling && !that.options.stretch) {
                        $(that.element).on('touchmove', '.km-content', preventScrollIfNotInput);
                    }
                }
            },
            _model: function () {
                var that = this, element = that.element, model = that.options.model;
                if (typeof model === 'string') {
                    model = kendo.getter(model)(that.options.modelScope);
                }
                that.model = model;
                initPopOvers(element);
                that.element.css('display', '');
                if (that.options.initWidgets) {
                    if (model) {
                        kendo.bind(element, model, ui, kendo.ui, kendo.dataviz.ui);
                    } else {
                        mobile.init(element.children());
                    }
                }
                that.element.css('display', 'none');
            },
            _id: function () {
                var element = this.element, idAttrValue = element.attr('id') || '';
                this.id = attrValue(element, 'url') || '#' + idAttrValue;
                if (this.id == '#') {
                    this.id = kendo.guid();
                    element.attr('id', this.id);
                }
            },
            _layout: function () {
                var contentSelector = roleSelector('content'), element = this.element;
                element.addClass('km-view');
                this.header = element.children(roleSelector('header')).addClass('km-header');
                this.footer = element.children(roleSelector('footer')).addClass('km-footer');
                if (!element.children(contentSelector)[0]) {
                    element.wrapInner('<div ' + attr('role') + '="content"></div>');
                }
                this.content = element.children(roleSelector('content')).addClass('km-content');
                this.element.prepend(this.header).append(this.footer);
                this.layout = this.options.getLayout(this.layout);
                if (this.layout) {
                    this.layout.setup(this);
                }
            },
            _overlay: function () {
                this.overlay = $(UI_OVERLAY).appendTo(this.element);
            },
            _invokeNgController: function () {
                var controller, scope;
                if (this.options.$angular) {
                    controller = this.element.controller();
                    scope = this.options.$angular[0];
                    if (controller) {
                        var callback = $.proxy(this, '_callController', controller, scope);
                        if (/^\$(digest|apply)$/.test(scope.$$phase)) {
                            callback();
                        } else {
                            scope.$apply(callback);
                        }
                    }
                }
            },
            _callController: function (controller, scope) {
                this.element.injector().invoke(controller.constructor, controller, { $scope: scope });
            }
        });
        function initWidgets(collection) {
            collection.each(function () {
                kendo.initWidget($(this), {}, ui.roles);
            });
        }
        var Layout = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                element = this.element;
                this.header = element.children(this._locate('header')).addClass('km-header');
                this.footer = element.children(this._locate('footer')).addClass('km-footer');
                this.elements = this.header.add(this.footer);
                initPopOvers(element);
                if (!this.options.$angular) {
                    kendo.mobile.init(this.element.children());
                }
                this.element.detach();
                this.trigger(INIT, { layout: this });
            },
            _locate: function (selectors) {
                return this.options.$angular ? directiveSelector(selectors) : roleSelector(selectors);
            },
            options: {
                name: 'Layout',
                id: null,
                platform: null
            },
            events: [
                INIT,
                SHOW,
                HIDE
            ],
            setup: function (view) {
                if (!view.header[0]) {
                    view.header = this.header;
                }
                if (!view.footer[0]) {
                    view.footer = this.footer;
                }
            },
            detach: function (view) {
                var that = this;
                if (view.header === that.header && that.header[0]) {
                    view.element.prepend(that.header.detach()[0].cloneNode(true));
                }
                if (view.footer === that.footer && that.footer.length) {
                    view.element.append(that.footer.detach()[0].cloneNode(true));
                }
            },
            attach: function (view) {
                var that = this, previousView = that.currentView;
                if (previousView) {
                    that.detach(previousView);
                }
                if (view.header === that.header) {
                    that.header.detach();
                    view.element.children(roleSelector('header')).remove();
                    view.element.prepend(that.header);
                }
                if (view.footer === that.footer) {
                    that.footer.detach();
                    view.element.children(roleSelector('footer')).remove();
                    view.element.append(that.footer);
                }
                that.trigger(SHOW, {
                    layout: that,
                    view: view
                });
                that.currentView = view;
            }
        });
        var Observable = kendo.Observable, bodyRegExp = /<body[^>]*>(([\u000a\u000d\u2028\u2029]|.)*)<\/body>/i, LOAD_START = 'loadStart', LOAD_COMPLETE = 'loadComplete', SHOW_START = 'showStart', SAME_VIEW_REQUESTED = 'sameViewRequested', VIEW_SHOW = 'viewShow', VIEW_TYPE_DETERMINED = 'viewTypeDetermined', AFTER = 'after';
        var ViewEngine = Observable.extend({
            init: function (options) {
                var that = this, views, errorMessage, container, collection;
                Observable.fn.init.call(that);
                $.extend(that, options);
                that.sandbox = $('<div />');
                container = that.container;
                views = that._hideViews(container);
                that.rootView = views.first();
                if (!that.rootView[0] && options.rootNeeded) {
                    if (container[0] == kendo.mobile.application.element[0]) {
                        errorMessage = 'Your kendo mobile application element does not contain any direct child elements with data-role="view" attribute set. Make sure that you instantiate the mobile application using the correct container.';
                    } else {
                        errorMessage = 'Your pane element does not contain any direct child elements with data-role="view" attribute set.';
                    }
                    throw new Error(errorMessage);
                }
                that.layouts = {};
                that.viewContainer = new kendo.ViewContainer(that.container);
                that.viewContainer.bind('accepted', function (e) {
                    e.view.params = that.params;
                });
                that.viewContainer.bind('complete', function (e) {
                    that.trigger(VIEW_SHOW, { view: e.view });
                });
                that.viewContainer.bind(AFTER, function () {
                    that.trigger(AFTER);
                });
                this.getLayoutProxy = $.proxy(this, '_getLayout');
                that._setupLayouts(container);
                collection = container.children(that._locate('modalview drawer'));
                if (that.$angular) {
                    that.$angular[0].viewOptions = {
                        defaultTransition: that.transition,
                        loader: that.loader,
                        container: that.container,
                        getLayout: that.getLayoutProxy
                    };
                    collection.each(function (idx, element) {
                        compileMobileDirective($(element), options.$angular[0]);
                    });
                } else {
                    initWidgets(collection);
                }
                this.bind(this.events, options);
            },
            events: [
                SHOW_START,
                AFTER,
                VIEW_SHOW,
                LOAD_START,
                LOAD_COMPLETE,
                SAME_VIEW_REQUESTED,
                VIEW_TYPE_DETERMINED
            ],
            destroy: function () {
                kendo.destroy(this.container);
                for (var id in this.layouts) {
                    this.layouts[id].destroy();
                }
            },
            view: function () {
                return this.viewContainer.view;
            },
            showView: function (url, transition, params) {
                url = url.replace(new RegExp('^' + this.remoteViewURLPrefix), '');
                if (url === '' && this.remoteViewURLPrefix) {
                    url = '/';
                }
                if (url.replace(/^#/, '') === this.url) {
                    this.trigger(SAME_VIEW_REQUESTED);
                    return false;
                }
                this.trigger(SHOW_START);
                var that = this, showClosure = function (view) {
                        return that.viewContainer.show(view, transition, url);
                    }, element = that._findViewElement(url), view = kendo.widgetInstance(element);
                that.url = url.replace(/^#/, '');
                that.params = params;
                if (view && view.reload) {
                    view.purge();
                    element = [];
                }
                this.trigger(VIEW_TYPE_DETERMINED, {
                    remote: element.length === 0,
                    url: url
                });
                if (element[0]) {
                    if (!view) {
                        view = that._createView(element);
                    }
                    return showClosure(view);
                } else {
                    if (this.serverNavigation) {
                        location.href = url;
                    } else {
                        that._loadView(url, showClosure);
                    }
                    return true;
                }
            },
            append: function (html, url) {
                var sandbox = this.sandbox, urlPath = (url || '').split('?')[0], container = this.container, views, modalViews, view;
                if (bodyRegExp.test(html)) {
                    html = RegExp.$1;
                }
                sandbox[0].innerHTML = html;
                container.append(sandbox.children('script, style'));
                views = this._hideViews(sandbox);
                view = views.first();
                if (!view.length) {
                    views = view = sandbox.wrapInner('<div data-role=view />').children();
                }
                if (urlPath) {
                    view.hide().attr(attr('url'), urlPath);
                }
                this._setupLayouts(sandbox);
                modalViews = sandbox.children(this._locate('modalview drawer'));
                container.append(sandbox.children(this._locate('layout modalview drawer')).add(views));
                initWidgets(modalViews);
                return this._createView(view);
            },
            _locate: function (selectors) {
                return this.$angular ? directiveSelector(selectors) : roleSelector(selectors);
            },
            _findViewElement: function (url) {
                var element, urlPath = url.split('?')[0];
                if (!urlPath) {
                    return this.rootView;
                }
                element = this.container.children('[' + attr('url') + '=\'' + urlPath + '\']');
                if (!element[0] && urlPath.indexOf('/') === -1) {
                    element = this.container.children(urlPath.charAt(0) === '#' ? urlPath : '#' + urlPath);
                }
                return element;
            },
            _createView: function (element) {
                if (this.$angular) {
                    return compileMobileDirective(element, this.$angular[0]);
                } else {
                    return kendo.initWidget(element, {
                        defaultTransition: this.transition,
                        loader: this.loader,
                        container: this.container,
                        getLayout: this.getLayoutProxy,
                        modelScope: this.modelScope,
                        reload: attrValue(element, 'reload')
                    }, ui.roles);
                }
            },
            _getLayout: function (name) {
                if (name === '') {
                    return null;
                }
                return name ? this.layouts[name] : this.layouts[this.layout];
            },
            _loadView: function (url, callback) {
                if (this._xhr) {
                    this._xhr.abort();
                }
                this.trigger(LOAD_START);
                this._xhr = $.get(kendo.absoluteURL(url, this.remoteViewURLPrefix), 'html').always($.proxy(this, '_xhrComplete', callback, url));
            },
            _xhrComplete: function (callback, url, response) {
                var success = true;
                if (typeof response === 'object') {
                    if (response.status === 0) {
                        if (response.responseText && response.responseText.length > 0) {
                            success = true;
                            response = response.responseText;
                        } else {
                            return;
                        }
                    }
                }
                this.trigger(LOAD_COMPLETE);
                if (success) {
                    callback(this.append(response, url));
                }
            },
            _hideViews: function (container) {
                return container.children(this._locate('view splitview')).hide();
            },
            _setupLayouts: function (element) {
                var that = this, layout;
                element.children(that._locate('layout')).each(function () {
                    if (that.$angular) {
                        layout = compileMobileDirective($(this), that.$angular[0]);
                    } else {
                        layout = kendo.initWidget($(this), {}, ui.roles);
                    }
                    var platform = layout.options.platform;
                    if (!platform || platform === mobile.application.os.name) {
                        that.layouts[layout.options.id] = layout;
                    } else {
                        layout.destroy();
                    }
                });
            }
        });
        kendo.mobile.ViewEngine = ViewEngine;
        ui.plugin(View);
        ui.plugin(Layout);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.loader', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'mobile.loader',
        name: 'Loader',
        category: 'mobile',
        description: 'Mobile Loader',
        depends: ['core'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, CAPTURE_EVENTS = $.map(kendo.eventMap, function (value) {
                return value;
            }).join(' ').split(' ');
        var Loader = Widget.extend({
            init: function (container, options) {
                var that = this, element = $('<div class="km-loader"><span class="km-loading km-spin"></span><span class="km-loading-left"></span><span class="km-loading-right"></span></div>');
                Widget.fn.init.call(that, element, options);
                that.container = container;
                that.captureEvents = false;
                that._attachCapture();
                element.append(that.options.loading).hide().appendTo(container);
            },
            options: {
                name: 'Loader',
                loading: '<h1>Loading...</h1>',
                timeout: 100
            },
            show: function () {
                var that = this;
                clearTimeout(that._loading);
                if (that.options.loading === false) {
                    return;
                }
                that.captureEvents = true;
                that._loading = setTimeout(function () {
                    that.element.show();
                }, that.options.timeout);
            },
            hide: function () {
                this.captureEvents = false;
                clearTimeout(this._loading);
                this.element.hide();
            },
            changeMessage: function (message) {
                this.options.loading = message;
                this.element.find('>h1').html(message);
            },
            transition: function () {
                this.captureEvents = true;
                this.container.css('pointer-events', 'none');
            },
            transitionDone: function () {
                this.captureEvents = false;
                this.container.css('pointer-events', '');
            },
            _attachCapture: function () {
                var that = this;
                that.captureEvents = false;
                function capture(e) {
                    if (that.captureEvents) {
                        e.preventDefault();
                    }
                }
                for (var i = 0; i < CAPTURE_EVENTS.length; i++) {
                    that.container[0].addEventListener(CAPTURE_EVENTS[i], capture, true);
                }
            }
        });
        ui.plugin(Loader);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.pane', [
        'kendo.mobile.view',
        'kendo.mobile.loader'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.pane',
        name: 'Pane',
        category: 'mobile',
        description: 'Mobile Pane',
        depends: [
            'mobile.view',
            'mobile.loader'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, roleSelector = kendo.roleSelector, ui = mobile.ui, Widget = ui.Widget, ViewEngine = mobile.ViewEngine, View = ui.View, Loader = mobile.ui.Loader, EXTERNAL = 'external', HREF = 'href', DUMMY_HREF = '#!', NAVIGATE = 'navigate', VIEW_SHOW = 'viewShow', SAME_VIEW_REQUESTED = 'sameViewRequested', OS = kendo.support.mobileOS, SKIP_TRANSITION_ON_BACK_BUTTON = OS.ios && !OS.appMode && OS.flatVersion >= 700, WIDGET_RELS = /popover|actionsheet|modalview|drawer/, BACK = '#:back', attrValue = kendo.attrValue;
        var Pane = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element;
                element.addClass('km-pane');
                if (that.options.collapsible) {
                    element.addClass('km-collapsible-pane');
                }
                this.history = [];
                this.historyCallback = function (url, params, backButtonPressed) {
                    var transition = that.transition;
                    that.transition = null;
                    if (SKIP_TRANSITION_ON_BACK_BUTTON && backButtonPressed) {
                        transition = 'none';
                    }
                    return that.viewEngine.showView(url, transition, params);
                };
                this._historyNavigate = function (url) {
                    if (url === BACK) {
                        if (that.history.length === 1) {
                            return;
                        }
                        that.history.pop();
                        url = that.history[that.history.length - 1];
                    } else {
                        that.history.push(url);
                    }
                    that.historyCallback(url, kendo.parseQueryStringParams(url));
                };
                this._historyReplace = function (url) {
                    var params = kendo.parseQueryStringParams(url);
                    that.history[that.history.length - 1] = url;
                    that.historyCallback(url, params);
                };
                that.loader = new Loader(element, { loading: that.options.loading });
                that.viewEngine = new ViewEngine({
                    container: element,
                    transition: options.transition,
                    modelScope: options.modelScope,
                    rootNeeded: !options.initial,
                    serverNavigation: options.serverNavigation,
                    remoteViewURLPrefix: options.root || '',
                    layout: options.layout,
                    $angular: options.$angular,
                    loader: that.loader,
                    showStart: function () {
                        that.loader.transition();
                        that.closeActiveDialogs();
                    },
                    after: function () {
                        that.loader.transitionDone();
                    },
                    viewShow: function (e) {
                        that.trigger(VIEW_SHOW, e);
                    },
                    loadStart: function () {
                        that.loader.show();
                    },
                    loadComplete: function () {
                        that.loader.hide();
                    },
                    sameViewRequested: function () {
                        that.trigger(SAME_VIEW_REQUESTED);
                    },
                    viewTypeDetermined: function (e) {
                        if (!e.remote || !that.options.serverNavigation) {
                            that.trigger(NAVIGATE, { url: e.url });
                        }
                    }
                });
                this._setPortraitWidth();
                kendo.onResize(function () {
                    that._setPortraitWidth();
                });
                that._setupAppLinks();
            },
            closeActiveDialogs: function () {
                var dialogs = this.element.find(roleSelector('actionsheet popover modalview')).filter(':visible');
                dialogs.each(function () {
                    kendo.widgetInstance($(this), ui).close();
                });
            },
            navigateToInitial: function () {
                var initial = this.options.initial;
                if (initial) {
                    this.navigate(initial);
                }
                return initial;
            },
            options: {
                name: 'Pane',
                portraitWidth: '',
                transition: '',
                layout: '',
                collapsible: false,
                initial: null,
                modelScope: window,
                loading: '<h1>Loading...</h1>'
            },
            events: [
                NAVIGATE,
                VIEW_SHOW,
                SAME_VIEW_REQUESTED
            ],
            append: function (html) {
                return this.viewEngine.append(html);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.viewEngine.destroy();
                this.userEvents.destroy();
            },
            navigate: function (url, transition) {
                if (url instanceof View) {
                    url = url.id;
                }
                this.transition = transition;
                this._historyNavigate(url);
            },
            replace: function (url, transition) {
                if (url instanceof View) {
                    url = url.id;
                }
                this.transition = transition;
                this._historyReplace(url);
            },
            bindToRouter: function (router) {
                var that = this, history = this.history, viewEngine = this.viewEngine;
                router.bind('init', function (e) {
                    var url = e.url, attrUrl = router.pushState ? url : '/';
                    viewEngine.rootView.attr(kendo.attr('url'), attrUrl);
                    var length = history.length;
                    if (url === '/' && length) {
                        router.navigate(history[length - 1], true);
                        e.preventDefault();
                    }
                });
                router.bind('routeMissing', function (e) {
                    if (!that.historyCallback(e.url, e.params, e.backButtonPressed)) {
                        e.preventDefault();
                    }
                });
                router.bind('same', function () {
                    that.trigger(SAME_VIEW_REQUESTED);
                });
                that._historyNavigate = function (url) {
                    router.navigate(url);
                };
                that._historyReplace = function (url) {
                    router.replace(url);
                };
            },
            hideLoading: function () {
                this.loader.hide();
            },
            showLoading: function () {
                this.loader.show();
            },
            changeLoadingMessage: function (message) {
                this.loader.changeMessage(message);
            },
            view: function () {
                return this.viewEngine.view();
            },
            _setPortraitWidth: function () {
                var width, portraitWidth = this.options.portraitWidth;
                if (portraitWidth) {
                    width = kendo.mobile.application.element.is('.km-vertical') ? portraitWidth : 'auto';
                    this.element.css('width', width);
                }
            },
            _setupAppLinks: function () {
                var that = this, linkRoles = 'tab', pressedButtonSelector = '[data-' + kendo.ns + 'navigate-on-press]', buttonSelectors = $.map([
                        'button',
                        'backbutton',
                        'detailbutton',
                        'listview-link'
                    ], function (role) {
                        return roleSelector(role) + ':not(' + pressedButtonSelector + ')';
                    }).join(',');
                this.element.handler(this).on('down', roleSelector(linkRoles) + ',' + pressedButtonSelector, '_mouseup').on('click', roleSelector(linkRoles) + ',' + buttonSelectors + ',' + pressedButtonSelector, '_appLinkClick');
                this.userEvents = new kendo.UserEvents(this.element, {
                    fastTap: true,
                    filter: buttonSelectors,
                    tap: function (e) {
                        e.event.currentTarget = e.touch.currentTarget;
                        that._mouseup(e.event);
                    }
                });
                this.element.css('-ms-touch-action', '');
            },
            _appLinkClick: function (e) {
                var href = $(e.currentTarget).attr('href');
                var remote = href && href[0] !== '#' && this.options.serverNavigation;
                if (!remote && attrValue($(e.currentTarget), 'rel') != EXTERNAL) {
                    e.preventDefault();
                }
            },
            _mouseup: function (e) {
                if (e.which > 1 || e.isDefaultPrevented()) {
                    return;
                }
                var pane = this, link = $(e.currentTarget), transition = attrValue(link, 'transition'), rel = attrValue(link, 'rel') || '', target = attrValue(link, 'target'), href = link.attr(HREF), delayedTouchEnd = SKIP_TRANSITION_ON_BACK_BUTTON && link[0].offsetHeight === 0, remote = href && href[0] !== '#' && this.options.serverNavigation;
                if (delayedTouchEnd || remote || rel === EXTERNAL || typeof href === 'undefined' || href === DUMMY_HREF) {
                    return;
                }
                link.attr(HREF, DUMMY_HREF);
                setTimeout(function () {
                    link.attr(HREF, href);
                });
                if (rel.match(WIDGET_RELS)) {
                    kendo.widgetInstance($(href), ui).openFor(link);
                    if (rel === 'actionsheet' || rel === 'drawer') {
                        e.stopPropagation();
                    }
                } else {
                    if (target === '_top') {
                        pane = mobile.application.pane;
                    } else if (target) {
                        pane = $('#' + target).data('kendoMobilePane');
                    }
                    pane.navigate(href, transition);
                }
                e.preventDefault();
            }
        });
        Pane.wrap = function (element) {
            if (!element.is(roleSelector('view'))) {
                element = element.wrap('<div data-' + kendo.ns + 'role="view" data-stretch="true"></div>').parent();
            }
            var paneContainer = element.wrap('<div class="km-pane-wrapper"><div></div></div>').parent(), pane = new Pane(paneContainer);
            pane.navigate('');
            return pane;
        };
        ui.plugin(Pane);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.popover', [
        'kendo.popup',
        'kendo.mobile.pane'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.popover',
        name: 'PopOver',
        category: 'mobile',
        description: 'The mobile PopOver widget represents a transient view which is displayed when the user taps on a navigational widget or area on the screen. ',
        depends: [
            'popup',
            'mobile.pane'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, HIDE = 'hide', OPEN = 'open', CLOSE = 'close', WRAPPER = '<div class="km-popup-wrapper" />', ARROW = '<div class="km-popup-arrow" />', OVERLAY = '<div class="km-popup-overlay" />', DIRECTION_CLASSES = 'km-up km-down km-left km-right', Widget = ui.Widget, DIRECTIONS = {
                'down': {
                    origin: 'bottom center',
                    position: 'top center'
                },
                'up': {
                    origin: 'top center',
                    position: 'bottom center'
                },
                'left': {
                    origin: 'center left',
                    position: 'center right',
                    collision: 'fit flip'
                },
                'right': {
                    origin: 'center right',
                    position: 'center left',
                    collision: 'fit flip'
                }
            }, ANIMATION = {
                animation: {
                    open: {
                        effects: 'fade:in',
                        duration: 0
                    },
                    close: {
                        effects: 'fade:out',
                        duration: 400
                    }
                }
            }, DIMENSIONS = {
                'horizontal': {
                    offset: 'top',
                    size: 'height'
                },
                'vertical': {
                    offset: 'left',
                    size: 'width'
                }
            }, REVERSE = {
                'up': 'down',
                'down': 'up',
                'left': 'right',
                'right': 'left'
            };
        var Popup = Widget.extend({
            init: function (element, options) {
                var that = this, containerPopup = element.closest('.km-modalview-wrapper'), viewport = element.closest('.km-root').children('.km-pane').first(), container = containerPopup[0] ? containerPopup : viewport, popupOptions, axis;
                if (options.viewport) {
                    viewport = options.viewport;
                } else if (!viewport[0]) {
                    viewport = window;
                }
                if (options.container) {
                    container = options.container;
                } else if (!container[0]) {
                    container = document.body;
                }
                popupOptions = {
                    viewport: viewport,
                    copyAnchorStyles: false,
                    autosize: true,
                    open: function () {
                        that.overlay.show();
                    },
                    activate: $.proxy(that._activate, that),
                    deactivate: function () {
                        that.overlay.hide();
                        if (!that._apiCall) {
                            that.trigger(HIDE);
                        }
                        that._apiCall = false;
                    }
                };
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                element.wrap(WRAPPER).addClass('km-popup').show();
                axis = that.options.direction.match(/left|right/) ? 'horizontal' : 'vertical';
                that.dimensions = DIMENSIONS[axis];
                that.wrapper = element.parent().css({
                    width: options.width,
                    height: options.height
                }).addClass('km-popup-wrapper km-' + options.direction).hide();
                that.arrow = $(ARROW).prependTo(that.wrapper).hide();
                that.overlay = $(OVERLAY).appendTo(container).hide();
                popupOptions.appendTo = that.overlay;
                if (options.className) {
                    that.overlay.addClass(options.className);
                }
                that.popup = new kendo.ui.Popup(that.wrapper, $.extend(true, popupOptions, ANIMATION, DIRECTIONS[options.direction]));
            },
            options: {
                name: 'Popup',
                width: 240,
                height: '',
                direction: 'down',
                container: null,
                viewport: null
            },
            events: [HIDE],
            show: function (target) {
                this.popup.options.anchor = $(target);
                this.popup.open();
            },
            hide: function () {
                this._apiCall = true;
                this.popup.close();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.popup.destroy();
                this.overlay.remove();
            },
            target: function () {
                return this.popup.options.anchor;
            },
            _activate: function () {
                var that = this, direction = that.options.direction, dimensions = that.dimensions, offset = dimensions.offset, popup = that.popup, anchor = popup.options.anchor, anchorOffset = $(anchor).offset(), elementOffset = $(popup.element).offset(), cssClass = popup.flipped ? REVERSE[direction] : direction, min = that.arrow[dimensions.size]() * 2, max = that.element[dimensions.size]() - that.arrow[dimensions.size](), size = $(anchor)[dimensions.size](), offsetAmount = anchorOffset[offset] - elementOffset[offset] + size / 2;
                if (offsetAmount < min) {
                    offsetAmount = min;
                }
                if (offsetAmount > max) {
                    offsetAmount = max;
                }
                that.wrapper.removeClass(DIRECTION_CLASSES).addClass('km-' + cssClass);
                that.arrow.css(offset, offsetAmount).show();
            }
        });
        var PopOver = Widget.extend({
            init: function (element, options) {
                var that = this, popupOptions;
                that.initialOpen = false;
                Widget.fn.init.call(that, element, options);
                popupOptions = $.extend({
                    className: 'km-popover-root',
                    hide: function () {
                        that.trigger(CLOSE);
                    }
                }, this.options.popup);
                that.popup = new Popup(that.element, popupOptions);
                that.popup.overlay.on('move', function (e) {
                    if (e.target == that.popup.overlay[0]) {
                        e.preventDefault();
                    }
                });
                that.pane = new ui.Pane(that.element, $.extend(this.options.pane, { $angular: this.options.$angular }));
                kendo.notify(that, ui);
            },
            options: {
                name: 'PopOver',
                popup: {},
                pane: {}
            },
            events: [
                OPEN,
                CLOSE
            ],
            open: function (target) {
                this.popup.show(target);
                if (!this.initialOpen) {
                    if (!this.pane.navigateToInitial()) {
                        this.pane.navigate('');
                    }
                    this.popup.popup._position();
                    this.initialOpen = true;
                } else {
                    this.pane.view()._invokeNgController();
                }
            },
            openFor: function (target) {
                this.open(target);
                this.trigger(OPEN, { target: this.popup.target() });
            },
            close: function () {
                this.popup.hide();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.pane.destroy();
                this.popup.destroy();
                kendo.destroy(this.element);
            }
        });
        ui.plugin(Popup);
        ui.plugin(PopOver);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.shim', ['kendo.popup'], f);
}(function () {
    var __meta__ = {
        id: 'mobile.shim',
        name: 'Shim',
        category: 'mobile',
        description: 'Mobile Shim',
        depends: ['popup'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.mobile.ui, Popup = kendo.ui.Popup, SHIM = '<div class="km-shim"/>', HIDE = 'hide', Widget = ui.Widget;
        var Shim = Widget.extend({
            init: function (element, options) {
                var that = this, app = kendo.mobile.application, os = kendo.support.mobileOS, osname = app ? app.os.name : os ? os.name : 'ios', ioswp = osname === 'ios' || osname === 'wp' || (app ? app.os.skin : false), bb = osname === 'blackberry', align = options.align || (ioswp ? 'bottom center' : bb ? 'center right' : 'center center'), position = options.position || (ioswp ? 'bottom center' : bb ? 'center right' : 'center center'), effect = options.effect || (ioswp ? 'slideIn:up' : bb ? 'slideIn:left' : 'fade:in'), shim = $(SHIM).handler(that).hide();
                Widget.fn.init.call(that, element, options);
                that.shim = shim;
                element = that.element;
                options = that.options;
                if (options.className) {
                    that.shim.addClass(options.className);
                }
                if (!options.modal) {
                    that.shim.on('down', '_hide');
                }
                (app ? app.element : $(document.body)).append(shim);
                that.popup = new Popup(that.element, {
                    anchor: shim,
                    modal: true,
                    appendTo: shim,
                    origin: align,
                    position: position,
                    animation: {
                        open: {
                            effects: effect,
                            duration: options.duration
                        },
                        close: { duration: options.duration }
                    },
                    close: function (e) {
                        var prevented = false;
                        if (!that._apiCall) {
                            prevented = that.trigger(HIDE);
                        }
                        if (prevented) {
                            e.preventDefault();
                        }
                        that._apiCall = false;
                    },
                    deactivate: function () {
                        shim.hide();
                    },
                    open: function () {
                        shim.show();
                    }
                });
                kendo.notify(that);
            },
            events: [HIDE],
            options: {
                name: 'Shim',
                modal: false,
                align: undefined,
                position: undefined,
                effect: undefined,
                duration: 200
            },
            show: function () {
                this.popup.open();
            },
            hide: function () {
                this._apiCall = true;
                this.popup.close();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.shim.kendoDestroy();
                this.popup.destroy();
                this.shim.remove();
            },
            _hide: function (e) {
                if (!e || !$.contains(this.shim.children().children('.k-popup')[0], e.target)) {
                    this.popup.close();
                }
            }
        });
        ui.plugin(Shim);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.actionsheet', [
        'kendo.mobile.popover',
        'kendo.mobile.shim'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.actionsheet',
        name: 'ActionSheet',
        category: 'mobile',
        description: 'The mobile ActionSheet widget displays a set of choices related to a task the user initiates.',
        depends: [
            'mobile.popover',
            'mobile.shim'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, support = kendo.support, ui = kendo.mobile.ui, Shim = ui.Shim, Popup = ui.Popup, Widget = ui.Widget, OPEN = 'open', CLOSE = 'close', COMMAND = 'command', BUTTONS = 'li>a', CONTEXT_DATA = 'actionsheetContext', WRAP = '<div class="km-actionsheet-wrapper" />', cancelTemplate = kendo.template('<li class="km-actionsheet-cancel"><a href="\\#">#:cancel#</a></li>');
        var ActionSheet = Widget.extend({
            init: function (element, options) {
                var that = this, ShimClass, tablet, type, os = support.mobileOS;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                type = options.type;
                element = that.element;
                if (type === 'auto') {
                    tablet = os && os.tablet;
                } else {
                    tablet = type === 'tablet';
                }
                ShimClass = tablet ? Popup : Shim;
                if (options.cancelTemplate) {
                    cancelTemplate = kendo.template(options.cancelTemplate);
                }
                element.addClass('km-actionsheet').append(cancelTemplate({ cancel: that.options.cancel })).wrap(WRAP).on('up', BUTTONS, '_click').on('click', BUTTONS, kendo.preventDefault);
                that.view().bind('destroy', function () {
                    that.destroy();
                });
                that.wrapper = element.parent().addClass(type ? ' km-actionsheet-' + type : '');
                that.shim = new ShimClass(that.wrapper, $.extend({
                    modal: os.ios && os.majorVersion < 7,
                    className: 'km-actionsheet-root'
                }, that.options.popup));
                that._closeProxy = $.proxy(that, '_close');
                that._shimHideProxy = $.proxy(that, '_shimHide');
                that.shim.bind('hide', that._shimHideProxy);
                if (tablet) {
                    kendo.onResize(that._closeProxy);
                }
                kendo.notify(that, ui);
            },
            events: [
                OPEN,
                CLOSE,
                COMMAND
            ],
            options: {
                name: 'ActionSheet',
                cancel: 'Cancel',
                type: 'auto',
                popup: { height: 'auto' }
            },
            open: function (target, context) {
                var that = this;
                that.target = $(target);
                that.context = context;
                that.shim.show(target);
            },
            close: function () {
                this.context = this.target = null;
                this.shim.hide();
            },
            openFor: function (target) {
                var that = this, context = target.data(CONTEXT_DATA);
                that.open(target, context);
                that.trigger(OPEN, {
                    target: target,
                    context: context
                });
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                kendo.unbindResize(this._closeProxy);
                this.shim.destroy();
            },
            _click: function (e) {
                if (e.isDefaultPrevented()) {
                    return;
                }
                var currentTarget = $(e.currentTarget);
                var action = currentTarget.data('action');
                if (action) {
                    var actionData = {
                            target: this.target,
                            context: this.context
                        }, $angular = this.options.$angular;
                    if ($angular) {
                        this.element.injector().get('$parse')(action)($angular[0])(actionData);
                    } else {
                        kendo.getter(action)(window)(actionData);
                    }
                }
                this.trigger(COMMAND, {
                    target: this.target,
                    context: this.context,
                    currentTarget: currentTarget
                });
                e.preventDefault();
                this._close();
            },
            _shimHide: function (e) {
                if (!this.trigger(CLOSE)) {
                    this.context = this.target = null;
                } else {
                    e.preventDefault();
                }
            },
            _close: function (e) {
                if (!this.trigger(CLOSE)) {
                    this.close();
                } else {
                    e.preventDefault();
                }
            }
        });
        ui.plugin(ActionSheet);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.progressbar', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'progressbar',
        name: 'ProgressBar',
        category: 'web',
        description: 'The ProgressBar offers rich functionality for displaying and tracking progress',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, HORIZONTAL = 'horizontal', VERTICAL = 'vertical', DEFAULTMIN = 0, DEFAULTMAX = 100, DEFAULTVALUE = 0, DEFAULTCHUNKCOUNT = 5, KPROGRESSBAR = 'k-progressbar', KPROGRESSBARREVERSE = 'k-progressbar-reverse', KPROGRESSBARINDETERMINATE = 'k-progressbar-indeterminate', KPROGRESSBARCOMPLETE = 'k-complete', KPROGRESSWRAPPER = 'k-state-selected', KPROGRESSSTATUS = 'k-progress-status', KCOMPLETEDCHUNK = 'k-state-selected', KUPCOMINGCHUNK = 'k-state-default', KSTATEDISABLED = 'k-state-disabled', PROGRESSTYPE = {
                VALUE: 'value',
                PERCENT: 'percent',
                CHUNK: 'chunk'
            }, CHANGE = 'change', COMPLETE = 'complete', BOOLEAN = 'boolean', math = Math, extend = $.extend, proxy = $.proxy, HUNDREDPERCENT = 100, DEFAULTANIMATIONDURATION = 400, PRECISION = 3, templates = { progressStatus: '<span class=\'k-progress-status-wrap\'><span class=\'k-progress-status\'></span></span>' };
        var ProgressBar = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(this, element, options);
                options = that.options;
                that._progressProperty = options.orientation === HORIZONTAL ? 'width' : 'height';
                that._fields();
                options.value = that._validateValue(options.value);
                that._validateType(options.type);
                that._wrapper();
                that._progressAnimation();
                if (options.value !== options.min && options.value !== false) {
                    that._updateProgress();
                }
            },
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                if (options.hasOwnProperty('reverse')) {
                    that.wrapper.toggleClass('k-progressbar-reverse', options.reverse);
                }
                if (options.hasOwnProperty('enable')) {
                    that.enable(options.enable);
                }
                that._progressAnimation();
                that._validateValue();
                that._updateProgress();
            },
            events: [
                CHANGE,
                COMPLETE
            ],
            options: {
                name: 'ProgressBar',
                orientation: HORIZONTAL,
                reverse: false,
                min: DEFAULTMIN,
                max: DEFAULTMAX,
                value: DEFAULTVALUE,
                enable: true,
                type: PROGRESSTYPE.VALUE,
                chunkCount: DEFAULTCHUNKCOUNT,
                showStatus: true,
                animation: {}
            },
            _fields: function () {
                var that = this;
                that._isStarted = false;
                that.progressWrapper = that.progressStatus = $();
            },
            _validateType: function (currentType) {
                var isValid = false;
                $.each(PROGRESSTYPE, function (k, type) {
                    if (type === currentType) {
                        isValid = true;
                        return false;
                    }
                });
                if (!isValid) {
                    throw new Error(kendo.format('Invalid ProgressBar type \'{0}\'', currentType));
                }
            },
            _wrapper: function () {
                var that = this;
                var container = that.wrapper = that.element;
                var options = that.options;
                var orientation = options.orientation;
                var initialStatusValue;
                container.addClass('k-widget ' + KPROGRESSBAR);
                container.addClass(KPROGRESSBAR + '-' + (orientation === HORIZONTAL ? HORIZONTAL : VERTICAL));
                if (options.enable === false) {
                    container.addClass(KSTATEDISABLED);
                }
                if (options.reverse) {
                    container.addClass(KPROGRESSBARREVERSE);
                }
                if (options.value === false) {
                    container.addClass(KPROGRESSBARINDETERMINATE);
                }
                if (options.type === PROGRESSTYPE.CHUNK) {
                    that._addChunkProgressWrapper();
                } else {
                    if (options.showStatus) {
                        that.progressStatus = that.wrapper.prepend(templates.progressStatus).find('.' + KPROGRESSSTATUS);
                        initialStatusValue = options.value !== false ? options.value : options.min;
                        if (options.type === PROGRESSTYPE.VALUE) {
                            that.progressStatus.text(initialStatusValue);
                        } else {
                            that.progressStatus.text(that._calculatePercentage(initialStatusValue).toFixed() + '%');
                        }
                    }
                }
            },
            value: function (value) {
                return this._value(value);
            },
            _value: function (value) {
                var that = this;
                var options = that.options;
                var validated;
                if (value === undefined) {
                    return options.value;
                } else {
                    if (typeof value !== BOOLEAN) {
                        value = that._roundValue(value);
                        if (!isNaN(value)) {
                            validated = that._validateValue(value);
                            if (validated !== options.value) {
                                that.wrapper.removeClass(KPROGRESSBARINDETERMINATE);
                                options.value = validated;
                                that._isStarted = true;
                                that._updateProgress();
                            }
                        }
                    } else if (!value) {
                        that.wrapper.addClass(KPROGRESSBARINDETERMINATE);
                        options.value = false;
                    }
                }
            },
            _roundValue: function (value) {
                value = parseFloat(value);
                var power = math.pow(10, PRECISION);
                return math.floor(value * power) / power;
            },
            _validateValue: function (value) {
                var that = this;
                var options = that.options;
                if (value !== false) {
                    if (value <= options.min || value === true) {
                        return options.min;
                    } else if (value >= options.max) {
                        return options.max;
                    }
                } else if (value === false) {
                    return false;
                }
                if (isNaN(that._roundValue(value))) {
                    return options.min;
                }
                return value;
            },
            _updateProgress: function () {
                var that = this;
                var options = that.options;
                var percentage = that._calculatePercentage();
                if (options.type === PROGRESSTYPE.CHUNK) {
                    that._updateChunks(percentage);
                    that._onProgressUpdateAlways(options.value);
                } else {
                    that._updateProgressWrapper(percentage);
                }
            },
            _updateChunks: function (percentage) {
                var that = this;
                var options = that.options;
                var chunkCount = options.chunkCount;
                var percentagesPerChunk = parseInt(HUNDREDPERCENT / chunkCount * 100, 10) / 100;
                var percentageParsed = parseInt(percentage * 100, 10) / 100;
                var completedChunksCount = math.floor(percentageParsed / percentagesPerChunk);
                var completedChunks;
                if (options.orientation === HORIZONTAL && !options.reverse || options.orientation === VERTICAL && options.reverse) {
                    completedChunks = that.wrapper.find('li.k-item:lt(' + completedChunksCount + ')');
                } else {
                    completedChunks = that.wrapper.find('li.k-item:gt(-' + (completedChunksCount + 1) + ')');
                }
                that.wrapper.find('.' + KCOMPLETEDCHUNK).removeClass(KCOMPLETEDCHUNK).addClass(KUPCOMINGCHUNK);
                completedChunks.removeClass(KUPCOMINGCHUNK).addClass(KCOMPLETEDCHUNK);
            },
            _updateProgressWrapper: function (percentage) {
                var that = this;
                var options = that.options;
                var progressWrapper = that.wrapper.find('.' + KPROGRESSWRAPPER);
                var animationDuration = that._isStarted ? that._animation.duration : 0;
                var animationCssOptions = {};
                if (progressWrapper.length === 0) {
                    that._addRegularProgressWrapper();
                }
                animationCssOptions[that._progressProperty] = percentage + '%';
                that.progressWrapper.animate(animationCssOptions, {
                    duration: animationDuration,
                    start: proxy(that._onProgressAnimateStart, that),
                    progress: proxy(that._onProgressAnimate, that),
                    complete: proxy(that._onProgressAnimateComplete, that, options.value),
                    always: proxy(that._onProgressUpdateAlways, that, options.value)
                });
            },
            _onProgressAnimateStart: function () {
                this.progressWrapper.show();
            },
            _onProgressAnimate: function (e) {
                var that = this;
                var options = that.options;
                var progressInPercent = parseFloat(e.elem.style[that._progressProperty], 10);
                var progressStatusWrapSize;
                if (options.showStatus) {
                    progressStatusWrapSize = 10000 / parseFloat(that.progressWrapper[0].style[that._progressProperty]);
                    that.progressWrapper.find('.k-progress-status-wrap').css(that._progressProperty, progressStatusWrapSize + '%');
                }
                if (options.type !== PROGRESSTYPE.CHUNK && progressInPercent <= 98) {
                    that.progressWrapper.removeClass(KPROGRESSBARCOMPLETE);
                }
            },
            _onProgressAnimateComplete: function (currentValue) {
                var that = this;
                var options = that.options;
                var progressWrapperSize = parseFloat(that.progressWrapper[0].style[that._progressProperty]);
                var progressValue;
                if (options.type !== PROGRESSTYPE.CHUNK && progressWrapperSize > 98) {
                    that.progressWrapper.addClass(KPROGRESSBARCOMPLETE);
                }
                if (options.showStatus) {
                    if (options.type === PROGRESSTYPE.VALUE) {
                        progressValue = currentValue;
                    } else if (options.type == PROGRESSTYPE.PERCENT) {
                        progressValue = that._calculatePercentage(currentValue).toFixed() + '%';
                    } else {
                        progressValue = math.floor(that._calculatePercentage(currentValue)) + '%';
                    }
                    that.progressStatus.text(progressValue);
                }
                if (currentValue === options.min) {
                    that.progressWrapper.hide();
                }
            },
            _onProgressUpdateAlways: function (currentValue) {
                var that = this;
                var options = that.options;
                if (that._isStarted) {
                    that.trigger(CHANGE, { value: currentValue });
                }
                if (currentValue === options.max && that._isStarted) {
                    that.trigger(COMPLETE, { value: options.max });
                }
            },
            enable: function (enable) {
                var that = this;
                var options = that.options;
                options.enable = typeof enable === 'undefined' ? true : enable;
                that.wrapper.toggleClass(KSTATEDISABLED, !options.enable);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
            },
            _addChunkProgressWrapper: function () {
                var that = this;
                var options = that.options;
                var container = that.wrapper;
                var chunkSize = HUNDREDPERCENT / options.chunkCount;
                var html = '';
                if (options.chunkCount <= 1) {
                    options.chunkCount = 1;
                }
                html += '<ul class=\'k-reset\'>';
                for (var i = options.chunkCount - 1; i >= 0; i--) {
                    html += '<li class=\'k-item k-state-default\'></li>';
                }
                html += '</ul>';
                container.append(html).find('.k-item').css(that._progressProperty, chunkSize + '%').first().addClass('k-first').end().last().addClass('k-last');
                that._normalizeChunkSize();
            },
            _normalizeChunkSize: function () {
                var that = this;
                var options = that.options;
                var lastChunk = that.wrapper.find('.k-item:last');
                var currentSize = parseFloat(lastChunk[0].style[that._progressProperty]);
                var difference = HUNDREDPERCENT - options.chunkCount * currentSize;
                if (difference > 0) {
                    lastChunk.css(that._progressProperty, currentSize + difference + '%');
                }
            },
            _addRegularProgressWrapper: function () {
                var that = this;
                that.progressWrapper = $('<div class=\'' + KPROGRESSWRAPPER + '\'></div>').appendTo(that.wrapper);
                if (that.options.showStatus) {
                    that.progressWrapper.append(templates.progressStatus);
                    that.progressStatus = that.wrapper.find('.' + KPROGRESSSTATUS);
                }
            },
            _calculateChunkSize: function () {
                var that = this;
                var chunkCount = that.options.chunkCount;
                var chunkContainer = that.wrapper.find('ul.k-reset');
                return (parseInt(chunkContainer.css(that._progressProperty), 10) - (chunkCount - 1)) / chunkCount;
            },
            _calculatePercentage: function (currentValue) {
                var that = this;
                var options = that.options;
                var value = currentValue !== undefined ? currentValue : options.value;
                var min = options.min;
                var max = options.max;
                that._onePercent = math.abs((max - min) / 100);
                return math.abs((value - min) / that._onePercent);
            },
            _progressAnimation: function () {
                var that = this;
                var options = that.options;
                var animation = options.animation;
                if (animation === false) {
                    that._animation = { duration: 0 };
                } else {
                    that._animation = extend({ duration: DEFAULTANIMATIONDURATION }, options.animation);
                }
            }
        });
        kendo.ui.plugin(ProgressBar);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf/core', [
        'kendo.core',
        'kendo.color',
        'kendo.drawing'
    ], f);
}(function () {
    (function (kendo) {
        window.kendo.pdf = window.kendo.pdf || {};
        var support = kendo.support;
        var supportBrowser = support.browser;
        var drawing = kendo.drawing;
        var util = drawing.util;
        var kendoGeometry = kendo.geometry;
        var HAS_TYPED_ARRAYS$1 = typeof Uint8Array !== 'undefined';
        var BASE64 = function () {
            var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            return {
                decode: function (str) {
                    var input = str.replace(/[^A-Za-z0-9\+\/\=]/g, ''), i = 0, n = input.length, output = [];
                    while (i < n) {
                        var enc1 = keyStr.indexOf(input.charAt(i++));
                        var enc2 = keyStr.indexOf(input.charAt(i++));
                        var enc3 = keyStr.indexOf(input.charAt(i++));
                        var enc4 = keyStr.indexOf(input.charAt(i++));
                        var chr1 = enc1 << 2 | enc2 >>> 4;
                        var chr2 = (enc2 & 15) << 4 | enc3 >>> 2;
                        var chr3 = (enc3 & 3) << 6 | enc4;
                        output.push(chr1);
                        if (enc3 != 64) {
                            output.push(chr2);
                        }
                        if (enc4 != 64) {
                            output.push(chr3);
                        }
                    }
                    return output;
                },
                encode: function (bytes) {
                    var i = 0, n = bytes.length;
                    var output = '';
                    while (i < n) {
                        var chr1 = bytes[i++];
                        var chr2 = bytes[i++];
                        var chr3 = bytes[i++];
                        var enc1 = chr1 >>> 2;
                        var enc2 = (chr1 & 3) << 4 | chr2 >>> 4;
                        var enc3 = (chr2 & 15) << 2 | chr3 >>> 6;
                        var enc4 = chr3 & 63;
                        if (i - n == 2) {
                            enc3 = enc4 = 64;
                        } else if (i - n == 1) {
                            enc4 = 64;
                        }
                        output += keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
                    }
                    return output;
                }
            };
        }();
        function BinaryStream(data) {
            var offset = 0, length = 0;
            if (data == null) {
                data = HAS_TYPED_ARRAYS$1 ? new Uint8Array(256) : [];
            } else {
                length = data.length;
            }
            var ensure = HAS_TYPED_ARRAYS$1 ? 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$1 ? function () {
                return new Uint8Array(data.buffer, 0, length);
            } : function () {
                return data;
            };
            var write = HAS_TYPED_ARRAYS$1 ? 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$1 ? function (start, length) {
                if (data.buffer.slice) {
                    return new Uint8Array(data.buffer.slice(start, start + length));
                } else {
                    var x = new Uint8Array(length);
                    x.set(new Uint8Array(data.buffer, start, length));
                    return x;
                }
            } : function (start, length) {
                return data.slice(start, start + length);
            };
            function eof() {
                return offset >= length;
            }
            function readByte() {
                return offset < length ? data[offset++] : 0;
            }
            function writeByte(b) {
                ensure(offset);
                data[offset++] = b & 255;
                if (offset > length) {
                    length = offset;
                }
            }
            function readShort() {
                return readByte() << 8 | readByte();
            }
            function writeShort(w) {
                writeByte(w >> 8);
                writeByte(w);
            }
            function readShort_() {
                var w = readShort();
                return w >= 32768 ? w - 65536 : w;
            }
            function writeShort_(w) {
                writeShort(w < 0 ? w + 65536 : w);
            }
            function readLong() {
                return readShort() * 65536 + readShort();
            }
            function writeLong(w) {
                writeShort(w >>> 16 & 65535);
                writeShort(w & 65535);
            }
            function readLong_() {
                var w = readLong();
                return w >= 2147483648 ? w - 4294967296 : w;
            }
            function writeLong_(w) {
                writeLong(w < 0 ? w + 4294967296 : w);
            }
            function readFixed() {
                return readLong() / 65536;
            }
            function writeFixed(f) {
                writeLong(Math.round(f * 65536));
            }
            function readFixed_() {
                return readLong_() / 65536;
            }
            function writeFixed_(f) {
                writeLong_(Math.round(f * 65536));
            }
            function read(len) {
                return times(len, readByte);
            }
            function readString(len) {
                return String.fromCharCode.apply(String, read(len));
            }
            function writeString(str) {
                for (var i = 0; i < str.length; ++i) {
                    writeByte(str.charCodeAt(i));
                }
            }
            function times(n, reader) {
                for (var ret = new Array(n), i = 0; i < n; ++i) {
                    ret[i] = reader();
                }
                return ret;
            }
            var stream = {
                eof: eof,
                readByte: readByte,
                writeByte: writeByte,
                readShort: readShort,
                writeShort: writeShort,
                readLong: readLong,
                writeLong: writeLong,
                readFixed: readFixed,
                writeFixed: writeFixed,
                readShort_: readShort_,
                writeShort_: writeShort_,
                readLong_: readLong_,
                writeLong_: writeLong_,
                readFixed_: readFixed_,
                writeFixed_: writeFixed_,
                read: read,
                write: write,
                readString: readString,
                writeString: writeString,
                times: times,
                get: get,
                slice: slice,
                offset: function (pos) {
                    if (pos != null) {
                        offset = pos;
                        return stream;
                    }
                    return offset;
                },
                skip: function (nbytes) {
                    offset += nbytes;
                },
                toString: function () {
                    throw new Error('FIX CALLER.  BinaryStream is no longer convertible to string!');
                },
                length: function () {
                    return length;
                },
                saveExcursion: function (f) {
                    var pos = offset;
                    try {
                        return f();
                    } finally {
                        offset = pos;
                    }
                },
                writeBase64: function (base64) {
                    if (window.atob) {
                        writeString(window.atob(base64));
                    } else {
                        write(BASE64.decode(base64));
                    }
                },
                base64: function () {
                    return BASE64.encode(get());
                }
            };
            return stream;
        }
        function ucs2decode(string) {
            var output = [], counter = 0, length = string.length, value, extra;
            while (counter < length) {
                value = string.charCodeAt(counter++);
                if (value >= 55296 && value <= 56319 && counter < length) {
                    extra = string.charCodeAt(counter++);
                    if ((extra & 64512) == 56320) {
                        output.push(((value & 1023) << 10) + (extra & 1023) + 65536);
                    } else {
                        output.push(value);
                        counter--;
                    }
                } else {
                    output.push(value);
                }
            }
            return output;
        }
        function ucs2encode(array) {
            return array.map(function (value) {
                var output = '';
                if (value > 65535) {
                    value -= 65536;
                    output += String.fromCharCode(value >>> 10 & 1023 | 55296);
                    value = 56320 | value & 1023;
                }
                output += String.fromCharCode(value);
                return output;
            }).join('');
        }
        function hasOwnProperty$1(obj, key) {
            return Object.prototype.hasOwnProperty.call(obj, key);
        }
        function sortedKeys(obj) {
            return Object.keys(obj).sort(function (a, b) {
                return a - b;
            }).map(parseFloat);
        }
        function Directory(data) {
            this.raw = data;
            this.scalerType = data.readLong();
            this.tableCount = data.readShort();
            this.searchRange = data.readShort();
            this.entrySelector = data.readShort();
            this.rangeShift = data.readShort();
            var tables = this.tables = {};
            for (var i = 0; i < this.tableCount; ++i) {
                var entry = {
                    tag: data.readString(4),
                    checksum: data.readLong(),
                    offset: data.readLong(),
                    length: data.readLong()
                };
                tables[entry.tag] = entry;
            }
        }
        Directory.prototype = {
            readTable: function (name, Ctor) {
                var def = this.tables[name];
                if (!def) {
                    throw new Error('Table ' + name + ' not found in directory');
                }
                return this[name] = def.table = new Ctor(this, def);
            },
            render: function (tables) {
                var this$1 = this;
                var tableCount = Object.keys(tables).length;
                var maxpow2 = Math.pow(2, Math.floor(Math.log(tableCount) / Math.LN2));
                var searchRange = maxpow2 * 16;
                var entrySelector = Math.floor(Math.log(maxpow2) / Math.LN2);
                var rangeShift = tableCount * 16 - searchRange;
                var out = BinaryStream();
                out.writeLong(this.scalerType);
                out.writeShort(tableCount);
                out.writeShort(searchRange);
                out.writeShort(entrySelector);
                out.writeShort(rangeShift);
                var directoryLength = tableCount * 16;
                var offset = out.offset() + directoryLength;
                var headOffset = null;
                var tableData = BinaryStream();
                for (var tag in tables) {
                    if (hasOwnProperty$1(tables, tag)) {
                        var table = tables[tag];
                        out.writeString(tag);
                        out.writeLong(this$1.checksum(table));
                        out.writeLong(offset);
                        out.writeLong(table.length);
                        tableData.write(table);
                        if (tag == 'head') {
                            headOffset = offset;
                        }
                        offset += table.length;
                        while (offset % 4) {
                            tableData.writeByte(0);
                            offset++;
                        }
                    }
                }
                out.write(tableData.get());
                var sum = this.checksum(out.get());
                var adjustment = 2981146554 - sum;
                out.offset(headOffset + 8);
                out.writeLong(adjustment);
                return out.get();
            },
            checksum: function (data) {
                data = BinaryStream(data);
                var sum = 0;
                while (!data.eof()) {
                    sum += data.readLong();
                }
                return sum & 4294967295;
            }
        };
        function deftable(methods) {
            function Ctor(file, def) {
                this.definition = def;
                this.length = def.length;
                this.offset = def.offset;
                this.file = file;
                this.rawData = file.raw;
                this.parse(file.raw);
            }
            Ctor.prototype.raw = function () {
                return this.rawData.slice(this.offset, this.length);
            };
            for (var i in methods) {
                if (hasOwnProperty$1(methods, i)) {
                    Ctor[i] = Ctor.prototype[i] = methods[i];
                }
            }
            return Ctor;
        }
        var HeadTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                this.version = data.readLong();
                this.revision = data.readLong();
                this.checkSumAdjustment = data.readLong();
                this.magicNumber = data.readLong();
                this.flags = data.readShort();
                this.unitsPerEm = data.readShort();
                this.created = data.read(8);
                this.modified = data.read(8);
                this.xMin = data.readShort_();
                this.yMin = data.readShort_();
                this.xMax = data.readShort_();
                this.yMax = data.readShort_();
                this.macStyle = data.readShort();
                this.lowestRecPPEM = data.readShort();
                this.fontDirectionHint = data.readShort_();
                this.indexToLocFormat = data.readShort_();
                this.glyphDataFormat = data.readShort_();
            },
            render: function (indexToLocFormat) {
                var out = BinaryStream();
                out.writeLong(this.version);
                out.writeLong(this.revision);
                out.writeLong(0);
                out.writeLong(this.magicNumber);
                out.writeShort(this.flags);
                out.writeShort(this.unitsPerEm);
                out.write(this.created);
                out.write(this.modified);
                out.writeShort_(this.xMin);
                out.writeShort_(this.yMin);
                out.writeShort_(this.xMax);
                out.writeShort_(this.yMax);
                out.writeShort(this.macStyle);
                out.writeShort(this.lowestRecPPEM);
                out.writeShort_(this.fontDirectionHint);
                out.writeShort_(indexToLocFormat);
                out.writeShort_(this.glyphDataFormat);
                return out.get();
            }
        });
        var LocaTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                var format = this.file.head.indexToLocFormat;
                if (format === 0) {
                    this.offsets = data.times(this.length / 2, function () {
                        return 2 * data.readShort();
                    });
                } else {
                    this.offsets = data.times(this.length / 4, data.readLong);
                }
            },
            offsetOf: function (id) {
                return this.offsets[id];
            },
            lengthOf: function (id) {
                return this.offsets[id + 1] - this.offsets[id];
            },
            render: function (offsets) {
                var out = BinaryStream();
                var needsLongFormat = offsets[offsets.length - 1] > 65535;
                for (var i = 0; i < offsets.length; ++i) {
                    if (needsLongFormat) {
                        out.writeLong(offsets[i]);
                    } else {
                        out.writeShort(offsets[i] / 2);
                    }
                }
                return {
                    format: needsLongFormat ? 1 : 0,
                    table: out.get()
                };
            }
        });
        var HheaTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                this.version = data.readLong();
                this.ascent = data.readShort_();
                this.descent = data.readShort_();
                this.lineGap = data.readShort_();
                this.advanceWidthMax = data.readShort();
                this.minLeftSideBearing = data.readShort_();
                this.minRightSideBearing = data.readShort_();
                this.xMaxExtent = data.readShort_();
                this.caretSlopeRise = data.readShort_();
                this.caretSlopeRun = data.readShort_();
                this.caretOffset = data.readShort_();
                data.skip(4 * 2);
                this.metricDataFormat = data.readShort_();
                this.numOfLongHorMetrics = data.readShort();
            },
            render: function (ids) {
                var out = BinaryStream();
                out.writeLong(this.version);
                out.writeShort_(this.ascent);
                out.writeShort_(this.descent);
                out.writeShort_(this.lineGap);
                out.writeShort(this.advanceWidthMax);
                out.writeShort_(this.minLeftSideBearing);
                out.writeShort_(this.minRightSideBearing);
                out.writeShort_(this.xMaxExtent);
                out.writeShort_(this.caretSlopeRise);
                out.writeShort_(this.caretSlopeRun);
                out.writeShort_(this.caretOffset);
                out.write([
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                    0
                ]);
                out.writeShort_(this.metricDataFormat);
                out.writeShort(ids.length);
                return out.get();
            }
        });
        var MaxpTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                this.version = data.readLong();
                this.numGlyphs = data.readShort();
                this.maxPoints = data.readShort();
                this.maxContours = data.readShort();
                this.maxComponentPoints = data.readShort();
                this.maxComponentContours = data.readShort();
                this.maxZones = data.readShort();
                this.maxTwilightPoints = data.readShort();
                this.maxStorage = data.readShort();
                this.maxFunctionDefs = data.readShort();
                this.maxInstructionDefs = data.readShort();
                this.maxStackElements = data.readShort();
                this.maxSizeOfInstructions = data.readShort();
                this.maxComponentElements = data.readShort();
                this.maxComponentDepth = data.readShort();
            },
            render: function (glyphIds) {
                var out = BinaryStream();
                out.writeLong(this.version);
                out.writeShort(glyphIds.length);
                out.writeShort(this.maxPoints);
                out.writeShort(this.maxContours);
                out.writeShort(this.maxComponentPoints);
                out.writeShort(this.maxComponentContours);
                out.writeShort(this.maxZones);
                out.writeShort(this.maxTwilightPoints);
                out.writeShort(this.maxStorage);
                out.writeShort(this.maxFunctionDefs);
                out.writeShort(this.maxInstructionDefs);
                out.writeShort(this.maxStackElements);
                out.writeShort(this.maxSizeOfInstructions);
                out.writeShort(this.maxComponentElements);
                out.writeShort(this.maxComponentDepth);
                return out.get();
            }
        });
        var HmtxTable = deftable({
            parse: function (data) {
                data.offset(this.offset);
                var dir = this.file, hhea = dir.hhea;
                this.metrics = data.times(hhea.numOfLongHorMetrics, function () {
                    return {
                        advance: data.readShort(),
                        lsb: data.readShort_()
                    };
                });
                var lsbCount = dir.maxp.numGlyphs - dir.hhea.numOfLongHorMetrics;
                this.leftSideBearings = data.times(lsbCount, data.readShort_);
            },
            forGlyph: function (id) {
                var metrics = this.metrics;
                var n = metrics.length;
                if (id < n) {
                    return metrics[id];
                }
                return {
                    advance: metrics[n - 1].advance,
                    lsb: this.leftSideBearings[id - n]
                };
            },
            render: function (glyphIds) {
                var this$1 = this;
                var out = BinaryStream();
                for (var i = 0; i < glyphIds.length; ++i) {
                    var m = this$1.forGlyph(glyphIds[i]);
                    out.writeShort(m.advance);
                    out.writeShort_(m.lsb);
                }
                return out.get();
            }
        });
        var GlyfTable = function () {
            function SimpleGlyph(raw) {
                this.raw = raw;
            }
            SimpleGlyph.prototype = {
                compound: false,
                render: function () {
                    return this.raw.get();
                }
            };
            var ARG_1_AND_2_ARE_WORDS = 1;
            var WE_HAVE_A_SCALE = 8;
            var MORE_COMPONENTS = 32;
            var WE_HAVE_AN_X_AND_Y_SCALE = 64;
            var WE_HAVE_A_TWO_BY_TWO = 128;
            function CompoundGlyph(data) {
                this.raw = data;
                var ids = this.glyphIds = [];
                var offsets = this.idOffsets = [];
                while (true) {
                    var flags = data.readShort();
                    offsets.push(data.offset());
                    ids.push(data.readShort());
                    if (!(flags & MORE_COMPONENTS)) {
                        break;
                    }
                    data.skip(flags & ARG_1_AND_2_ARE_WORDS ? 4 : 2);
                    if (flags & WE_HAVE_A_TWO_BY_TWO) {
                        data.skip(8);
                    } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
                        data.skip(4);
                    } else if (flags & WE_HAVE_A_SCALE) {
                        data.skip(2);
                    }
                }
            }
            CompoundGlyph.prototype = {
                compound: true,
                render: function (old2new) {
                    var this$1 = this;
                    var out = BinaryStream(this.raw.get());
                    for (var i = 0; i < this.glyphIds.length; ++i) {
                        var id = this$1.glyphIds[i];
                        out.offset(this$1.idOffsets[i]);
                        out.writeShort(old2new[id]);
                    }
                    return out.get();
                }
            };
            return deftable({
                parse: function () {
                    this.cache = {};
                },
                glyphFor: function (id) {
                    var cache = this.cache;
                    if (hasOwnProperty$1(cache, id)) {
                        return cache[id];
                    }
                    var loca = this.file.loca;
                    var length = loca.lengthOf(id);
                    if (length === 0) {
                        return cache[id] = null;
                    }
                    var data = this.rawData;
                    var offset = this.offset + loca.offsetOf(id);
                    var raw = BinaryStream(data.slice(offset, length));
                    var numberOfContours = raw.readShort_();
                    var xMin = raw.readShort_();
                    var yMin = raw.readShort_();
                    var xMax = raw.readShort_();
                    var yMax = raw.readShort_();
                    var glyph = cache[id] = numberOfContours == -1 ? new CompoundGlyph(raw) : new SimpleGlyph(raw);
                    glyph.numberOfContours = numberOfContours;
                    glyph.xMin = xMin;
                    glyph.yMin = yMin;
                    glyph.xMax = xMax;
                    glyph.yMax = yMax;
                    return glyph;
                },
                render: function (glyphs, oldIds, old2new) {
                    var out = BinaryStream(), offsets = [];
                    for (var i = 0; i < oldIds.length; ++i) {
                        var id = oldIds[i];
                        var glyph = glyphs[id];
                        offsets.push(out.offset());
                        if (glyph) {
                            out.write(glyph.render(old2new));
                        }
                    }
                    offsets.push(out.offset());
                    return {
                        table: out.get(),
                        offsets: offsets
                    };
                }
            });
        }();
        var NameTable = function () {
            function NameEntry(text, entry) {
                this.text = text;
                this.length = text.length;
                this.platformID = entry.platformID;
                this.platformSpecificID = entry.platformSpecificID;
                this.languageID = entry.languageID;
                this.nameID = entry.nameID;
            }
            return deftable({
                parse: function (data) {
                    data.offset(this.offset);
                    data.readShort();
                    var count = data.readShort();
                    var stringOffset = this.offset + data.readShort();
                    var nameRecords = data.times(count, function () {
                        return {
                            platformID: data.readShort(),
                            platformSpecificID: data.readShort(),
                            languageID: data.readShort(),
                            nameID: data.readShort(),
                            length: data.readShort(),
                            offset: data.readShort() + stringOffset
                        };
                    });
                    var strings = this.strings = {};
                    for (var i = 0; i < nameRecords.length; ++i) {
                        var rec = nameRecords[i];
                        data.offset(rec.offset);
                        var text = data.readString(rec.length);
                        if (!strings[rec.nameID]) {
                            strings[rec.nameID] = [];
                        }
                        strings[rec.nameID].push(new NameEntry(text, rec));
                    }
                    this.postscriptEntry = strings[6][0];
                    this.postscriptName = this.postscriptEntry.text.replace(/[^\x20-\x7F]/g, '');
                },
                render: function (psName) {
                    var this$1 = this;
                    var strings = this.strings;
                    var strCount = 0;
                    for (var i in strings) {
                        if (hasOwnProperty$1(strings, i)) {
                            strCount += strings[i].length;
                        }
                    }
                    var out = BinaryStream();
                    var strTable = BinaryStream();
                    out.writeShort(0);
                    out.writeShort(strCount);
                    out.writeShort(6 + 12 * strCount);
                    for (i in strings) {
                        if (hasOwnProperty$1(strings, i)) {
                            var list = i == 6 ? [new NameEntry(psName, this$1.postscriptEntry)] : strings[i];
                            for (var j = 0; j < list.length; ++j) {
                                var str = list[j];
                                out.writeShort(str.platformID);
                                out.writeShort(str.platformSpecificID);
                                out.writeShort(str.languageID);
                                out.writeShort(str.nameID);
                                out.writeShort(str.length);
                                out.writeShort(strTable.offset());
                                strTable.writeString(str.text);
                            }
                        }
                    }
                    out.write(strTable.get());
                    return out.get();
                }
            });
        }();
        var PostTable = function () {
            var POSTSCRIPT_GLYPHS = '.notdef .null nonmarkingreturn space exclam quotedbl numbersign dollar percent ampersand quotesingle parenleft parenright asterisk plus comma hyphen period slash zero one two three four five six seven eight nine colon semicolon less equal greater question at A B C D E F G H I J K L M N O P Q R S T U V W X Y Z bracketleft backslash bracketright asciicircum underscore grave a b c d e f g h i j k l m n o p q r s t u v w x y z braceleft bar braceright asciitilde Adieresis Aring Ccedilla Eacute Ntilde Odieresis Udieresis aacute agrave acircumflex adieresis atilde aring ccedilla eacute egrave ecircumflex edieresis iacute igrave icircumflex idieresis ntilde oacute ograve ocircumflex odieresis otilde uacute ugrave ucircumflex udieresis dagger degree cent sterling section bullet paragraph germandbls registered copyright trademark acute dieresis notequal AE Oslash infinity plusminus lessequal greaterequal yen mu partialdiff summation product pi integral ordfeminine ordmasculine Omega ae oslash questiondown exclamdown logicalnot radical florin approxequal Delta guillemotleft guillemotright ellipsis nonbreakingspace Agrave Atilde Otilde OE oe endash emdash quotedblleft quotedblright quoteleft quoteright divide lozenge ydieresis Ydieresis fraction currency guilsinglleft guilsinglright fi fl daggerdbl periodcentered quotesinglbase quotedblbase perthousand Acircumflex Ecircumflex Aacute Edieresis Egrave Iacute Icircumflex Idieresis Igrave Oacute Ocircumflex apple Ograve Uacute Ucircumflex Ugrave dotlessi circumflex tilde macron breve dotaccent ring cedilla hungarumlaut ogonek caron Lslash lslash Scaron scaron Zcaron zcaron brokenbar Eth eth Yacute yacute Thorn thorn minus multiply onesuperior twosuperior threesuperior onehalf onequarter threequarters franc Gbreve gbreve Idotaccent Scedilla scedilla Cacute cacute Ccaron ccaron dcroat'.split(/\s+/g);
            return deftable({
                parse: function (data) {
                    var this$1 = this;
                    data.offset(this.offset);
                    this.format = data.readLong();
                    this.italicAngle = data.readFixed_();
                    this.underlinePosition = data.readShort_();
                    this.underlineThickness = data.readShort_();
                    this.isFixedPitch = data.readLong();
                    this.minMemType42 = data.readLong();
                    this.maxMemType42 = data.readLong();
                    this.minMemType1 = data.readLong();
                    this.maxMemType1 = data.readLong();
                    var numberOfGlyphs;
                    switch (this.format) {
                    case 65536:
                    case 196608:
                        break;
                    case 131072:
                        numberOfGlyphs = data.readShort();
                        this.glyphNameIndex = data.times(numberOfGlyphs, data.readShort);
                        this.names = [];
                        var limit = this.offset + this.length;
                        while (data.offset() < limit) {
                            this$1.names.push(data.readString(data.readByte()));
                        }
                        break;
                    case 151552:
                        numberOfGlyphs = data.readShort();
                        this.offsets = data.read(numberOfGlyphs);
                        break;
                    case 262144:
                        this.map = data.times(this.file.maxp.numGlyphs, data.readShort);
                        break;
                    }
                },
                glyphFor: function (code) {
                    switch (this.format) {
                    case 65536:
                        return POSTSCRIPT_GLYPHS[code] || '.notdef';
                    case 131072:
                        var index = this.glyphNameIndex[code];
                        if (index < POSTSCRIPT_GLYPHS.length) {
                            return POSTSCRIPT_GLYPHS[index];
                        }
                        return this.names[index - POSTSCRIPT_GLYPHS.length] || '.notdef';
                    case 151552:
                    case 196608:
                        return '.notdef';
                    case 262144:
                        return this.map[code] || 65535;
                    }
                },
                render: function (mapping) {
                    var this$1 = this;
                    if (this.format == 196608) {
                        return this.raw();
                    }
                    var out = BinaryStream(this.rawData.slice(this.offset, 32));
                    out.writeLong(131072);
                    out.offset(32);
                    var indexes = [];
                    var strings = [];
                    for (var i = 0; i < mapping.length; ++i) {
                        var id = mapping[i];
                        var post = this$1.glyphFor(id);
                        var index = POSTSCRIPT_GLYPHS.indexOf(post);
                        if (index >= 0) {
                            indexes.push(index);
                        } else {
                            indexes.push(POSTSCRIPT_GLYPHS.length + strings.length);
                            strings.push(post);
                        }
                    }
                    out.writeShort(mapping.length);
                    for (i = 0; i < indexes.length; ++i) {
                        out.writeShort(indexes[i]);
                    }
                    for (i = 0; i < strings.length; ++i) {
                        out.writeByte(strings[i].length);
                        out.writeString(strings[i]);
                    }
                    return out.get();
                }
            });
        }();
        var CmapTable = function () {
            function CmapEntry(data, offset, codeMap) {
                var self = this;
                self.platformID = data.readShort();
                self.platformSpecificID = data.readShort();
                self.offset = offset + data.readLong();
                data.saveExcursion(function () {
                    var code;
                    data.offset(self.offset);
                    self.format = data.readShort();
                    switch (self.format) {
                    case 0:
                        self.length = data.readShort();
                        self.language = data.readShort();
                        for (var i = 0; i < 256; ++i) {
                            codeMap[i] = data.readByte();
                        }
                        break;
                    case 4:
                        self.length = data.readShort();
                        self.language = data.readShort();
                        var segCount = data.readShort() / 2;
                        data.skip(6);
                        var endCode = data.times(segCount, data.readShort);
                        data.skip(2);
                        var startCode = data.times(segCount, data.readShort);
                        var idDelta = data.times(segCount, data.readShort_);
                        var idRangeOffset = data.times(segCount, data.readShort);
                        var count = (self.length + self.offset - data.offset()) / 2;
                        var glyphIds = data.times(count, data.readShort);
                        for (i = 0; i < segCount; ++i) {
                            var start = startCode[i], end = endCode[i];
                            for (code = start; code <= end; ++code) {
                                var glyphId;
                                if (idRangeOffset[i] === 0) {
                                    glyphId = code + idDelta[i];
                                } else {
                                    var index = idRangeOffset[i] / 2 - (segCount - i) + (code - start);
                                    glyphId = glyphIds[index] || 0;
                                    if (glyphId !== 0) {
                                        glyphId += idDelta[i];
                                    }
                                }
                                codeMap[code] = glyphId & 65535;
                            }
                        }
                        break;
                    case 6:
                        self.length = data.readShort();
                        self.language = data.readShort();
                        code = data.readShort();
                        var length = data.readShort();
                        while (length-- > 0) {
                            codeMap[code++] = data.readShort();
                        }
                        break;
                    case 12:
                        data.readShort();
                        self.length = data.readLong();
                        self.language = data.readLong();
                        var ngroups = data.readLong();
                        while (ngroups-- > 0) {
                            code = data.readLong();
                            var endCharCode = data.readLong();
                            var glyphCode = data.readLong();
                            while (code <= endCharCode) {
                                codeMap[code++] = glyphCode++;
                            }
                        }
                        break;
                    default:
                        if (window.console) {
                            window.console.error('Unhandled CMAP format: ' + self.format);
                        }
                    }
                });
            }
            function renderCharmap(ncid2ogid, ogid2ngid) {
                var codes = sortedKeys(ncid2ogid);
                var startCodes = [];
                var endCodes = [];
                var last = null;
                var diff = null;
                function new_gid(charcode) {
                    return ogid2ngid[ncid2ogid[charcode]];
                }
                for (var i = 0; i < codes.length; ++i) {
                    var code = codes[i];
                    var gid = new_gid(code);
                    var delta = gid - code;
                    if (last == null || delta !== diff) {
                        if (last) {
                            endCodes.push(last);
                        }
                        startCodes.push(code);
                        diff = delta;
                    }
                    last = code;
                }
                if (last) {
                    endCodes.push(last);
                }
                endCodes.push(65535);
                startCodes.push(65535);
                var segCount = startCodes.length;
                var segCountX2 = segCount * 2;
                var searchRange = 2 * Math.pow(2, Math.floor(Math.log(segCount) / Math.LN2));
                var entrySelector = Math.log(searchRange / 2) / Math.LN2;
                var rangeShift = segCountX2 - searchRange;
                var deltas = [];
                var rangeOffsets = [];
                var glyphIds = [];
                for (i = 0; i < segCount; ++i) {
                    var startCode = startCodes[i];
                    var endCode = endCodes[i];
                    if (startCode == 65535) {
                        deltas.push(0);
                        rangeOffsets.push(0);
                        break;
                    }
                    var startGlyph = new_gid(startCode);
                    if (startCode - startGlyph >= 32768) {
                        deltas.push(0);
                        rangeOffsets.push(2 * (glyphIds.length + segCount - i));
                        for (var j = startCode; j <= endCode; ++j) {
                            glyphIds.push(new_gid(j));
                        }
                    } else {
                        deltas.push(startGlyph - startCode);
                        rangeOffsets.push(0);
                    }
                }
                var out = BinaryStream();
                out.writeShort(3);
                out.writeShort(1);
                out.writeLong(12);
                out.writeShort(4);
                out.writeShort(16 + segCount * 8 + glyphIds.length * 2);
                out.writeShort(0);
                out.writeShort(segCountX2);
                out.writeShort(searchRange);
                out.writeShort(entrySelector);
                out.writeShort(rangeShift);
                endCodes.forEach(out.writeShort);
                out.writeShort(0);
                startCodes.forEach(out.writeShort);
                deltas.forEach(out.writeShort_);
                rangeOffsets.forEach(out.writeShort);
                glyphIds.forEach(out.writeShort);
                return out.get();
            }
            return deftable({
                parse: function (data) {
                    var self = this;
                    var offset = self.offset;
                    data.offset(offset);
                    self.codeMap = {};
                    self.version = data.readShort();
                    var tableCount = data.readShort();
                    self.tables = data.times(tableCount, function () {
                        return new CmapEntry(data, offset, self.codeMap);
                    });
                },
                render: function (ncid2ogid, ogid2ngid) {
                    var out = BinaryStream();
                    out.writeShort(0);
                    out.writeShort(1);
                    out.write(renderCharmap(ncid2ogid, ogid2ngid));
                    return out.get();
                }
            });
        }();
        var OS2Table = deftable({
            parse: function (data) {
                data.offset(this.offset);
                this.version = data.readShort();
                this.averageCharWidth = data.readShort_();
                this.weightClass = data.readShort();
                this.widthClass = data.readShort();
                this.type = data.readShort();
                this.ySubscriptXSize = data.readShort_();
                this.ySubscriptYSize = data.readShort_();
                this.ySubscriptXOffset = data.readShort_();
                this.ySubscriptYOffset = data.readShort_();
                this.ySuperscriptXSize = data.readShort_();
                this.ySuperscriptYSize = data.readShort_();
                this.ySuperscriptXOffset = data.readShort_();
                this.ySuperscriptYOffset = data.readShort_();
                this.yStrikeoutSize = data.readShort_();
                this.yStrikeoutPosition = data.readShort_();
                this.familyClass = data.readShort_();
                this.panose = data.times(10, data.readByte);
                this.charRange = data.times(4, data.readLong);
                this.vendorID = data.readString(4);
                this.selection = data.readShort();
                this.firstCharIndex = data.readShort();
                this.lastCharIndex = data.readShort();
                if (this.version > 0) {
                    this.ascent = data.readShort_();
                    this.descent = data.readShort_();
                    this.lineGap = data.readShort_();
                    this.winAscent = data.readShort();
                    this.winDescent = data.readShort();
                    this.codePageRange = data.times(2, data.readLong);
                    if (this.version > 1) {
                        this.xHeight = data.readShort();
                        this.capHeight = data.readShort();
                        this.defaultChar = data.readShort();
                        this.breakChar = data.readShort();
                        this.maxContext = data.readShort();
                    }
                }
            },
            render: function () {
                return this.raw();
            }
        });
        var subsetTag = 100000;
        function nextSubsetTag() {
            var ret = '', n = String(subsetTag);
            for (var i = 0; i < n.length; ++i) {
                ret += String.fromCharCode(n.charCodeAt(i) - 48 + 65);
            }
            ++subsetTag;
            return ret;
        }
        function Subfont(font) {
            this.font = font;
            this.subset = {};
            this.unicodes = {};
            this.ogid2ngid = { 0: 0 };
            this.ngid2ogid = { 0: 0 };
            this.ncid2ogid = {};
            this.next = this.firstChar = 1;
            this.nextGid = 1;
            this.psName = nextSubsetTag() + '+' + this.font.psName;
        }
        Subfont.prototype = {
            use: function (ch) {
                var self = this;
                if (typeof ch == 'string') {
                    return ucs2decode(ch).reduce(function (ret, code) {
                        return ret + String.fromCharCode(self.use(code));
                    }, '');
                }
                var code = self.unicodes[ch];
                if (!code) {
                    code = self.next++;
                    self.subset[code] = ch;
                    self.unicodes[ch] = code;
                    var old_gid = self.font.cmap.codeMap[ch];
                    if (old_gid) {
                        self.ncid2ogid[code] = old_gid;
                        if (self.ogid2ngid[old_gid] == null) {
                            var new_gid = self.nextGid++;
                            self.ogid2ngid[old_gid] = new_gid;
                            self.ngid2ogid[new_gid] = old_gid;
                        }
                    }
                }
                return code;
            },
            encodeText: function (text) {
                return this.use(text);
            },
            glyphIds: function () {
                return sortedKeys(this.ogid2ngid);
            },
            glyphsFor: function (glyphIds, result) {
                var this$1 = this;
                if (!result) {
                    result = {};
                }
                for (var i = 0; i < glyphIds.length; ++i) {
                    var id = glyphIds[i];
                    if (!result[id]) {
                        var glyph = result[id] = this$1.font.glyf.glyphFor(id);
                        if (glyph && glyph.compound) {
                            this$1.glyphsFor(glyph.glyphIds, result);
                        }
                    }
                }
                return result;
            },
            render: function () {
                var this$1 = this;
                var glyphs = this.glyphsFor(this.glyphIds());
                for (var old_gid in glyphs) {
                    if (hasOwnProperty$1(glyphs, old_gid)) {
                        old_gid = parseInt(old_gid, 10);
                        if (this$1.ogid2ngid[old_gid] == null) {
                            var new_gid = this$1.nextGid++;
                            this$1.ogid2ngid[old_gid] = new_gid;
                            this$1.ngid2ogid[new_gid] = old_gid;
                        }
                    }
                }
                var new_gid_ids = sortedKeys(this.ngid2ogid);
                var old_gid_ids = new_gid_ids.map(function (id) {
                    return this.ngid2ogid[id];
                }, this);
                var font = this.font;
                var glyf = font.glyf.render(glyphs, old_gid_ids, this.ogid2ngid);
                var loca = font.loca.render(glyf.offsets);
                this.lastChar = this.next - 1;
                var tables = {
                    'cmap': CmapTable.render(this.ncid2ogid, this.ogid2ngid),
                    'glyf': glyf.table,
                    'loca': loca.table,
                    'hmtx': font.hmtx.render(old_gid_ids),
                    'hhea': font.hhea.render(old_gid_ids),
                    'maxp': font.maxp.render(old_gid_ids),
                    'post': font.post.render(old_gid_ids),
                    'name': font.name.render(this.psName),
                    'head': font.head.render(loca.format),
                    'OS/2': font.os2.render()
                };
                return this.font.directory.render(tables);
            },
            cidToGidMap: function () {
                var this$1 = this;
                var out = BinaryStream(), len = 0;
                for (var cid = this.firstChar; cid < this.next; ++cid) {
                    while (len < cid) {
                        out.writeShort(0);
                        len++;
                    }
                    var old_gid = this$1.ncid2ogid[cid];
                    if (old_gid) {
                        var new_gid = this$1.ogid2ngid[old_gid];
                        out.writeShort(new_gid);
                    } else {
                        out.writeShort(0);
                    }
                    len++;
                }
                return out.get();
            }
        };
        function TTFFont(rawData, name) {
            var self = this;
            var data = self.contents = BinaryStream(rawData);
            if (data.readString(4) == 'ttcf') {
                var offset;
                var parse = function () {
                    data.offset(offset);
                    self.parse();
                };
                if (!name) {
                    throw new Error('Must specify a name for TTC files');
                }
                data.readLong();
                var numFonts = data.readLong();
                for (var i = 0; i < numFonts; ++i) {
                    offset = data.readLong();
                    data.saveExcursion(parse);
                    if (self.psName == name) {
                        return;
                    }
                }
                throw new Error('Font ' + name + ' not found in collection');
            } else {
                data.offset(0);
                self.parse();
            }
        }
        TTFFont.prototype = {
            parse: function () {
                var dir = this.directory = new Directory(this.contents);
                this.head = dir.readTable('head', HeadTable);
                this.loca = dir.readTable('loca', LocaTable);
                this.hhea = dir.readTable('hhea', HheaTable);
                this.maxp = dir.readTable('maxp', MaxpTable);
                this.hmtx = dir.readTable('hmtx', HmtxTable);
                this.glyf = dir.readTable('glyf', GlyfTable);
                this.name = dir.readTable('name', NameTable);
                this.post = dir.readTable('post', PostTable);
                this.cmap = dir.readTable('cmap', CmapTable);
                this.os2 = dir.readTable('OS/2', OS2Table);
                this.psName = this.name.postscriptName;
                this.ascent = this.os2.ascent || this.hhea.ascent;
                this.descent = this.os2.descent || this.hhea.descent;
                this.lineGap = this.os2.lineGap || this.hhea.lineGap;
                this.scale = 1000 / this.head.unitsPerEm;
            },
            widthOfGlyph: function (glyph) {
                return this.hmtx.forGlyph(glyph).advance * this.scale;
            },
            makeSubset: function () {
                return new Subfont(this);
            }
        };
        var browser = kendo.support.browser;
        var HAS_TYPED_ARRAYS = typeof Uint8Array !== 'undefined';
        var NL = '\n';
        var RESOURCE_COUNTER = 0;
        var PAPER_SIZE = {
            a0: [
                2383.94,
                3370.39
            ],
            a1: [
                1683.78,
                2383.94
            ],
            a2: [
                1190.55,
                1683.78
            ],
            a3: [
                841.89,
                1190.55
            ],
            a4: [
                595.28,
                841.89
            ],
            a5: [
                419.53,
                595.28
            ],
            a6: [
                297.64,
                419.53
            ],
            a7: [
                209.76,
                297.64
            ],
            a8: [
                147.4,
                209.76
            ],
            a9: [
                104.88,
                147.4
            ],
            a10: [
                73.7,
                104.88
            ],
            b0: [
                2834.65,
                4008.19
            ],
            b1: [
                2004.09,
                2834.65
            ],
            b2: [
                1417.32,
                2004.09
            ],
            b3: [
                1000.63,
                1417.32
            ],
            b4: [
                708.66,
                1000.63
            ],
            b5: [
                498.9,
                708.66
            ],
            b6: [
                354.33,
                498.9
            ],
            b7: [
                249.45,
                354.33
            ],
            b8: [
                175.75,
                249.45
            ],
            b9: [
                124.72,
                175.75
            ],
            b10: [
                87.87,
                124.72
            ],
            c0: [
                2599.37,
                3676.54
            ],
            c1: [
                1836.85,
                2599.37
            ],
            c2: [
                1298.27,
                1836.85
            ],
            c3: [
                918.43,
                1298.27
            ],
            c4: [
                649.13,
                918.43
            ],
            c5: [
                459.21,
                649.13
            ],
            c6: [
                323.15,
                459.21
            ],
            c7: [
                229.61,
                323.15
            ],
            c8: [
                161.57,
                229.61
            ],
            c9: [
                113.39,
                161.57
            ],
            c10: [
                79.37,
                113.39
            ],
            executive: [
                521.86,
                756
            ],
            folio: [
                612,
                936
            ],
            legal: [
                612,
                1008
            ],
            letter: [
                612,
                792
            ],
            tabloid: [
                792,
                1224
            ]
        };
        function makeOutput() {
            var indentLevel = 0, output = BinaryStream();
            function out() {
                var arguments$1 = arguments;
                for (var i = 0; i < arguments.length; ++i) {
                    var x = arguments$1[i];
                    if (x === undefined) {
                        throw new Error('Cannot output undefined to PDF');
                    } else if (x instanceof PDFValue) {
                        x.beforeRender(out);
                        x.render(out);
                    } else if (isArray(x)) {
                        renderArray(x, out);
                    } else if (isDate(x)) {
                        renderDate(x, out);
                    } else if (typeof x == 'number') {
                        if (isNaN(x)) {
                            throw new Error('Cannot output NaN to PDF');
                        }
                        var num = x.toFixed(7);
                        if (num.indexOf('.') >= 0) {
                            num = num.replace(/\.?0+$/, '');
                        }
                        if (num == '-0') {
                            num = '0';
                        }
                        output.writeString(num);
                    } else if (/string|boolean/.test(typeof x)) {
                        output.writeString(String(x));
                    } else if (typeof x.get == 'function') {
                        output.write(x.get());
                    } else if (typeof x == 'object') {
                        if (!x) {
                            output.writeString('null');
                        } else {
                            out(new PDFDictionary(x));
                        }
                    }
                }
            }
            out.writeData = function (data) {
                output.write(data);
            };
            out.withIndent = function (f) {
                ++indentLevel;
                f(out);
                --indentLevel;
            };
            out.indent = function () {
                out(NL, pad('', indentLevel * 2, '  '));
                out.apply(null, arguments);
            };
            out.offset = function () {
                return output.offset();
            };
            out.toString = function () {
                throw new Error('FIX CALLER');
            };
            out.get = function () {
                return output.get();
            };
            out.stream = function () {
                return output;
            };
            return out;
        }
        function wrapObject(value, id) {
            var beforeRender = value.beforeRender;
            var renderValue = value.render;
            value.beforeRender = function () {
            };
            value.render = function (out) {
                out(id, ' 0 R');
            };
            value.renderFull = function (out) {
                value._offset = out.offset();
                out(id, ' 0 obj ');
                beforeRender.call(value, out);
                renderValue.call(value, out);
                out(' endobj');
            };
        }
        function getPaperOptions(getOption) {
            if (typeof getOption != 'function') {
                var options = getOption;
                getOption = function (key, def) {
                    return key in options ? options[key] : def;
                };
            }
            var paperSize = getOption('paperSize', PAPER_SIZE.a4);
            if (!paperSize) {
                return {};
            }
            if (typeof paperSize == 'string') {
                paperSize = PAPER_SIZE[paperSize.toLowerCase()];
                if (paperSize == null) {
                    throw new Error('Unknown paper size');
                }
            }
            paperSize[0] = unitsToPoints(paperSize[0]);
            paperSize[1] = unitsToPoints(paperSize[1]);
            if (getOption('landscape', false)) {
                paperSize = [
                    Math.max(paperSize[0], paperSize[1]),
                    Math.min(paperSize[0], paperSize[1])
                ];
            }
            var margin = getOption('margin');
            if (margin) {
                if (typeof margin == 'string' || typeof margin == 'number') {
                    margin = unitsToPoints(margin, 0);
                    margin = {
                        left: margin,
                        top: margin,
                        right: margin,
                        bottom: margin
                    };
                } else {
                    margin = {
                        left: unitsToPoints(margin.left, 0),
                        top: unitsToPoints(margin.top, 0),
                        right: unitsToPoints(margin.right, 0),
                        bottom: unitsToPoints(margin.bottom, 0)
                    };
                }
                if (getOption('addMargin')) {
                    paperSize[0] += margin.left + margin.right;
                    paperSize[1] += margin.top + margin.bottom;
                }
            }
            return {
                paperSize: paperSize,
                margin: margin
            };
        }
        function PDFDocument(options) {
            var self = this;
            var out = makeOutput();
            var objcount = 0;
            var objects = [];
            function getOption(name, defval) {
                return options && options[name] != null ? options[name] : defval;
            }
            self.getOption = getOption;
            self.attach = function (value) {
                if (objects.indexOf(value) < 0) {
                    wrapObject(value, ++objcount);
                    objects.push(value);
                }
                return value;
            };
            self.pages = [];
            self.FONTS = {};
            self.IMAGES = {};
            self.GRAD_COL_FUNCTIONS = {};
            self.GRAD_OPC_FUNCTIONS = {};
            self.GRAD_COL = {};
            self.GRAD_OPC = {};
            var catalog = self.attach(new PDFCatalog());
            var pageTree = self.attach(new PDFPageTree());
            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')),
                        Title: new PDFString(getOption('title', '')),
                        Author: new PDFString(getOption('author', '')),
                        Subject: new PDFString(getOption('subject', '')),
                        Keywords: new PDFString(getOption('keywords', '')),
                        Creator: new PDFString(getOption('creator', 'Kendo UI PDF Generator')),
                        CreationDate: getOption('date', new Date())
                    })
                }), 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 window.VBArray(req.responseBody).toArray());
                    }
                } else {
                    error();
                }
            };
            req.onerror = error;
            req.send(null);
        }
        function loadFont(url, cont) {
            var font = FONT_CACHE[url];
            if (font) {
                cont(font);
            } else {
                loadBinary(url, function (data) {
                    if (data == null) {
                        throw new Error('Cannot load font from ' + url);
                    } else {
                        var font = new TTFFont(data);
                        FONT_CACHE[url] = font;
                        cont(font);
                    }
                });
            }
        }
        var IMAGE_CACHE = {};
        function 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 && !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(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) {
                    _onerror();
                    return;
                } finally {
                    if (bloburl) {
                        URL.revokeObjectURL(bloburl);
                    }
                }
                var hasAlpha = false, rgb = BinaryStream(), alpha = BinaryStream();
                var rawbytes = imgdata.data;
                var i = 0;
                while (i < rawbytes.length) {
                    rgb.writeByte(rawbytes[i++]);
                    rgb.writeByte(rawbytes[i++]);
                    rgb.writeByte(rawbytes[i++]);
                    var a = rawbytes[i++];
                    if (a < 255) {
                        hasAlpha = true;
                    }
                    alpha.writeByte(a);
                }
                if (hasAlpha) {
                    img = new PDFRawImage(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);
                    img = new PDFJpegImage(stream);
                }
                cont(IMAGE_CACHE[url] = img);
            }
        }
        function manyLoader(loadOne) {
            return function (urls, callback) {
                var n = urls.length, i = n;
                if (n === 0) {
                    return callback();
                }
                function next() {
                    if (--n === 0) {
                        callback();
                    }
                }
                while (i-- > 0) {
                    loadOne(urls[i], next);
                }
            };
        }
        var loadFonts = manyLoader(loadFont);
        var loadImages = 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(String(n), len, '0');
        }
        function hasOwnProperty(obj, key) {
            return Object.prototype.hasOwnProperty.call(obj, key);
        }
        var isArray = Array.isArray || function (obj) {
            return obj instanceof Array;
        };
        function isDate(obj) {
            return obj instanceof Date;
        }
        function renderArray(a, out) {
            out('[');
            if (a.length > 0) {
                out.withIndent(function () {
                    for (var i = 0; i < a.length; ++i) {
                        if (i > 0 && i % 8 === 0) {
                            out.indent(a[i]);
                        } else {
                            out(' ', a[i]);
                        }
                    }
                });
            }
            out(' ]');
        }
        function renderDate(date, out) {
            out('(D:', zeropad(date.getUTCFullYear(), 4), zeropad(date.getUTCMonth() + 1, 2), zeropad(date.getUTCDate(), 2), zeropad(date.getUTCHours(), 2), zeropad(date.getUTCMinutes(), 2), zeropad(date.getUTCSeconds(), 2), 'Z)');
        }
        function mm2pt(mm) {
            return mm * (72 / 25.4);
        }
        function cm2pt(cm) {
            return mm2pt(cm * 10);
        }
        function in2pt(inch) {
            return inch * 72;
        }
        function unitsToPoints(x, def) {
            if (typeof x == 'number') {
                return x;
            }
            if (typeof x == 'string') {
                var m;
                m = /^\s*([0-9.]+)\s*(mm|cm|in|pt)\s*$/.exec(x);
                if (m) {
                    var num = parseFloat(m[1]);
                    if (!isNaN(num)) {
                        if (m[2] == 'pt') {
                            return num;
                        }
                        return {
                            'mm': mm2pt,
                            'cm': cm2pt,
                            'in': in2pt
                        }[m[2]](num);
                    }
                }
            }
            if (def != null) {
                return def;
            }
            throw new Error('Can\'t parse unit: ' + x);
        }
        function PDFValue() {
        }
        PDFValue.prototype.beforeRender = function () {
        };
        function defclass(Ctor, proto, Base) {
            if (!Base) {
                Base = PDFValue;
            }
            Ctor.prototype = new Base();
            for (var i in proto) {
                if (hasOwnProperty(proto, i)) {
                    Ctor.prototype[i] = proto[i];
                }
            }
            return Ctor;
        }
        var PDFString = defclass(function PDFString(value) {
            this.value = value;
        }, {
            render: function (out) {
                var txt = '', val = this.value;
                for (var i = 0; i < val.length; ++i) {
                    txt += String.fromCharCode(val.charCodeAt(i) & 255);
                }
                out('(', txt.replace(/([\(\)\\])/g, '\\$1'), ')');
            },
            toString: function () {
                return this.value;
            }
        });
        var PDFHexString = defclass(function PDFHexString(value) {
            this.value = value;
        }, {
            render: function (out) {
                var this$1 = this;
                out('<');
                for (var i = 0; i < this.value.length; ++i) {
                    out(zeropad(this$1.value.charCodeAt(i).toString(16), 4));
                }
                out('>');
            }
        }, PDFString);
        var PDFName = defclass(function PDFName(name) {
            this.name = name;
        }, {
            render: function (out) {
                out('/' + this.escape());
            },
            escape: function () {
                return this.name.replace(/[^\x21-\x7E]/g, function (c) {
                    return '#' + zeropad(c.charCodeAt(0).toString(16), 2);
                });
            },
            toString: function () {
                return this.name;
            }
        });
        var PDFName_cache = {};
        PDFName.get = _;
        function _(name) {
            if (hasOwnProperty(PDFName_cache, name)) {
                return PDFName_cache[name];
            }
            return PDFName_cache[name] = new PDFName(name);
        }
        var PDFDictionary = defclass(function PDFDictionary(props) {
            this.props = props;
        }, {
            render: function (out) {
                var props = this.props, empty = true;
                out('<<');
                out.withIndent(function () {
                    for (var i in props) {
                        if (hasOwnProperty(props, i) && !/^_/.test(i)) {
                            empty = false;
                            out.indent(_(i), ' ', props[i]);
                        }
                    }
                });
                if (!empty) {
                    out.indent();
                }
                out('>>');
            }
        });
        var PDFStream = defclass(function PDFStream(data, props, compress) {
            if (typeof data == 'string') {
                var tmp = BinaryStream();
                tmp.write(data);
                data = tmp;
            }
            this.data = data;
            this.props = props || {};
            this.compress = compress;
        }, {
            render: function (out) {
                var data = this.data.get(), props = this.props;
                if (this.compress && 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);
        var SOF_CODES = [
            192,
            193,
            194,
            195,
            197,
            198,
            199,
            201,
            202,
            203,
            205,
            206,
            207
        ];
        function PDFJpegImage(data) {
            data.offset(0);
            var width, height, colorSpace, bitsPerComponent;
            var soi = data.readShort();
            if (soi != 65496) {
                throw new Error('Invalid JPEG image');
            }
            while (!data.eof()) {
                var ff = data.readByte();
                if (ff != 255) {
                    throw new Error('Invalid JPEG image');
                }
                var marker = data.readByte();
                var length = data.readShort();
                if (SOF_CODES.indexOf(marker) >= 0) {
                    bitsPerComponent = data.readByte();
                    height = data.readShort();
                    width = data.readShort();
                    colorSpace = data.readByte();
                    break;
                }
                data.skip(length - 2);
            }
            if (colorSpace == null) {
                throw new Error('Invalid JPEG image');
            }
            var props = {
                Type: _('XObject'),
                Subtype: _('Image'),
                Width: width,
                Height: height,
                BitsPerComponent: bitsPerComponent,
                Filter: _('DCTDecode')
            };
            switch (colorSpace) {
            case 1:
                props.ColorSpace = _('DeviceGray');
                break;
            case 3:
                props.ColorSpace = _('DeviceRGB');
                break;
            case 4:
                props.ColorSpace = _('DeviceCMYK');
                props.Decode = [
                    1,
                    0,
                    1,
                    0,
                    1,
                    0,
                    1,
                    0
                ];
                break;
            }
            this.asStream = function () {
                data.offset(0);
                var stream = new PDFStream(data, props);
                stream._resourceName = _('I' + ++RESOURCE_COUNTER);
                return stream;
            };
        }
        function PDFRawImage(width, height, rgb, alpha) {
            this.asStream = function (pdf) {
                var mask = new PDFStream(alpha, {
                    Type: _('XObject'),
                    Subtype: _('Image'),
                    Width: width,
                    Height: height,
                    BitsPerComponent: 8,
                    ColorSpace: _('DeviceGray')
                }, true);
                var stream = new PDFStream(rgb, {
                    Type: _('XObject'),
                    Subtype: _('Image'),
                    Width: width,
                    Height: height,
                    BitsPerComponent: 8,
                    ColorSpace: _('DeviceRGB'),
                    SMask: pdf.attach(mask)
                }, true);
                stream._resourceName = _('I' + ++RESOURCE_COUNTER);
                return stream;
            };
        }
        var PDFStandardFont = defclass(function PDFStandardFont(name) {
            this.props = {
                Type: _('Font'),
                Subtype: _('Type1'),
                BaseFont: _(name)
            };
            this._resourceName = _('F' + ++RESOURCE_COUNTER);
        }, {
            encodeText: function (str) {
                return new PDFString(String(str));
            }
        }, PDFDictionary);
        var PDFFont = defclass(function PDFFont(pdf, font, props) {
            props = this.props = props || {};
            props.Type = _('Font');
            props.Subtype = _('Type0');
            props.Encoding = _('Identity-H');
            this._pdf = pdf;
            this._font = font;
            this._sub = font.makeSubset();
            this._resourceName = _('F' + ++RESOURCE_COUNTER);
            var head = font.head;
            this.name = font.psName;
            var scale = this.scale = font.scale;
            this.bbox = [
                head.xMin * scale,
                head.yMin * scale,
                head.xMax * scale,
                head.yMax * scale
            ];
            this.italicAngle = font.post.italicAngle;
            this.ascent = font.ascent * scale;
            this.descent = font.descent * scale;
            this.lineGap = font.lineGap * scale;
            this.capHeight = font.os2.capHeight || this.ascent;
            this.xHeight = font.os2.xHeight || 0;
            this.stemV = 0;
            this.familyClass = (font.os2.familyClass || 0) >> 8;
            this.isSerif = this.familyClass >= 1 && this.familyClass <= 7;
            this.isScript = this.familyClass == 10;
            this.flags = (font.post.isFixedPitch ? 1 : 0) | (this.isSerif ? 1 << 1 : 0) | (this.isScript ? 1 << 3 : 0) | (this.italicAngle !== 0 ? 1 << 6 : 0) | 1 << 5;
        }, {
            encodeText: function (text) {
                return new PDFHexString(this._sub.encodeText(String(text)));
            },
            getTextWidth: function (fontSize, text) {
                var this$1 = this;
                var width = 0, codeMap = this._font.cmap.codeMap;
                for (var i = 0; i < text.length; ++i) {
                    var glyphId = codeMap[text.charCodeAt(i)];
                    width += this$1._font.widthOfGlyph(glyphId || 0);
                }
                return width * fontSize / 1000;
            },
            beforeRender: function () {
                var self = this;
                var sub = self._sub;
                var data = sub.render();
                var fontStream = new PDFStream(BinaryStream(data), { Length1: data.length }, true);
                var descriptor = self._pdf.attach(new PDFDictionary({
                    Type: _('FontDescriptor'),
                    FontName: _(self._sub.psName),
                    FontBBox: self.bbox,
                    Flags: self.flags,
                    StemV: self.stemV,
                    ItalicAngle: self.italicAngle,
                    Ascent: self.ascent,
                    Descent: self.descent,
                    CapHeight: self.capHeight,
                    XHeight: self.xHeight,
                    FontFile2: self._pdf.attach(fontStream)
                }));
                var cmap = sub.ncid2ogid;
                var firstChar = sub.firstChar;
                var lastChar = sub.lastChar;
                var charWidths = [];
                (function loop(i, chunk) {
                    if (i <= lastChar) {
                        var gid = cmap[i];
                        if (gid == null) {
                            loop(i + 1);
                        } else {
                            if (!chunk) {
                                charWidths.push(i, chunk = []);
                            }
                            chunk.push(self._font.widthOfGlyph(gid));
                            loop(i + 1, chunk);
                        }
                    }
                }(firstChar));
                var descendant = new PDFDictionary({
                    Type: _('Font'),
                    Subtype: _('CIDFontType2'),
                    BaseFont: _(self._sub.psName),
                    CIDSystemInfo: new PDFDictionary({
                        Registry: new PDFString('Adobe'),
                        Ordering: new PDFString('Identity'),
                        Supplement: 0
                    }),
                    FontDescriptor: descriptor,
                    FirstChar: firstChar,
                    LastChar: lastChar,
                    DW: Math.round(self._font.widthOfGlyph(0)),
                    W: charWidths,
                    CIDToGIDMap: self._pdf.attach(self._makeCidToGidMap())
                });
                var dict = self.props;
                dict.BaseFont = _(self._sub.psName);
                dict.DescendantFonts = [self._pdf.attach(descendant)];
                var unimap = new PDFToUnicodeCmap(firstChar, lastChar, sub.subset);
                var unimapStream = new PDFStream(makeOutput(), null, true);
                unimapStream.data(unimap);
                dict.ToUnicode = self._pdf.attach(unimapStream);
            },
            _makeCidToGidMap: function () {
                return new PDFStream(BinaryStream(this._sub.cidToGidMap()), null, true);
            }
        }, PDFDictionary);
        var PDFToUnicodeCmap = defclass(function PDFUnicodeCMap(firstChar, lastChar, map) {
            this.firstChar = firstChar;
            this.lastChar = lastChar;
            this.map = map;
        }, {
            render: function (out) {
                out.indent('/CIDInit /ProcSet findresource begin');
                out.indent('12 dict begin');
                out.indent('begincmap');
                out.indent('/CIDSystemInfo <<');
                out.indent('  /Registry (Adobe)');
                out.indent('  /Ordering (UCS)');
                out.indent('  /Supplement 0');
                out.indent('>> def');
                out.indent('/CMapName /Adobe-Identity-UCS def');
                out.indent('/CMapType 2 def');
                out.indent('1 begincodespacerange');
                out.indent('  <0000><ffff>');
                out.indent('endcodespacerange');
                var self = this;
                out.indent(self.lastChar - self.firstChar + 1, ' beginbfchar');
                out.withIndent(function () {
                    for (var code = self.firstChar; code <= self.lastChar; ++code) {
                        var unicode = self.map[code];
                        var str = ucs2encode([unicode]);
                        out.indent('<', zeropad(code.toString(16), 4), '>', '<');
                        for (var i = 0; i < str.length; ++i) {
                            out(zeropad(str.charCodeAt(i).toString(16), 4));
                        }
                        out('>');
                    }
                });
                out.indent('endbfchar');
                out.indent('endcmap');
                out.indent('CMapName currentdict /CMap defineresource pop');
                out.indent('end');
                out.indent('end');
            }
        });
        function makeHash(a) {
            return a.map(function (x) {
                return isArray(x) ? makeHash(x) : typeof x == 'number' ? (Math.round(x * 1000) / 1000).toFixed(3) : x;
            }).join(' ');
        }
        function cacheColorGradientFunction(pdf, r1, g1, b1, r2, g2, b2) {
            var hash = makeHash([
                r1,
                g1,
                b1,
                r2,
                g2,
                b2
            ]);
            var func = pdf.GRAD_COL_FUNCTIONS[hash];
            if (!func) {
                func = pdf.GRAD_COL_FUNCTIONS[hash] = pdf.attach(new PDFDictionary({
                    FunctionType: 2,
                    Domain: [
                        0,
                        1
                    ],
                    Range: [
                        0,
                        1,
                        0,
                        1,
                        0,
                        1
                    ],
                    N: 1,
                    C0: [
                        r1,
                        g1,
                        b1
                    ],
                    C1: [
                        r2,
                        g2,
                        b2
                    ]
                }));
            }
            return func;
        }
        function cacheOpacityGradientFunction(pdf, a1, a2) {
            var hash = makeHash([
                a1,
                a2
            ]);
            var func = pdf.GRAD_OPC_FUNCTIONS[hash];
            if (!func) {
                func = pdf.GRAD_OPC_FUNCTIONS[hash] = pdf.attach(new PDFDictionary({
                    FunctionType: 2,
                    Domain: [
                        0,
                        1
                    ],
                    Range: [
                        0,
                        1
                    ],
                    N: 1,
                    C0: [a1],
                    C1: [a2]
                }));
            }
            return func;
        }
        function makeGradientFunctions(pdf, stops) {
            var hasAlpha = false;
            var opacities = [];
            var colors = [];
            var offsets = [];
            var encode = [];
            var i, prev, cur, prevColor, curColor;
            for (i = 1; i < stops.length; ++i) {
                prev = stops[i - 1];
                cur = stops[i];
                prevColor = prev.color;
                curColor = cur.color;
                colors.push(cacheColorGradientFunction(pdf, prevColor.r, prevColor.g, prevColor.b, curColor.r, curColor.g, curColor.b));
                if (prevColor.a < 1 || curColor.a < 1) {
                    hasAlpha = true;
                }
                offsets.push(cur.offset);
                encode.push(0, 1);
            }
            if (hasAlpha) {
                for (i = 1; i < stops.length; ++i) {
                    prev = stops[i - 1];
                    cur = stops[i];
                    prevColor = prev.color;
                    curColor = cur.color;
                    opacities.push(cacheOpacityGradientFunction(pdf, prevColor.a, curColor.a));
                }
            }
            offsets.pop();
            return {
                hasAlpha: hasAlpha,
                colors: assemble(colors),
                opacities: hasAlpha ? assemble(opacities) : null
            };
            function assemble(funcs) {
                if (funcs.length == 1) {
                    return funcs[0];
                }
                return {
                    FunctionType: 3,
                    Functions: funcs,
                    Domain: [
                        0,
                        1
                    ],
                    Bounds: offsets,
                    Encode: encode
                };
            }
        }
        function cacheColorGradient(pdf, isRadial, stops, coords, funcs, box) {
            var shading, hash;
            if (!box) {
                var a = [isRadial].concat(coords);
                stops.forEach(function (x) {
                    a.push(x.offset, x.color.r, x.color.g, x.color.b);
                });
                hash = makeHash(a);
                shading = pdf.GRAD_COL[hash];
            }
            if (!shading) {
                shading = new PDFDictionary({
                    Type: _('Shading'),
                    ShadingType: isRadial ? 3 : 2,
                    ColorSpace: _('DeviceRGB'),
                    Coords: coords,
                    Domain: [
                        0,
                        1
                    ],
                    Function: funcs,
                    Extend: [
                        true,
                        true
                    ]
                });
                pdf.attach(shading);
                shading._resourceName = 'S' + ++RESOURCE_COUNTER;
                if (hash) {
                    pdf.GRAD_COL[hash] = shading;
                }
            }
            return shading;
        }
        function cacheOpacityGradient(pdf, isRadial, stops, coords, funcs, box) {
            var opacity, hash;
            if (!box) {
                var a = [isRadial].concat(coords);
                stops.forEach(function (x) {
                    a.push(x.offset, x.color.a);
                });
                hash = makeHash(a);
                opacity = pdf.GRAD_OPC[hash];
            }
            if (!opacity) {
                opacity = new PDFDictionary({
                    Type: _('ExtGState'),
                    AIS: false,
                    CA: 1,
                    ca: 1,
                    SMask: {
                        Type: _('Mask'),
                        S: _('Luminosity'),
                        G: pdf.attach(new PDFStream('/a0 gs /s0 sh', {
                            Type: _('XObject'),
                            Subtype: _('Form'),
                            FormType: 1,
                            BBox: box ? [
                                box.left,
                                box.top + box.height,
                                box.left + box.width,
                                box.top
                            ] : [
                                0,
                                1,
                                1,
                                0
                            ],
                            Group: {
                                Type: _('Group'),
                                S: _('Transparency'),
                                CS: _('DeviceGray'),
                                I: true
                            },
                            Resources: {
                                ExtGState: {
                                    a0: {
                                        CA: 1,
                                        ca: 1
                                    }
                                },
                                Shading: {
                                    s0: {
                                        ColorSpace: _('DeviceGray'),
                                        Coords: coords,
                                        Domain: [
                                            0,
                                            1
                                        ],
                                        ShadingType: isRadial ? 3 : 2,
                                        Function: funcs,
                                        Extend: [
                                            true,
                                            true
                                        ]
                                    }
                                }
                            }
                        }))
                    }
                });
                pdf.attach(opacity);
                opacity._resourceName = 'O' + ++RESOURCE_COUNTER;
                if (hash) {
                    pdf.GRAD_OPC[hash] = opacity;
                }
            }
            return opacity;
        }
        function cacheGradient(pdf, gradient, box) {
            var isRadial = gradient.type == 'radial';
            var funcs = makeGradientFunctions(pdf, gradient.stops);
            var coords = isRadial ? [
                gradient.start.x,
                gradient.start.y,
                gradient.start.r,
                gradient.end.x,
                gradient.end.y,
                gradient.end.r
            ] : [
                gradient.start.x,
                gradient.start.y,
                gradient.end.x,
                gradient.end.y
            ];
            var shading = cacheColorGradient(pdf, isRadial, gradient.stops, coords, funcs.colors, gradient.userSpace && box);
            var opacity = funcs.hasAlpha ? cacheOpacityGradient(pdf, isRadial, gradient.stops, coords, funcs.opacities, gradient.userSpace && box) : null;
            return {
                hasAlpha: funcs.hasAlpha,
                shading: shading,
                opacity: opacity
            };
        }
        var PDFPage = defclass(function PDFPage(pdf, props) {
            this._pdf = pdf;
            this._rcount = 0;
            this._textMode = false;
            this._fontResources = {};
            this._gsResources = {};
            this._xResources = {};
            this._patResources = {};
            this._shResources = {};
            this._opacity = 1;
            this._matrix = [
                1,
                0,
                0,
                1,
                0,
                0
            ];
            this._annotations = [];
            this._font = null;
            this._fontSize = null;
            this._contextStack = [];
            props = this.props = props || {};
            props.Type = _('Page');
            props.ProcSet = [
                _('PDF'),
                _('Text'),
                _('ImageB'),
                _('ImageC'),
                _('ImageI')
            ];
            props.Resources = new PDFDictionary({
                Font: new PDFDictionary(this._fontResources),
                ExtGState: new PDFDictionary(this._gsResources),
                XObject: new PDFDictionary(this._xResources),
                Pattern: new PDFDictionary(this._patResources),
                Shading: new PDFDictionary(this._shResources)
            });
            props.Annots = this._annotations;
        }, {
            _out: function () {
                this._content.data.apply(null, arguments);
            },
            transform: function (a, b, c, d, e, f) {
                if (!isIdentityMatrix(arguments)) {
                    this._matrix = mmul(arguments, this._matrix);
                    this._out(a, ' ', b, ' ', c, ' ', d, ' ', e, ' ', f, ' cm');
                    this._out(NL);
                }
            },
            translate: function (dx, dy) {
                this.transform(1, 0, 0, 1, dx, dy);
            },
            scale: function (sx, sy) {
                this.transform(sx, 0, 0, sy, 0, 0);
            },
            rotate: function (angle) {
                var cos = Math.cos(angle), sin = Math.sin(angle);
                this.transform(cos, sin, -sin, cos, 0, 0);
            },
            beginText: function () {
                this._textMode = true;
                this._out('BT', NL);
            },
            endText: function () {
                this._textMode = false;
                this._out('ET', NL);
            },
            _requireTextMode: function () {
                if (!this._textMode) {
                    throw new Error('Text mode required; call page.beginText() first');
                }
            },
            _requireFont: function () {
                if (!this._font) {
                    throw new Error('No font selected; call page.setFont() first');
                }
            },
            setFont: function (font, size) {
                this._requireTextMode();
                if (font == null) {
                    font = this._font;
                } else if (!(font instanceof PDFFont)) {
                    font = this._pdf.getFont(font);
                }
                if (size == null) {
                    size = this._fontSize;
                }
                this._fontResources[font._resourceName] = font;
                this._font = font;
                this._fontSize = size;
                this._out(font._resourceName, ' ', size, ' Tf', NL);
            },
            setTextLeading: function (size) {
                this._requireTextMode();
                this._out(size, ' TL', NL);
            },
            setTextRenderingMode: function (mode) {
                this._requireTextMode();
                this._out(mode, ' Tr', NL);
            },
            showText: function (text, requestedWidth) {
                this._requireFont();
                if (text.length > 1 && requestedWidth && this._font instanceof PDFFont) {
                    var outputWidth = this._font.getTextWidth(this._fontSize, text);
                    var scale = requestedWidth / outputWidth * 100;
                    this._out(scale, ' Tz ');
                }
                this._out(this._font.encodeText(text), ' Tj', NL);
            },
            showTextNL: function (text) {
                this._requireFont();
                this._out(this._font.encodeText(text), ' \'', NL);
            },
            addLink: function (uri, box) {
                var ll = this._toPage({
                    x: box.left,
                    y: box.bottom
                });
                var ur = this._toPage({
                    x: box.right,
                    y: box.top
                });
                this._annotations.push(new PDFDictionary({
                    Type: _('Annot'),
                    Subtype: _('Link'),
                    Rect: [
                        ll.x,
                        ll.y,
                        ur.x,
                        ur.y
                    ],
                    Border: [
                        0,
                        0,
                        0
                    ],
                    A: new PDFDictionary({
                        Type: _('Action'),
                        S: _('URI'),
                        URI: new PDFString(uri)
                    })
                }));
            },
            setStrokeColor: function (r, g, b) {
                this._out(r, ' ', g, ' ', b, ' RG', NL);
            },
            setOpacity: function (opacity) {
                this.setFillOpacity(opacity);
                this.setStrokeOpacity(opacity);
                this._opacity *= opacity;
            },
            setStrokeOpacity: function (opacity) {
                if (opacity < 1) {
                    var gs = this._pdf.getOpacityGS(this._opacity * opacity, true);
                    this._gsResources[gs._resourceName] = gs;
                    this._out(gs._resourceName, ' gs', NL);
                }
            },
            setFillColor: function (r, g, b) {
                this._out(r, ' ', g, ' ', b, ' rg', NL);
            },
            setFillOpacity: function (opacity) {
                if (opacity < 1) {
                    var gs = this._pdf.getOpacityGS(this._opacity * opacity, false);
                    this._gsResources[gs._resourceName] = gs;
                    this._out(gs._resourceName, ' gs', NL);
                }
            },
            gradient: function (gradient, box) {
                this.save();
                this.rect(box.left, box.top, box.width, box.height);
                this.clip();
                if (!gradient.userSpace) {
                    this.transform(box.width, 0, 0, box.height, box.left, box.top);
                }
                var g = cacheGradient(this._pdf, gradient, box);
                var sname = g.shading._resourceName, oname;
                this._shResources[sname] = g.shading;
                if (g.hasAlpha) {
                    oname = g.opacity._resourceName;
                    this._gsResources[oname] = g.opacity;
                    this._out('/' + oname + ' gs ');
                }
                this._out('/' + sname + ' sh', NL);
                this.restore();
            },
            setDashPattern: function (dashArray, dashPhase) {
                this._out(dashArray, ' ', dashPhase, ' d', NL);
            },
            setLineWidth: function (width) {
                this._out(width, ' w', NL);
            },
            setLineCap: function (lineCap) {
                this._out(lineCap, ' J', NL);
            },
            setLineJoin: function (lineJoin) {
                this._out(lineJoin, ' j', NL);
            },
            setMitterLimit: function (mitterLimit) {
                this._out(mitterLimit, ' M', NL);
            },
            save: function () {
                this._contextStack.push(this._context());
                this._out('q', NL);
            },
            restore: function () {
                this._out('Q', NL);
                this._context(this._contextStack.pop());
            },
            moveTo: function (x, y) {
                this._out(x, ' ', y, ' m', NL);
            },
            lineTo: function (x, y) {
                this._out(x, ' ', y, ' l', NL);
            },
            bezier: function (x1, y1, x2, y2, x3, y3) {
                this._out(x1, ' ', y1, ' ', x2, ' ', y2, ' ', x3, ' ', y3, ' c', NL);
            },
            bezier1: function (x1, y1, x3, y3) {
                this._out(x1, ' ', y1, ' ', x3, ' ', y3, ' y', NL);
            },
            bezier2: function (x2, y2, x3, y3) {
                this._out(x2, ' ', y2, ' ', x3, ' ', y3, ' v', NL);
            },
            close: function () {
                this._out('h', NL);
            },
            rect: function (x, y, w, h) {
                this._out(x, ' ', y, ' ', w, ' ', h, ' re', NL);
            },
            ellipse: function (x, y, rx, ry) {
                function _X(v) {
                    return x + v;
                }
                function _Y(v) {
                    return y + v;
                }
                var k = 0.5522847498307936;
                this.moveTo(_X(0), _Y(ry));
                this.bezier(_X(rx * k), _Y(ry), _X(rx), _Y(ry * k), _X(rx), _Y(0));
                this.bezier(_X(rx), _Y(-ry * k), _X(rx * k), _Y(-ry), _X(0), _Y(-ry));
                this.bezier(_X(-rx * k), _Y(-ry), _X(-rx), _Y(-ry * k), _X(-rx), _Y(0));
                this.bezier(_X(-rx), _Y(ry * k), _X(-rx * k), _Y(ry), _X(0), _Y(ry));
            },
            circle: function (x, y, r) {
                this.ellipse(x, y, r, r);
            },
            stroke: function () {
                this._out('S', NL);
            },
            nop: function () {
                this._out('n', NL);
            },
            clip: function () {
                this._out('W n', NL);
            },
            clipStroke: function () {
                this._out('W S', NL);
            },
            closeStroke: function () {
                this._out('s', NL);
            },
            fill: function () {
                this._out('f', NL);
            },
            fillStroke: function () {
                this._out('B', NL);
            },
            drawImage: function (url) {
                var img = this._pdf.getImage(url);
                if (img) {
                    this._xResources[img._resourceName] = img;
                    this._out(img._resourceName, ' Do', NL);
                }
            },
            comment: function (txt) {
                var self = this;
                txt.split(/\r?\n/g).forEach(function (line) {
                    self._out('% ', line, NL);
                });
            },
            _context: function (val) {
                if (val != null) {
                    this._opacity = val.opacity;
                    this._matrix = val.matrix;
                } else {
                    return {
                        opacity: this._opacity,
                        matrix: this._matrix
                    };
                }
            },
            _toPage: function (p) {
                var m = this._matrix;
                var a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];
                return {
                    x: a * p.x + c * p.y + e,
                    y: b * p.x + d * p.y + f
                };
            }
        }, PDFDictionary);
        function unquote(str) {
            return str.replace(/^\s*(['"])(.*)\1\s*$/, '$2');
        }
        function parseFontDef(fontdef) {
            var rx = /^\s*((normal|italic)\s+)?((normal|small-caps)\s+)?((normal|bold|\d+)\s+)?(([0-9.]+)(px|pt))(\/(([0-9.]+)(px|pt)|normal))?\s+(.*?)\s*$/i;
            var m = rx.exec(fontdef);
            if (!m) {
                return {
                    fontSize: 12,
                    fontFamily: 'sans-serif'
                };
            }
            var fontSize = m[8] ? parseInt(m[8], 10) : 12;
            return {
                italic: m[2] && m[2].toLowerCase() == 'italic',
                variant: m[4],
                bold: m[6] && /bold|700/i.test(m[6]),
                fontSize: fontSize,
                lineHeight: m[12] ? m[12] == 'normal' ? fontSize : parseInt(m[12], 10) : null,
                fontFamily: m[14].split(/\s*,\s*/g).map(unquote)
            };
        }
        function getFontURL(style) {
            function mkFamily(name) {
                if (style.bold) {
                    name += '|bold';
                }
                if (style.italic) {
                    name += '|italic';
                }
                return name.toLowerCase();
            }
            var fontFamily = style.fontFamily;
            var name, url;
            if (fontFamily instanceof Array) {
                for (var i = 0; i < fontFamily.length; ++i) {
                    name = mkFamily(fontFamily[i]);
                    url = FONT_MAPPINGS[name];
                    if (url) {
                        break;
                    }
                }
            } else {
                url = FONT_MAPPINGS[fontFamily.toLowerCase()];
            }
            while (typeof url == 'function') {
                url = url();
            }
            if (!url) {
                url = 'Times-Roman';
            }
            return url;
        }
        var FONT_MAPPINGS = {
            'serif': 'Times-Roman',
            'serif|bold': 'Times-Bold',
            'serif|italic': 'Times-Italic',
            'serif|bold|italic': 'Times-BoldItalic',
            'sans-serif': 'Helvetica',
            'sans-serif|bold': 'Helvetica-Bold',
            'sans-serif|italic': 'Helvetica-Oblique',
            'sans-serif|bold|italic': 'Helvetica-BoldOblique',
            'monospace': 'Courier',
            'monospace|bold': 'Courier-Bold',
            'monospace|italic': 'Courier-Oblique',
            'monospace|bold|italic': 'Courier-BoldOblique',
            'zapfdingbats': 'ZapfDingbats',
            'zapfdingbats|bold': 'ZapfDingbats',
            'zapfdingbats|italic': 'ZapfDingbats',
            'zapfdingbats|bold|italic': 'ZapfDingbats'
        };
        function fontAlias(alias, name) {
            alias = alias.toLowerCase();
            FONT_MAPPINGS[alias] = function () {
                return FONT_MAPPINGS[name];
            };
            FONT_MAPPINGS[alias + '|bold'] = function () {
                return FONT_MAPPINGS[name + '|bold'];
            };
            FONT_MAPPINGS[alias + '|italic'] = function () {
                return FONT_MAPPINGS[name + '|italic'];
            };
            FONT_MAPPINGS[alias + '|bold|italic'] = function () {
                return FONT_MAPPINGS[name + '|bold|italic'];
            };
        }
        fontAlias('Times New Roman', 'serif');
        fontAlias('Courier New', 'monospace');
        fontAlias('Arial', 'sans-serif');
        fontAlias('Helvetica', 'sans-serif');
        fontAlias('Verdana', 'sans-serif');
        fontAlias('Tahoma', 'sans-serif');
        fontAlias('Georgia', 'sans-serif');
        fontAlias('Monaco', 'monospace');
        fontAlias('Andale Mono', 'monospace');
        function defineFont(name, url) {
            if (arguments.length == 1) {
                for (var i in name) {
                    if (hasOwnProperty(name, i)) {
                        defineFont(i, name[i]);
                    }
                }
            } else {
                name = name.toLowerCase();
                FONT_MAPPINGS[name] = url;
                switch (name) {
                case 'dejavu sans':
                    FONT_MAPPINGS['sans-serif'] = url;
                    break;
                case 'dejavu sans|bold':
                    FONT_MAPPINGS['sans-serif|bold'] = url;
                    break;
                case 'dejavu sans|italic':
                    FONT_MAPPINGS['sans-serif|italic'] = url;
                    break;
                case 'dejavu sans|bold|italic':
                    FONT_MAPPINGS['sans-serif|bold|italic'] = url;
                    break;
                case 'dejavu serif':
                    FONT_MAPPINGS['serif'] = url;
                    break;
                case 'dejavu serif|bold':
                    FONT_MAPPINGS['serif|bold'] = url;
                    break;
                case 'dejavu serif|italic':
                    FONT_MAPPINGS['serif|italic'] = url;
                    break;
                case 'dejavu serif|bold|italic':
                    FONT_MAPPINGS['serif|bold|italic'] = url;
                    break;
                case 'dejavu mono':
                    FONT_MAPPINGS['monospace'] = url;
                    break;
                case 'dejavu mono|bold':
                    FONT_MAPPINGS['monospace|bold'] = url;
                    break;
                case 'dejavu mono|italic':
                    FONT_MAPPINGS['monospace|italic'] = url;
                    break;
                case 'dejavu mono|bold|italic':
                    FONT_MAPPINGS['monospace|bold|italic'] = url;
                    break;
                }
            }
        }
        function mmul(a, b) {
            var a1 = a[0], b1 = a[1], c1 = a[2], d1 = a[3], e1 = a[4], f1 = a[5];
            var a2 = b[0], b2 = b[1], c2 = b[2], d2 = b[3], e2 = b[4], f2 = b[5];
            return [
                a1 * a2 + b1 * c2,
                a1 * b2 + b1 * d2,
                c1 * a2 + d1 * c2,
                c1 * b2 + d1 * d2,
                e1 * a2 + f1 * c2 + e2,
                e1 * b2 + f1 * d2 + f2
            ];
        }
        function isIdentityMatrix(m) {
            return m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0;
        }
        var TEXT_RENDERING_MODE = {
            fill: 0,
            stroke: 1,
            fillAndStroke: 2,
            invisible: 3,
            fillAndClip: 4,
            strokeAndClip: 5,
            fillStrokeClip: 6,
            clip: 7
        };
        var TEXT_RENDERING_MODE$1 = TEXT_RENDERING_MODE;
        var DASH_PATTERNS = {
            dash: [4],
            dashDot: [
                4,
                2,
                1,
                2
            ],
            dot: [
                1,
                2
            ],
            longDash: [
                8,
                2
            ],
            longDashDot: [
                8,
                2,
                1,
                2
            ],
            longDashDotDot: [
                8,
                2,
                1,
                2,
                1,
                2
            ],
            solid: []
        };
        var LINE_CAP = {
            butt: 0,
            round: 1,
            square: 2
        };
        var LINE_JOIN = {
            miter: 0,
            round: 1,
            bevel: 2
        };
        function render(group, callback) {
            var fonts = [], images = [], options = group.options;
            function getOption(name, defval, hash) {
                if (!hash) {
                    hash = options;
                }
                if (hash.pdf && hash.pdf[name] != null) {
                    return hash.pdf[name];
                }
                return defval;
            }
            var multiPage = getOption('multiPage');
            group.traverse(function (element) {
                dispatch({
                    Image: function (element) {
                        if (images.indexOf(element.src()) < 0) {
                            images.push(element.src());
                        }
                    },
                    Text: function (element) {
                        var style = parseFontDef(element.options.font);
                        var url = getFontURL(style);
                        if (fonts.indexOf(url) < 0) {
                            fonts.push(url);
                        }
                    }
                }, element);
            });
            function doIt() {
                if (--count > 0) {
                    return;
                }
                var pdf = new PDFDocument({
                    producer: getOption('producer'),
                    title: getOption('title'),
                    author: getOption('author'),
                    subject: getOption('subject'),
                    keywords: getOption('keywords'),
                    creator: getOption('creator'),
                    date: getOption('date')
                });
                function drawPage(group) {
                    var options = group.options;
                    var tmp = optimize(group);
                    var bbox = tmp.bbox;
                    group = tmp.root;
                    var paperSize = getOption('paperSize', getOption('paperSize', 'auto'), options), addMargin = false;
                    if (paperSize == 'auto') {
                        if (bbox) {
                            var size = bbox.getSize();
                            paperSize = [
                                size.width,
                                size.height
                            ];
                            addMargin = true;
                            var origin = bbox.getOrigin();
                            tmp = new drawing.Group();
                            tmp.transform(new kendoGeometry.Matrix(1, 0, 0, 1, -origin.x, -origin.y));
                            tmp.append(group);
                            group = tmp;
                        } else {
                            paperSize = 'A4';
                        }
                    }
                    var page;
                    page = pdf.addPage({
                        paperSize: paperSize,
                        margin: getOption('margin', getOption('margin'), options),
                        addMargin: addMargin,
                        landscape: getOption('landscape', getOption('landscape', false), options)
                    });
                    drawElement(group, page, pdf);
                }
                if (multiPage) {
                    group.children.forEach(drawPage);
                } else {
                    drawPage(group);
                }
                callback(pdf.render(), pdf);
            }
            var count = 2;
            loadFonts(fonts, doIt);
            loadImages(images, doIt);
        }
        function toDataURL(group, callback) {
            render(group, function (data) {
                callback('data:application/pdf;base64,' + data.base64());
            });
        }
        function toBlob(group, callback) {
            render(group, function (data) {
                callback(new window.Blob([data.get()], { type: 'application/pdf' }));
            });
        }
        function saveAs$1(group, filename, proxy, callback) {
            if (window.Blob && !supportBrowser.safari) {
                toBlob(group, function (blob) {
                    kendo.saveAs({
                        dataURI: blob,
                        fileName: filename
                    });
                    if (callback) {
                        callback(blob);
                    }
                });
            } else {
                toDataURL(group, function (dataURL) {
                    kendo.saveAs({
                        dataURI: dataURL,
                        fileName: filename,
                        proxyURL: proxy
                    });
                    if (callback) {
                        callback(dataURL);
                    }
                });
            }
        }
        function dispatch(handlers, element) {
            var handler = handlers[element.nodeType];
            if (handler) {
                return handler.call.apply(handler, arguments);
            }
            return element;
        }
        function drawElement(element, page, pdf) {
            if (element.options._pdfDebug) {
                page.comment('BEGIN: ' + element.options._pdfDebug);
            }
            var transform = element.transform();
            var opacity = element.opacity();
            page.save();
            if (opacity != null && opacity < 1) {
                page.setOpacity(opacity);
            }
            setStrokeOptions(element, page, pdf);
            setFillOptions(element, page, pdf);
            if (transform) {
                var m = transform.matrix();
                page.transform(m.a, m.b, m.c, m.d, m.e, m.f);
            }
            setClipping(element, page, pdf);
            dispatch({
                Path: drawPath,
                MultiPath: drawMultiPath,
                Circle: drawCircle,
                Arc: drawArc,
                Text: drawText,
                Image: drawImage,
                Group: drawGroup,
                Rect: drawRect
            }, element, page, pdf);
            page.restore();
            if (element.options._pdfDebug) {
                page.comment('END: ' + element.options._pdfDebug);
            }
        }
        function setStrokeOptions(element, page) {
            var stroke = element.stroke && element.stroke();
            if (!stroke) {
                return;
            }
            var color = stroke.color;
            if (color) {
                color = parseColor$1(color);
                if (color == null) {
                    return;
                }
                page.setStrokeColor(color.r, color.g, color.b);
                if (color.a != 1) {
                    page.setStrokeOpacity(color.a);
                }
            }
            var width = stroke.width;
            if (width != null) {
                if (width === 0) {
                    return;
                }
                page.setLineWidth(width);
            }
            var dashType = stroke.dashType;
            if (dashType) {
                page.setDashPattern(DASH_PATTERNS[dashType], 0);
            }
            var lineCap = stroke.lineCap;
            if (lineCap) {
                page.setLineCap(LINE_CAP[lineCap]);
            }
            var lineJoin = stroke.lineJoin;
            if (lineJoin) {
                page.setLineJoin(LINE_JOIN[lineJoin]);
            }
            var opacity = stroke.opacity;
            if (opacity != null) {
                page.setStrokeOpacity(opacity);
            }
        }
        function setFillOptions(element, page) {
            var fill = element.fill && element.fill();
            if (!fill) {
                return;
            }
            if (fill instanceof drawing.Gradient) {
                return;
            }
            var color = fill.color;
            if (color) {
                color = parseColor$1(color);
                if (color == null) {
                    return;
                }
                page.setFillColor(color.r, color.g, color.b);
                if (color.a != 1) {
                    page.setFillOpacity(color.a);
                }
            }
            var opacity = fill.opacity;
            if (opacity != null) {
                page.setFillOpacity(opacity);
            }
        }
        function setClipping(element, page, pdf) {
            var clip = element.clip();
            if (clip) {
                _drawPath(clip, page, pdf);
                page.clip();
            }
        }
        function shouldDraw(thing) {
            return thing && (thing instanceof drawing.Gradient || thing.color && !/^(none|transparent)$/i.test(thing.color) && (thing.width == null || thing.width > 0) && (thing.opacity == null || thing.opacity > 0));
        }
        function maybeGradient(element, page, pdf, stroke) {
            var fill = element.fill();
            if (fill instanceof drawing.Gradient) {
                if (stroke) {
                    page.clipStroke();
                } else {
                    page.clip();
                }
                var isRadial = fill instanceof drawing.RadialGradient;
                var start, end;
                if (isRadial) {
                    start = {
                        x: fill.center().x,
                        y: fill.center().y,
                        r: 0
                    };
                    end = {
                        x: fill.center().x,
                        y: fill.center().y,
                        r: fill.radius()
                    };
                } else {
                    start = {
                        x: fill.start().x,
                        y: fill.start().y
                    };
                    end = {
                        x: fill.end().x,
                        y: fill.end().y
                    };
                }
                var stops = fill.stops.elements().map(function (stop) {
                    var offset = stop.offset();
                    if (/%$/.test(offset)) {
                        offset = parseFloat(offset) / 100;
                    } else {
                        offset = parseFloat(offset);
                    }
                    var color = parseColor$1(stop.color());
                    color.a *= stop.opacity();
                    return {
                        offset: offset,
                        color: color
                    };
                });
                stops.unshift(stops[0]);
                stops.push(stops[stops.length - 1]);
                var gradient = {
                    userSpace: fill.userSpace(),
                    type: isRadial ? 'radial' : 'linear',
                    start: start,
                    end: end,
                    stops: stops
                };
                var box = element.rawBBox();
                var tl = box.topLeft(), size = box.getSize();
                box = {
                    left: tl.x,
                    top: tl.y,
                    width: size.width,
                    height: size.height
                };
                page.gradient(gradient, box);
                return true;
            }
        }
        function maybeFillStroke(element, page, pdf) {
            if (shouldDraw(element.fill()) && shouldDraw(element.stroke())) {
                if (!maybeGradient(element, page, pdf, true)) {
                    page.fillStroke();
                }
            } else if (shouldDraw(element.fill())) {
                if (!maybeGradient(element, page, pdf, false)) {
                    page.fill();
                }
            } else if (shouldDraw(element.stroke())) {
                page.stroke();
            } else {
                page.nop();
            }
        }
        function maybeDrawRect(path, page) {
            var segments = path.segments;
            if (segments.length == 4 && path.options.closed) {
                var a = [];
                for (var i = 0; i < segments.length; ++i) {
                    if (segments[i].controlIn()) {
                        return false;
                    }
                    a[i] = segments[i].anchor();
                }
                var isRect = a[0].y == a[1].y && a[1].x == a[2].x && a[2].y == a[3].y && a[3].x == a[0].x || a[0].x == a[1].x && a[1].y == a[2].y && a[2].x == a[3].x && a[3].y == a[0].y;
                if (isRect) {
                    page.rect(a[0].x, a[0].y, a[2].x - a[0].x, a[2].y - a[0].y);
                    return true;
                }
            }
        }
        function _drawPath(element, page, pdf) {
            var segments = element.segments;
            if (segments.length === 0) {
                return;
            }
            if (!maybeDrawRect(element, page, pdf)) {
                for (var prev, i = 0; i < segments.length; ++i) {
                    var seg = segments[i];
                    var anchor = seg.anchor();
                    if (!prev) {
                        page.moveTo(anchor.x, anchor.y);
                    } else {
                        var prevOut = prev.controlOut();
                        var controlIn = seg.controlIn();
                        if (prevOut && controlIn) {
                            page.bezier(prevOut.x, prevOut.y, controlIn.x, controlIn.y, anchor.x, anchor.y);
                        } else {
                            page.lineTo(anchor.x, anchor.y);
                        }
                    }
                    prev = seg;
                }
                if (element.options.closed) {
                    page.close();
                }
            }
        }
        function drawPath(element, page, pdf) {
            _drawPath(element, page, pdf);
            maybeFillStroke(element, page, pdf);
        }
        function drawMultiPath(element, page, pdf) {
            var paths = element.paths;
            for (var i = 0; i < paths.length; ++i) {
                _drawPath(paths[i], page, pdf);
            }
            maybeFillStroke(element, page, pdf);
        }
        function drawCircle(element, page, pdf) {
            var g = element.geometry();
            page.circle(g.center.x, g.center.y, g.radius);
            maybeFillStroke(element, page, pdf);
        }
        function drawArc(element, page, pdf) {
            var points = element.geometry().curvePoints();
            page.moveTo(points[0].x, points[0].y);
            for (var i = 1; i < points.length;) {
                page.bezier(points[i].x, points[i++].y, points[i].x, points[i++].y, points[i].x, points[i++].y);
            }
            maybeFillStroke(element, page, pdf);
        }
        function drawText(element, page) {
            var style = parseFontDef(element.options.font);
            var pos = element._position;
            var mode;
            if (element.fill() && element.stroke()) {
                mode = TEXT_RENDERING_MODE$1.fillAndStroke;
            } else if (element.fill()) {
                mode = TEXT_RENDERING_MODE$1.fill;
            } else if (element.stroke()) {
                mode = TEXT_RENDERING_MODE$1.stroke;
            }
            page.transform(1, 0, 0, -1, pos.x, pos.y + style.fontSize);
            page.beginText();
            page.setFont(getFontURL(style), style.fontSize);
            page.setTextRenderingMode(mode);
            page.showText(element.content(), element._pdfRect ? element._pdfRect.width() : null);
            page.endText();
        }
        function drawGroup(element, page, pdf) {
            if (element._pdfLink) {
                page.addLink(element._pdfLink.url, element._pdfLink);
            }
            var children = element.children;
            for (var i = 0; i < children.length; ++i) {
                drawElement(children[i], page, pdf);
            }
        }
        function drawImage(element, page) {
            var url = element.src();
            if (!url) {
                return;
            }
            var rect = element.rect();
            var tl = rect.getOrigin();
            var sz = rect.getSize();
            page.transform(sz.width, 0, 0, -sz.height, tl.x, tl.y + sz.height);
            page.drawImage(url);
        }
        function drawRect(element, page, pdf) {
            var geometry = element.geometry();
            page.rect(geometry.origin.x, geometry.origin.y, geometry.size.width, geometry.size.height);
            maybeFillStroke(element, page, pdf);
        }
        function parseColor$1(value) {
            var color = kendo.parseColor(value, true);
            return color ? color.toRGB() : null;
        }
        function optimize(root) {
            var clipbox = false;
            var matrix = kendoGeometry.Matrix.unit();
            var currentBox = null;
            var changed;
            do {
                changed = false;
                root = opt(root);
            } while (root && changed);
            return {
                root: root,
                bbox: currentBox
            };
            function change(newShape) {
                changed = true;
                return newShape;
            }
            function visible(shape) {
                return shape.visible() && shape.opacity() > 0 && (shouldDraw(shape.fill()) || shouldDraw(shape.stroke()));
            }
            function optArray(a) {
                var b = [];
                for (var i = 0; i < a.length; ++i) {
                    var el = opt(a[i]);
                    if (el != null) {
                        b.push(el);
                    }
                }
                return b;
            }
            function withClipping(shape, f) {
                var saveclipbox = clipbox;
                var savematrix = matrix;
                if (shape.transform()) {
                    matrix = matrix.multiplyCopy(shape.transform().matrix());
                }
                var clip = shape.clip();
                if (clip) {
                    clip = clip.bbox();
                    if (clip) {
                        clip = clip.bbox(matrix);
                        clipbox = clipbox ? kendoGeometry.Rect.intersect(clipbox, clip) : clip;
                    }
                }
                try {
                    return f();
                } finally {
                    clipbox = saveclipbox;
                    matrix = savematrix;
                }
            }
            function inClipbox(shape) {
                if (clipbox == null) {
                    return false;
                }
                var box = shape.rawBBox().bbox(matrix);
                if (clipbox && box) {
                    box = kendoGeometry.Rect.intersect(box, clipbox);
                }
                return box;
            }
            function opt(shape) {
                return withClipping(shape, function () {
                    if (!(shape instanceof drawing.Group || shape instanceof drawing.MultiPath)) {
                        var box = inClipbox(shape);
                        if (!box) {
                            return change(null);
                        }
                        currentBox = currentBox ? kendoGeometry.Rect.union(currentBox, box) : box;
                    }
                    return dispatch({
                        Path: function (shape) {
                            if (shape.segments.length === 0 || !visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        },
                        MultiPath: function (shape) {
                            if (!visible(shape)) {
                                return change(null);
                            }
                            var el = new drawing.MultiPath(shape.options);
                            el.paths = optArray(shape.paths);
                            if (el.paths.length === 0) {
                                return change(null);
                            }
                            return el;
                        },
                        Circle: function (shape) {
                            if (!visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        },
                        Arc: function (shape) {
                            if (!visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        },
                        Text: function (shape) {
                            if (!/\S/.test(shape.content()) || !visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        },
                        Image: function (shape) {
                            if (!(shape.visible() && shape.opacity() > 0)) {
                                return change(null);
                            }
                            return shape;
                        },
                        Group: function (shape) {
                            var el = new drawing.Group(shape.options);
                            el.children = optArray(shape.children);
                            el._pdfLink = shape._pdfLink;
                            if (shape !== root && el.children.length === 0 && !shape._pdfLink) {
                                return change(null);
                            }
                            return el;
                        },
                        Rect: function (shape) {
                            if (!visible(shape)) {
                                return change(null);
                            }
                            return shape;
                        }
                    }, shape);
                });
            }
        }
        function exportPDF(group, options) {
            var promise = util.createPromise();
            for (var i in options) {
                if (i == 'margin' && group.options.pdf && group.options.pdf._ignoreMargin) {
                    continue;
                }
                group.options.set('pdf.' + i, options[i]);
            }
            toDataURL(group, promise.resolve);
            return promise;
        }
        kendo.deepExtend(kendo.pdf, {
            Document: PDFDocument,
            BinaryStream: BinaryStream,
            defineFont: defineFont,
            parseFontDef: parseFontDef,
            getFontURL: getFontURL,
            loadFonts: loadFonts,
            loadImages: loadImages,
            getPaperOptions: getPaperOptions,
            TEXT_RENDERING_MODE: TEXT_RENDERING_MODE,
            exportPDF: exportPDF,
            saveAs: saveAs$1,
            toDataURL: toDataURL,
            toBlob: toBlob,
            render: render
        });
        kendo.drawing.exportPDF = kendo.pdf.exportPDF;
        kendo.drawing.pdf = kendo.pdf;
    }(kendo));
    return kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('pdf/mixins', ['pdf/core'], f);
}(function () {
    (function ($, undefined) {
        kendo.PDFMixin = {
            extend: function (proto) {
                proto.events.push('pdfExport');
                proto.options.pdf = this.options;
                proto.saveAsPDF = this.saveAsPDF;
                proto._drawPDF = this._drawPDF;
                proto._drawPDFShadow = this._drawPDFShadow;
            },
            options: {
                fileName: 'Export.pdf',
                proxyURL: '',
                paperSize: 'auto',
                allPages: false,
                landscape: false,
                margin: null,
                title: null,
                author: null,
                subject: null,
                keywords: null,
                creator: 'Kendo UI PDF Generator v.' + kendo.version,
                date: null
            },
            saveAsPDF: function () {
                var progress = new $.Deferred();
                var promise = progress.promise();
                var args = { promise: promise };
                if (this.trigger('pdfExport', args)) {
                    return;
                }
                var options = this.options.pdf;
                options.multiPage = options.multiPage || options.allPages;
                this._drawPDF(progress).then(function (root) {
                    return kendo.drawing.exportPDF(root, options);
                }).done(function (dataURI) {
                    kendo.saveAs({
                        dataURI: dataURI,
                        fileName: options.fileName,
                        proxyURL: options.proxyURL,
                        forceProxy: options.forceProxy,
                        proxyTarget: options.proxyTarget
                    });
                    progress.resolve();
                }).fail(function (err) {
                    progress.reject(err);
                });
                return promise;
            },
            _drawPDF: function (progress) {
                var promise = new $.Deferred();
                kendo.drawing.drawDOM(this.wrapper).done(function (group) {
                    var args = {
                        page: group,
                        pageNumber: 1,
                        progress: 1,
                        totalPages: 1
                    };
                    progress.notify(args);
                    promise.resolve(args.page);
                }).fail(function (err) {
                    promise.reject(err);
                });
                return promise;
            },
            _drawPDFShadow: function (settings, drawOptions) {
                settings = settings || {};
                var wrapper = this.wrapper;
                var shadow = $('<div class=\'k-pdf-export-shadow\'>');
                if (settings.width) {
                    shadow.css({
                        width: settings.width,
                        overflow: 'visible'
                    });
                }
                wrapper.before(shadow);
                shadow.append(settings.content || wrapper.clone(true, true));
                var defer = $.Deferred();
                setTimeout(function () {
                    var promise = kendo.drawing.drawDOM(shadow, drawOptions);
                    promise.always(function () {
                        shadow.remove();
                    }).then(function () {
                        defer.resolve.apply(defer, arguments);
                    }).fail(function () {
                        defer.reject.apply(defer, arguments);
                    }).progress(function () {
                        defer.progress.apply(defer, arguments);
                    });
                }, 15);
                return defer.promise();
            }
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pdf', [
        'kendo.core',
        'kendo.drawing',
        'pdf/core',
        'pdf/mixins'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pdf',
        name: 'PDF export',
        description: 'PDF Generation framework',
        mixin: true,
        category: 'framework',
        depends: [
            'core',
            'drawing'
        ]
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.grid', [
        'kendo.data',
        'kendo.columnsorter',
        'kendo.editable',
        'kendo.window',
        'kendo.filtermenu',
        'kendo.columnmenu',
        'kendo.groupable',
        'kendo.pager',
        'kendo.selectable',
        'kendo.sortable',
        'kendo.reorderable',
        'kendo.resizable',
        'kendo.mobile.actionsheet',
        'kendo.mobile.pane',
        'kendo.ooxml',
        'kendo.excel',
        'kendo.progressbar',
        'kendo.pdf'
    ], f);
}(function () {
    var __meta__ = {
        id: 'grid',
        name: 'Grid',
        category: 'web',
        description: 'The Grid widget displays tabular data and offers rich support for interacting with data,including paging, sorting, grouping, and selection.',
        depends: [
            'data',
            'columnsorter'
        ],
        features: [
            {
                id: 'grid-editing',
                name: 'Editing',
                description: 'Support for record editing',
                depends: [
                    'editable',
                    'window'
                ]
            },
            {
                id: 'grid-filtering',
                name: 'Filtering',
                description: 'Support for record filtering',
                depends: ['filtermenu']
            },
            {
                id: 'grid-columnmenu',
                name: 'Column menu',
                description: 'Support for header column menu',
                depends: ['columnmenu']
            },
            {
                id: 'grid-grouping',
                name: 'Grouping',
                description: 'Support for grid grouping',
                depends: ['groupable']
            },
            {
                id: 'grid-filtercell',
                name: 'Row filter',
                description: 'Support for grid header filtering',
                depends: ['filtercell']
            },
            {
                id: 'grid-paging',
                name: 'Paging',
                description: 'Support for grid paging',
                depends: ['pager']
            },
            {
                id: 'grid-selection',
                name: 'Selection',
                description: 'Support for row selection',
                depends: ['selectable']
            },
            {
                id: 'grid-column-reorder',
                name: 'Column reordering',
                description: 'Support for column reordering',
                depends: ['reorderable']
            },
            {
                id: 'grid-column-resize',
                name: 'Column resizing',
                description: 'Support for column resizing',
                depends: ['resizable']
            },
            {
                id: 'grid-mobile',
                name: 'Grid adaptive rendering',
                description: 'Support for adaptive rendering',
                depends: [
                    'mobile.actionsheet',
                    'mobile.pane'
                ]
            },
            {
                id: 'grid-excel-export',
                name: 'Excel export',
                description: 'Export grid data as Excel spreadsheet',
                depends: ['excel']
            },
            {
                id: 'grid-pdf-export',
                name: 'PDF export',
                description: 'Export grid data as PDF',
                depends: [
                    'pdf',
                    'drawing',
                    'progressbar'
                ]
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, DataSource = kendo.data.DataSource, tbodySupportsInnerHtml = kendo.support.tbodyInnerHtml, activeElement = kendo._activeElement, Widget = ui.Widget, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, keys = kendo.keys, isPlainObject = $.isPlainObject, extend = $.extend, map = $.map, grep = $.grep, isArray = $.isArray, inArray = $.inArray, push = Array.prototype.push, proxy = $.proxy, isFunction = kendo.isFunction, isEmptyObject = $.isEmptyObject, math = Math, PROGRESS = 'progress', ERROR = 'error', DATA_CELL = ':not(.k-group-cell):not(.k-hierarchy-cell):visible', SELECTION_CELL_SELECTOR = 'tbody>tr:not(.k-grouping-row):not(.k-detail-row):not(.k-group-footer) > td:not(.k-group-cell):not(.k-hierarchy-cell)', NAVROW = 'tr:not(.k-footer-template):visible', NAVCELL = ':not(.k-group-cell):not(.k-hierarchy-cell):visible', FIRSTNAVITEM = NAVROW + ':first>' + NAVCELL + ':first', HEADERCELLS = 'th.k-header:not(.k-group-cell):not(.k-hierarchy-cell)', NS = '.kendoGrid', EDIT = 'edit', BEFOREEDIT = 'beforeEdit', SAVE = 'save', REMOVE = 'remove', DETAILINIT = 'detailInit', FILTERMENUINIT = 'filterMenuInit', COLUMNMENUINIT = 'columnMenuInit', FILTERMENUOPEN = 'filterMenuOpen', COLUMNMENUOPEN = 'columnMenuOpen', CELLCLOSE = 'cellClose', CHANGE = 'change', COLUMNHIDE = 'columnHide', COLUMNSHOW = 'columnShow', SAVECHANGES = 'saveChanges', DATABOUND = 'dataBound', DETAILEXPAND = 'detailExpand', DETAILCOLLAPSE = 'detailCollapse', FOCUSED = 'k-state-focused', SELECTED = 'k-state-selected', NORECORDSCLASS = 'k-grid-norecords', COLUMNRESIZE = 'columnResize', COLUMNREORDER = 'columnReorder', COLUMNLOCK = 'columnLock', COLUMNUNLOCK = 'columnUnlock', NAVIGATE = 'navigate', CLICK = 'click', HEIGHT = 'height', TABINDEX = 'tabIndex', FUNCTION = 'function', STRING = 'string', DELETECONFIRM = 'Are you sure you want to delete this record?', NORECORDS = 'No records available.', CONFIRMDELETE = 'Delete', CANCELDELETE = 'Cancel', COLLAPSE = 'Collapse', EXPAND = 'Expand', ARIALABEL = 'aria-label', formatRegExp = /(\}|\#)/gi, templateHashRegExp = /#/gi, whitespaceRegExp = '[\\x20\\t\\r\\n\\f]', nonDataCellsRegExp = new RegExp('(^|' + whitespaceRegExp + ')' + '(k-group-cell|k-hierarchy-cell)' + '(' + whitespaceRegExp + '|$)'), filterRowRegExp = new RegExp('(^|' + whitespaceRegExp + ')' + '(k-filter-row)' + '(' + whitespaceRegExp + '|$)'), COMMANDBUTTONTMPL = '<a role="button" class="k-button k-button-icontext #=className#" #=attr# href="\\#"><span class="#=iconClass# #=imageClass#"></span>#=text#</a>', isRtl = false, browser = kendo.support.browser, isIE7 = browser.msie && browser.version == 7, isIE8 = browser.msie && browser.version == 8;
        var VirtualScrollable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._refreshHandler = proxy(that.refresh, that);
                that.setDataSource(options.dataSource);
                that.wrap();
            },
            setDataSource: function (dataSource) {
                var that = this;
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                }
                that.dataSource = dataSource;
                that.dataSource.bind(CHANGE, that._refreshHandler);
            },
            options: {
                name: 'VirtualScrollable',
                itemHeight: $.noop,
                prefetch: true
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.dataSource.unbind(CHANGE, that._refreshHandler);
                that.wrapper.add(that.verticalScrollbar).off(NS);
                if (that.drag) {
                    that.drag.destroy();
                    that.drag = null;
                }
                that.wrapper = that.element = that.verticalScrollbar = null;
                that._refreshHandler = null;
            },
            wrap: function () {
                var that = this, scrollbar = kendo.support.scrollbar() + 1, element = that.element, wrapper;
                element.css({
                    width: 'auto',
                    overflow: 'hidden'
                }).css(isRtl ? 'padding-left' : 'padding-right', scrollbar);
                that.content = element.children().first();
                wrapper = that.wrapper = that.content.wrap('<div class="k-virtual-scrollable-wrap"/>').parent().bind('DOMMouseScroll' + NS + ' mousewheel' + NS, proxy(that._wheelScroll, that));
                if (kendo.support.kineticScrollNeeded) {
                    that.drag = new kendo.UserEvents(that.wrapper, {
                        global: true,
                        start: function (e) {
                            e.sender.capture();
                        },
                        move: function (e) {
                            that.verticalScrollbar.scrollTop(that.verticalScrollbar.scrollTop() - e.y.delta);
                            wrapper.scrollLeft(wrapper.scrollLeft() - e.x.delta);
                            e.preventDefault();
                        }
                    });
                }
                that.verticalScrollbar = $('<div class="k-scrollbar k-scrollbar-vertical" />').css({ width: scrollbar }).appendTo(element).bind('scroll' + NS, proxy(that._scroll, that));
            },
            _wheelScroll: function (e) {
                if (e.ctrlKey) {
                    return;
                }
                var scrollbar = this.verticalScrollbar, scrollTop = scrollbar.scrollTop(), delta = kendo.wheelDeltaY(e);
                if (delta && !(delta > 0 && scrollTop === 0) && !(delta < 0 && scrollTop + scrollbar[0].clientHeight == scrollbar[0].scrollHeight)) {
                    e.preventDefault();
                    this.verticalScrollbar.scrollTop(scrollTop + -delta);
                }
            },
            _scroll: function (e) {
                var that = this, delayLoading = !that.options.prefetch, scrollTop = e.currentTarget.scrollTop, dataSource = that.dataSource, rowHeight = that.itemHeight, skip = dataSource.skip() || 0, start = that._rangeStart || skip, height = that.element.innerHeight(), isScrollingUp = !!(that._scrollbarTop && that._scrollbarTop > scrollTop), firstItemIndex = math.max(math.floor(scrollTop / rowHeight), 0), lastItemIndex = math.max(firstItemIndex + math.floor(height / rowHeight), 0);
                that._scrollTop = scrollTop - start * rowHeight;
                that._scrollbarTop = scrollTop;
                that._scrolling = delayLoading;
                if (!that._fetch(firstItemIndex, lastItemIndex, isScrollingUp)) {
                    that.wrapper[0].scrollTop = that._scrollTop;
                }
                if (delayLoading) {
                    if (that._scrollingTimeout) {
                        clearTimeout(that._scrollingTimeout);
                    }
                    that._scrollingTimeout = setTimeout(function () {
                        that._scrolling = false;
                        that._page(that._rangeStart, that.dataSource.take());
                    }, 100);
                }
            },
            itemIndex: function (rowIndex) {
                var rangeStart = this._rangeStart || this.dataSource.skip() || 0;
                return rangeStart + rowIndex;
            },
            position: function (index) {
                var rangeStart = this._rangeStart || this.dataSource.skip() || 0;
                var pageSize = this.dataSource.pageSize();
                var result;
                if (index > rangeStart) {
                    result = index - rangeStart + 1;
                } else {
                    result = rangeStart - index - 1;
                }
                return result > pageSize ? pageSize : result;
            },
            scrollIntoView: function (row) {
                var container = this.wrapper[0];
                var containerHeight = container.clientHeight;
                var containerScroll = this._scrollTop || container.scrollTop;
                var elementOffset = row[0].offsetTop;
                var elementHeight = row[0].offsetHeight;
                if (containerScroll > elementOffset) {
                    this.verticalScrollbar[0].scrollTop -= containerHeight / 2;
                } else if (elementOffset + elementHeight >= containerScroll + containerHeight) {
                    this.verticalScrollbar[0].scrollTop += containerHeight / 2;
                }
            },
            _fetch: function (firstItemIndex, lastItemIndex, scrollingUp) {
                var that = this, dataSource = that.dataSource, itemHeight = that.itemHeight, take = dataSource.take(), rangeStart = that._rangeStart || dataSource.skip() || 0, currentSkip = math.floor(firstItemIndex / take) * take, fetching = false, prefetchAt = 0.33;
                if (firstItemIndex < rangeStart) {
                    fetching = true;
                    rangeStart = math.max(0, lastItemIndex - take);
                    that._scrollTop = (firstItemIndex - rangeStart) * itemHeight;
                    that._page(rangeStart, take);
                } else if (lastItemIndex >= rangeStart + take && !scrollingUp) {
                    fetching = true;
                    rangeStart = firstItemIndex;
                    that._scrollTop = itemHeight;
                    that._page(rangeStart, take);
                } else if (!that._fetching && that.options.prefetch) {
                    if (firstItemIndex < currentSkip + take - take * prefetchAt && firstItemIndex > take) {
                        dataSource.prefetch(currentSkip - take, take, $.noop);
                    }
                    if (lastItemIndex > currentSkip + take * prefetchAt) {
                        dataSource.prefetch(currentSkip + take, take, $.noop);
                    }
                }
                return fetching;
            },
            fetching: function () {
                return this._fetching;
            },
            _page: function (skip, take) {
                var that = this, delayLoading = !that.options.prefetch, dataSource = that.dataSource;
                clearTimeout(that._timeout);
                that._fetching = true;
                that._rangeStart = skip;
                if (dataSource.inRange(skip, take)) {
                    dataSource.range(skip, take);
                } else {
                    if (!delayLoading) {
                        kendo.ui.progress(that.wrapper.parent(), true);
                    }
                    that._timeout = setTimeout(function () {
                        if (!that._scrolling) {
                            if (delayLoading) {
                                kendo.ui.progress(that.wrapper.parent(), true);
                            }
                            dataSource.range(skip, take);
                        }
                    }, 100);
                }
            },
            repaintScrollbar: function () {
                var that = this, html = '', maxHeight = 250000, dataSource = that.dataSource, scrollbar = !kendo.support.kineticScrollNeeded ? kendo.support.scrollbar() : 0, wrapperElement = that.wrapper[0], totalHeight, idx, itemHeight;
                itemHeight = that.itemHeight = that.options.itemHeight() || 0;
                var addScrollBarHeight = wrapperElement.scrollWidth > wrapperElement.offsetWidth ? scrollbar : 0;
                totalHeight = dataSource.total() * itemHeight + addScrollBarHeight;
                for (idx = 0; idx < math.floor(totalHeight / maxHeight); idx++) {
                    html += '<div style="width:1px;height:' + maxHeight + 'px"></div>';
                }
                if (totalHeight % maxHeight) {
                    html += '<div style="width:1px;height:' + totalHeight % maxHeight + 'px"></div>';
                }
                that.verticalScrollbar.html(html);
                wrapperElement.scrollTop = that._scrollTop;
            },
            refresh: function () {
                var that = this, dataSource = that.dataSource, rangeStart = that._rangeStart;
                kendo.ui.progress(that.wrapper.parent(), false);
                clearTimeout(that._timeout);
                that.repaintScrollbar();
                if (that.drag) {
                    that.drag.cancel();
                }
                if (rangeStart && !that._fetching) {
                    that._rangeStart = dataSource.skip();
                    if (dataSource.page() === 1) {
                        that.verticalScrollbar[0].scrollTop = 0;
                    }
                }
                that._fetching = false;
            }
        });
        function groupCells(count) {
            return new Array(count + 1).join('<td class="k-group-cell">&nbsp;</td>');
        }
        function stringifyAttributes(attributes) {
            var attr, result = ' ';
            if (attributes) {
                if (typeof attributes === STRING) {
                    return attributes;
                }
                for (attr in attributes) {
                    result += attr + '="' + attributes[attr] + '"';
                }
            }
            return result;
        }
        var defaultCommands = {
            create: {
                text: 'Add new record',
                imageClass: 'k-i-plus',
                className: 'k-grid-add',
                iconClass: 'k-icon'
            },
            cancel: {
                text: 'Cancel changes',
                imageClass: 'k-i-cancel',
                className: 'k-grid-cancel-changes',
                iconClass: 'k-icon'
            },
            save: {
                text: 'Save changes',
                imageClass: 'k-i-check',
                className: 'k-grid-save-changes',
                iconClass: 'k-icon'
            },
            destroy: {
                text: 'Delete',
                imageClass: 'k-i-close',
                className: 'k-grid-delete',
                iconClass: 'k-icon'
            },
            edit: {
                text: 'Edit',
                imageClass: 'k-i-edit',
                className: 'k-grid-edit',
                iconClass: 'k-icon'
            },
            update: {
                text: 'Update',
                imageClass: 'k-i-check',
                className: 'k-primary k-grid-update',
                iconClass: 'k-icon'
            },
            canceledit: {
                text: 'Cancel',
                imageClass: 'k-i-cancel',
                className: 'k-grid-cancel',
                iconClass: 'k-icon'
            },
            excel: {
                text: 'Export to Excel',
                imageClass: 'k-i-file-excel',
                className: 'k-grid-excel',
                iconClass: 'k-icon'
            },
            pdf: {
                text: 'Export to PDF',
                imageClass: 'k-i-file-pdf',
                className: 'k-grid-pdf',
                iconClass: 'k-icon'
            }
        };
        function cursor(context, value) {
            $('th, th .k-grid-filter, th .k-link', context).add(document.body).css('cursor', value);
        }
        function reorder(selector, source, dest, before, count) {
            var sourceIndex = source;
            source = $();
            count = count || 1;
            for (var idx = 0; idx < count; idx++) {
                source = source.add(selector.eq(sourceIndex + idx));
            }
            if (typeof dest == 'number') {
                source[before ? 'insertBefore' : 'insertAfter'](selector.eq(dest));
            } else {
                source.appendTo(dest);
            }
        }
        function elements(lockedContent, content, filter) {
            return $(lockedContent).add(content).find(filter);
        }
        function attachCustomCommandEvent(context, container, commands) {
            var idx, length, command, commandName;
            commands = !isArray(commands) ? [commands] : commands;
            for (idx = 0, length = commands.length; idx < length; idx++) {
                command = commands[idx];
                if (isPlainObject(command) && command.click) {
                    commandName = command.name || command.text;
                    container.on(CLICK + NS, 'a.k-grid-' + (commandName || '').replace(/\s/g, ''), { commandName: commandName }, proxy(command.click, context));
                }
            }
        }
        function normalizeColumns(columns, encoded, hide) {
            return map(columns, function (column) {
                column = typeof column === STRING ? { field: column } : column;
                var hidden;
                if (!isVisible(column) || hide) {
                    column.attributes = addHiddenStyle(column.attributes);
                    column.footerAttributes = addHiddenStyle(column.footerAttributes);
                    column.headerAttributes = addHiddenStyle(column.headerAttributes);
                    hidden = true;
                }
                if (column.columns) {
                    column.columns = normalizeColumns(column.columns, encoded, hidden);
                }
                var uid = kendo.guid();
                column.headerAttributes = extend({ id: uid }, column.headerAttributes);
                return extend({
                    encoded: encoded,
                    hidden: hidden
                }, column);
            });
        }
        function columnParent(column, columns) {
            var parents = [];
            columnParents(column, columns, parents);
            return parents[parents.length - 1];
        }
        function columnParents(column, columns, parents) {
            parents = parents || [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (column === columns[idx]) {
                    return true;
                } else if (columns[idx].columns) {
                    var inserted = parents.length;
                    parents.push(columns[idx]);
                    if (!columnParents(column, columns[idx].columns, parents)) {
                        parents.splice(inserted, parents.length - inserted);
                    } else {
                        return true;
                    }
                }
            }
            return false;
        }
        function setColumnVisibility(column, visible) {
            var method = visible ? removeHiddenStyle : addHiddenStyle;
            column.hidden = !visible;
            column.attributes = method(column.attributes);
            column.footerAttributes = method(column.footerAttributes);
            column.headerAttributes = method(column.headerAttributes);
        }
        function isCellVisible() {
            return this.style.display !== 'none';
        }
        function isVisible(column) {
            return visibleColumns([column]).length > 0;
        }
        function visibleColumns(columns) {
            return grep(columns, function (column) {
                var result = !column.hidden;
                if (result && column.columns) {
                    result = visibleColumns(column.columns).length > 0;
                }
                return result;
            });
        }
        function toJQuery(elements) {
            return $(elements).map(function () {
                return this.toArray();
            });
        }
        function updateCellRowSpan(cell, columns, sourceLockedColumnsCount) {
            var lockedColumnDepth = depth(lockedColumns(columns));
            var nonLockedColumnDepth = depth(nonLockedColumns(columns));
            var rowSpan = cell.rowSpan;
            if (sourceLockedColumnsCount) {
                if (lockedColumnDepth > nonLockedColumnDepth) {
                    cell.rowSpan = rowSpan - (lockedColumnDepth - nonLockedColumnDepth) || 1;
                } else {
                    cell.rowSpan = rowSpan + (nonLockedColumnDepth - lockedColumnDepth);
                }
            } else {
                if (lockedColumnDepth > nonLockedColumnDepth) {
                    cell.rowSpan = rowSpan + (lockedColumnDepth - nonLockedColumnDepth);
                } else {
                    cell.rowSpan = rowSpan - (nonLockedColumnDepth - lockedColumnDepth) || 1;
                }
            }
        }
        function moveCellsBetweenContainers(sources, target, leafs, columns, container, destination, groups) {
            var sourcesDepth = depth(sources);
            var targetDepth = depth([target]);
            if (sourcesDepth > targetDepth) {
                var groupCells = new Array(groups + 1).join('<th class="k-group-cell k-header" scope="col">&nbsp;</th>');
                var rows = destination.children(':not(.k-filter-row)');
                $(new Array(sourcesDepth - targetDepth + 1).join('<tr>' + groupCells + '</tr>')).insertAfter(rows.last());
            }
            addRowSpanValue(destination, sourcesDepth - targetDepth);
            moveCells(leafs, columns, container, destination);
        }
        function updateCellIndex(thead, columns, offset) {
            offset = offset || 0;
            var position;
            var cell;
            var allColumns = columns;
            columns = leafColumns(columns);
            var cells = {};
            var rows = thead.find('>tr:not(.k-filter-row)');
            var filter = function () {
                var el = $(this);
                return !el.hasClass('k-group-cell') && !el.hasClass('k-hierarchy-cell');
            };
            for (var idx = 0, length = columns.length; idx < length; idx++) {
                position = columnPosition(columns[idx], allColumns);
                if (!cells[position.row]) {
                    cells[position.row] = rows.eq(position.row).find('.k-header').filter(filter);
                }
                cell = cells[position.row].eq(position.cell);
                cell.attr(kendo.attr('index'), offset + idx);
            }
            return columns.length;
        }
        function depth(columns) {
            var result = 1;
            var max = 0;
            for (var idx = 0; idx < columns.length; idx++) {
                if (columns[idx].columns) {
                    var temp = depth(columns[idx].columns);
                    if (temp > max) {
                        max = temp;
                    }
                }
            }
            return result + max;
        }
        function moveCells(leafs, columns, container, destination) {
            var sourcePosition = columnVisiblePosition(leafs[0], columns);
            var ths = container.find('>tr:not(.k-filter-row):eq(' + sourcePosition.row + ')>th.k-header');
            var t = $();
            var sourceIndex = sourcePosition.cell;
            var idx;
            for (idx = 0; idx < leafs.length; idx++) {
                t = t.add(ths.eq(sourceIndex + idx));
            }
            destination.find('>tr:not(.k-filter-row)').eq(sourcePosition.row).append(t);
            var children = [];
            for (idx = 0; idx < leafs.length; idx++) {
                if (leafs[idx].columns) {
                    children = children.concat(leafs[idx].columns);
                }
            }
            if (children.length) {
                moveCells(children, columns, container, destination);
            }
        }
        function columnPosition(column, columns, row, cellCounts) {
            var result;
            var idx;
            row = row || 0;
            cellCounts = cellCounts || {};
            cellCounts[row] = cellCounts[row] || 0;
            for (idx = 0; idx < columns.length; idx++) {
                if (columns[idx] == column) {
                    result = {
                        cell: cellCounts[row],
                        row: row
                    };
                    break;
                } else if (columns[idx].columns) {
                    result = columnPosition(column, columns[idx].columns, row + 1, cellCounts);
                    if (result) {
                        break;
                    }
                }
                cellCounts[row]++;
            }
            return result;
        }
        function findParentColumnWithChildren(columns, index, source, rtl) {
            var target;
            var locked = source.locked;
            do {
                target = columns[index];
                index += rtl ? 1 : -1;
            } while (target && index > -1 && index < columns.length && target != source && !target.columns && target.locked == locked);
            return target;
        }
        function findReorderTarget(columns, target, source, before) {
            if (target.columns) {
                target = target.columns;
                return target[before ? 0 : target.length - 1];
            } else {
                var parent = columnParent(target, columns);
                var parentColumns;
                if (parent) {
                    parentColumns = parent.columns;
                } else {
                    parentColumns = columns;
                }
                var index = inArray(target, parentColumns);
                if (index === 0 && before) {
                    index++;
                } else if (index == parentColumns.length - 1 && !before) {
                    index--;
                } else if (index > 0 || index === 0 && !before) {
                    index += before ? -1 : 1;
                }
                var sourceIndex = inArray(source, parentColumns);
                target = findParentColumnWithChildren(parentColumns, index, source, sourceIndex > index);
                if (target && target != source && target.columns) {
                    return findReorderTarget(columns, target, source, before);
                }
            }
            return null;
        }
        function columnVisiblePosition(column, columns, row, cellCounts) {
            var result;
            var idx;
            row = row || 0;
            cellCounts = cellCounts || {};
            cellCounts[row] = cellCounts[row] || 0;
            for (idx = 0; idx < columns.length; idx++) {
                if (columns[idx] == column) {
                    result = {
                        cell: cellCounts[row],
                        row: row
                    };
                    break;
                } else if (columns[idx].columns) {
                    result = columnVisiblePosition(column, columns[idx].columns, row + 1, cellCounts);
                    if (result) {
                        break;
                    }
                }
                if (!columns[idx].hidden) {
                    cellCounts[row]++;
                }
            }
            return result;
        }
        function flatColumnsInDomOrder(columns) {
            var result = flatColumns(lockedColumns(columns));
            return result.concat(flatColumns(nonLockedColumns(columns)));
        }
        function flatColumns(columns) {
            var result = [];
            var children = [];
            for (var idx = 0; idx < columns.length; idx++) {
                result.push(columns[idx]);
                if (columns[idx].columns) {
                    children = children.concat(columns[idx].columns);
                }
            }
            if (children.length) {
                result = result.concat(flatColumns(children));
            }
            return result;
        }
        function hiddenLeafColumnsCount(columns) {
            var counter = 0;
            var column;
            for (var idx = 0; idx < columns.length; idx++) {
                column = columns[idx];
                if (column.columns) {
                    counter += hiddenLeafColumnsCount(column.columns);
                } else if (column.hidden) {
                    counter++;
                }
            }
            return counter;
        }
        function columnsWidth(cols) {
            var colWidth, width = 0;
            for (var idx = 0, length = cols.length; idx < length; idx++) {
                colWidth = cols[idx].style.width;
                if (colWidth && colWidth.indexOf('%') == -1) {
                    width += parseInt(colWidth, 10);
                }
            }
            return width;
        }
        function removeRowSpanValue(container, count) {
            var cells = container.find('tr:not(.k-filter-row) th:not(.k-group-cell,.k-hierarchy-cell)');
            var rowSpan;
            for (var idx = 0; idx < cells.length; idx++) {
                rowSpan = cells[idx].rowSpan;
                if (rowSpan > 1) {
                    cells[idx].rowSpan = rowSpan - count || 1;
                }
            }
        }
        function addRowSpanValue(container, count) {
            var cells = container.find('tr:not(.k-filter-row) th:not(.k-group-cell,.k-hierarchy-cell)');
            for (var idx = 0; idx < cells.length; idx++) {
                cells[idx].rowSpan += count;
            }
        }
        function removeEmptyRows(container) {
            var rows = container.find('tr:not(.k-filter-row)');
            var emptyRowsCount = rows.filter(function () {
                return !$(this).children().length;
            }).remove().length;
            var cells = rows.find('th:not(.k-group-cell,.k-hierarchy-cell)');
            for (var idx = 0; idx < cells.length; idx++) {
                if (cells[idx].rowSpan > 1) {
                    cells[idx].rowSpan -= emptyRowsCount;
                }
            }
            return rows.length - emptyRowsCount;
        }
        function mapColumnToCellRows(columns, cells, rows, rowIndex, offset) {
            var idx, row, length, children = [];
            for (idx = 0, length = columns.length; idx < length; idx++) {
                row = rows[rowIndex] || [];
                row.push(cells.eq(offset + idx));
                rows[rowIndex] = row;
                if (columns[idx].columns) {
                    children = children.concat(columns[idx].columns);
                }
            }
            if (children.length) {
                mapColumnToCellRows(children, cells, rows, rowIndex + 1, offset + columns.length);
            }
        }
        function lockedColumns(columns) {
            return grep(columns, function (column) {
                return column.locked;
            });
        }
        function nonLockedColumns(columns) {
            return grep(columns, function (column) {
                return !column.locked;
            });
        }
        function visibleNonLockedColumns(columns) {
            return grep(columns, function (column) {
                return !column.locked && isVisible(column);
            });
        }
        function visibleLockedColumns(columns) {
            return grep(columns, function (column) {
                return column.locked && isVisible(column);
            });
        }
        function visibleLeafColumns(columns) {
            var result = [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (columns[idx].hidden) {
                    continue;
                }
                if (columns[idx].columns) {
                    result = result.concat(visibleLeafColumns(columns[idx].columns));
                } else {
                    result.push(columns[idx]);
                }
            }
            return result;
        }
        function leafColumns(columns) {
            var result = [];
            for (var idx = 0; idx < columns.length; idx++) {
                if (!columns[idx].columns) {
                    result.push(columns[idx]);
                    continue;
                }
                result = result.concat(leafColumns(columns[idx].columns));
            }
            return result;
        }
        function leafDataCells(container) {
            var rows = container.find('>tr:not(.k-filter-row)');
            var filter = function () {
                var el = $(this);
                return !el.hasClass('k-group-cell') && !el.hasClass('k-hierarchy-cell');
            };
            var cells = $();
            if (rows.length > 1) {
                cells = rows.find('th').filter(filter).filter(function () {
                    return this.rowSpan > 1;
                });
            }
            cells = cells.add(rows.last().find('th').filter(filter));
            var indexAttr = kendo.attr('index');
            cells.sort(function (a, b) {
                a = $(a);
                b = $(b);
                var indexA = a.attr(indexAttr);
                var indexB = b.attr(indexAttr);
                if (indexA === undefined) {
                    indexA = $(a).index();
                }
                if (indexB === undefined) {
                    indexB = $(b).index();
                }
                indexA = parseInt(indexA, 10);
                indexB = parseInt(indexB, 10);
                return indexA > indexB ? 1 : indexA < indexB ? -1 : 0;
            });
            return cells;
        }
        function parentColumnsCells(cell) {
            var container = cell.closest('table');
            var result = $().add(cell);
            var row = cell.closest('tr');
            var headerRows = container.find('tr:not(.k-filter-row)');
            var level = headerRows.index(row);
            if (level > 0) {
                var parent = headerRows.eq(level - 1);
                var parentCellsWithChildren = parent.find('th:not(.k-group-cell,.k-hierarchy-cell)').filter(function () {
                    return !$(this).attr('rowspan');
                });
                var offset = 0;
                var index = row.find('th:not(.k-group-cell,.k-hierarchy-cell)').index(cell);
                var prevCells = cell.prevAll(':not(.k-group-cell,.k-hierarchy-cell)').filter(function () {
                    return this.colSpan > 1;
                });
                for (var idx = 0; idx < prevCells.length; idx++) {
                    offset += prevCells[idx].colSpan || 1;
                }
                index += Math.max(offset - 1, 0);
                offset = 0;
                for (idx = 0; idx < parentCellsWithChildren.length; idx++) {
                    var parentCell = parentCellsWithChildren.eq(idx);
                    if (parentCell.attr('colSpan')) {
                        offset += parentCell[0].colSpan;
                    } else {
                        offset += 1;
                    }
                    if (index >= idx && index < offset) {
                        result = parentColumnsCells(parentCell).add(result);
                        break;
                    }
                }
            }
            return result;
        }
        function childColumnsCells(cell) {
            var container = cell.closest('thead');
            var result = $().add(cell);
            var row = cell.closest('tr');
            var headerRows = container.find('tr:not(.k-filter-row)');
            var level = headerRows.index(row) + cell[0].rowSpan;
            var colSpanAttr = kendo.attr('colspan');
            if (level <= headerRows.length - 1) {
                var child = row.next();
                var prevCells = cell.prevAll(':not(.k-group-cell,.k-hierarchy-cell)');
                var idx;
                prevCells = prevCells.filter(function () {
                    return !this.rowSpan || this.rowSpan === 1;
                });
                var offset = 0;
                for (idx = 0; idx < prevCells.length; idx++) {
                    offset += parseInt(prevCells.eq(idx).attr(colSpanAttr), 10) || 1;
                }
                var cells = child.find('th:not(.k-group-cell,.k-hierarchy-cell)');
                var colSpan = parseInt(cell.attr(colSpanAttr), 10) || 1;
                idx = 0;
                while (idx < colSpan) {
                    child = cells.eq(idx + offset);
                    result = result.add(childColumnsCells(child));
                    var value = parseInt(child.attr(colSpanAttr), 10);
                    if (value > 1) {
                        colSpan -= value - 1;
                    }
                    idx++;
                }
            }
            return result;
        }
        function appendContent(tbody, table, html, empty) {
            var placeholder, tmp = tbody;
            if (empty) {
                tbody.empty();
            }
            if (tbodySupportsInnerHtml) {
                tbody[0].innerHTML = html;
            } else {
                placeholder = document.createElement('div');
                placeholder.innerHTML = '<table><tbody>' + html + '</tbody></table>';
                tbody = placeholder.firstChild.firstChild;
                table[0].replaceChild(tbody, tmp[0]);
                tbody = $(tbody);
            }
            return tbody;
        }
        function addHiddenStyle(attr) {
            attr = attr || {};
            var style = attr.style;
            if (!style) {
                style = 'display:none';
            } else {
                style = style.replace(/((.*)?display)(.*)?:([^;]*)/i, '$1:none');
                if (style === attr.style) {
                    style = style.replace(/(.*)?/i, 'display:none;$1');
                }
            }
            return extend({}, attr, { style: style });
        }
        function removeHiddenStyle(attr) {
            attr = attr || {};
            var style = attr.style;
            if (style) {
                attr.style = style.replace(/(display\s*:\s*none\s*;?)*/gi, '');
            }
            return attr;
        }
        function normalizeCols(table, visibleColumns, hasDetails, groups) {
            var colgroup = table.find('>colgroup'), width, cols = map(visibleColumns, function (column) {
                    width = column.width;
                    if (width && parseInt(width, 10) !== 0) {
                        return kendo.format('<col style="width:{0}"/>', typeof width === STRING ? width : width + 'px');
                    }
                    return '<col />';
                });
            if (hasDetails || colgroup.find('.k-hierarchy-col').length) {
                cols.splice(0, 0, '<col class="k-hierarchy-col" />');
            }
            if (colgroup.length) {
                colgroup.remove();
            }
            colgroup = $(new Array(groups + 1).join('<col class="k-group-col">') + cols.join(''));
            if (!colgroup.is('colgroup')) {
                colgroup = $('<colgroup/>').append(colgroup);
            }
            table.prepend(colgroup);
            if (browser.msie && browser.version == 8) {
                table.css('display', 'inline-table');
                window.setTimeout(function () {
                    table.css('display', '');
                }, 1);
            }
        }
        function normalizeHeaderCells(container, columns) {
            var lastIndex = 0;
            var idx, len;
            var th = container.find('th:not(.k-group-cell)');
            for (idx = 0, len = columns.length; idx < len; idx++) {
                if (columns[idx].locked) {
                    th.eq(idx).insertBefore(th.eq(lastIndex));
                    th = container.find('th:not(.k-group-cell)');
                    lastIndex++;
                }
            }
        }
        function convertToObject(array) {
            var result = {}, item, idx, length;
            for (idx = 0, length = array.length; idx < length; idx++) {
                item = array[idx];
                result[item.value] = item.text;
            }
            return result;
        }
        function formatGroupValue(value, format, columnValues, encoded) {
            var isForeignKey = columnValues && columnValues.length && isPlainObject(columnValues[0]) && 'value' in columnValues[0], groupValue = isForeignKey ? convertToObject(columnValues)[value] : value;
            groupValue = groupValue != null ? groupValue : '';
            return format ? kendo.format(format, groupValue) : encoded === false ? groupValue : kendo.htmlEncode(groupValue);
        }
        function setCellVisibility(cells, index, visible) {
            var pad = 0, state, cell = cells[pad];
            while (cell) {
                state = visible ? true : cell.style.display !== 'none';
                if (state && !nonDataCellsRegExp.test(cell.className) && --index < 0) {
                    cell.style.display = visible ? '' : 'none';
                    break;
                }
                cell = cells[++pad];
            }
        }
        function hideColumnCells(rows, columnIndex) {
            var idx = 0, length = rows.length, cell, row;
            for (; idx < length; idx += 1) {
                row = rows.eq(idx);
                if (row.is('.k-grouping-row,.k-detail-row')) {
                    cell = row.children(':not(.k-group-cell):first,.k-detail-cell').last();
                    cell.attr('colspan', parseInt(cell.attr('colspan'), 10) - 1);
                } else {
                    if (row.hasClass('k-grid-edit-row') && (cell = row.children('.k-edit-container')[0])) {
                        cell = $(cell);
                        cell.attr('colspan', parseInt(cell.attr('colspan'), 10) - 1);
                        cell.find('col').eq(columnIndex).remove();
                        row = cell.find('tr:first');
                    }
                    setCellVisibility(row[0].cells, columnIndex, false);
                }
            }
        }
        function groupRows(data) {
            var result = [];
            var item;
            for (var idx = 0; idx < data.length; idx++) {
                item = data[idx];
                if (!('field' in item && 'value' in item && 'items' in item)) {
                    break;
                }
                result.push(item);
                if (item.hasSubgroups) {
                    result = result.concat(groupRows(item.items));
                }
            }
            return result;
        }
        function groupFooters(data) {
            var result = [];
            var item;
            for (var idx = 0; idx < data.length; idx++) {
                item = data[idx];
                if (!('field' in item && 'value' in item && 'items' in item)) {
                    break;
                }
                if (item.hasSubgroups) {
                    result = result.concat(groupFooters(item.items));
                }
                result.push(item.aggregates);
            }
            return result;
        }
        function showColumnCells(rows, columnIndex) {
            var idx = 0, length = rows.length, cell, row, columns;
            for (; idx < length; idx += 1) {
                row = rows.eq(idx);
                if (row.is('.k-grouping-row,.k-detail-row')) {
                    cell = row.children(':not(.k-group-cell):first,.k-detail-cell').last();
                    cell.attr('colspan', parseInt(cell.attr('colspan'), 10) + 1);
                } else {
                    if (row.hasClass('k-grid-edit-row') && (cell = row.children('.k-edit-container')[0])) {
                        cell = $(cell);
                        cell.attr('colspan', parseInt(cell.attr('colspan'), 10) + 1);
                        normalizeCols(cell.find('>form>table'), visibleColumns(columns), false, 0);
                        row = cell.find('tr:first');
                    }
                    setCellVisibility(row[0].cells, columnIndex, true);
                }
            }
        }
        function updateColspan(toAdd, toRemove, num) {
            num = num || 1;
            var item, idx, length;
            for (idx = 0, length = toAdd.length; idx < length; idx++) {
                item = toAdd.eq(idx).children().last();
                item.attr('colspan', parseInt(item.attr('colspan'), 10) + num);
                item = toRemove.eq(idx).children().last();
                item.attr('colspan', parseInt(item.attr('colspan'), 10) - num);
            }
        }
        function tableWidth(table) {
            var idx, length, width = 0;
            var cols = table.find('>colgroup>col');
            for (idx = 0, length = cols.length; idx < length; idx += 1) {
                width += parseInt(cols[idx].style.width, 10);
            }
            return width;
        }
        var Grid = kendo.ui.DataBoundWidget.extend({
            init: function (element, options, events) {
                var that = this;
                options = isArray(options) ? { dataSource: options } : options;
                Widget.fn.init.call(that, element, options);
                if (events) {
                    that._events = events;
                }
                isRtl = kendo.support.isRtl(element);
                that._element();
                that._aria();
                that._columns(that.options.columns);
                that._dataSource();
                that._tbody();
                that._pageable();
                that._thead();
                that._groupable();
                that._toolbar();
                that._setContentHeight();
                that._templates();
                that._navigatable();
                that._selectable();
                that._clipboard();
                that._details();
                that._editable();
                that._attachCustomCommandsEvent();
                that._minScreenSupport();
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                } else {
                    that._group = that._groups() > 0;
                    that._footer();
                }
                if (that.lockedContent) {
                    that.wrapper.addClass('k-grid-lockedcolumns');
                    that._resizeHandler = function () {
                        that.resize();
                    };
                    $(window).on('resize' + NS, that._resizeHandler);
                }
                kendo.notify(that);
            },
            events: [
                CHANGE,
                'dataBinding',
                'cancel',
                DATABOUND,
                DETAILEXPAND,
                DETAILCOLLAPSE,
                DETAILINIT,
                FILTERMENUINIT,
                FILTERMENUOPEN,
                COLUMNMENUINIT,
                COLUMNMENUOPEN,
                EDIT,
                BEFOREEDIT,
                SAVE,
                REMOVE,
                SAVECHANGES,
                CELLCLOSE,
                COLUMNRESIZE,
                COLUMNREORDER,
                COLUMNSHOW,
                COLUMNHIDE,
                COLUMNLOCK,
                COLUMNUNLOCK,
                NAVIGATE,
                'page',
                'sort',
                'filter',
                'group'
            ],
            setDataSource: function (dataSource) {
                var that = this;
                var scrollable = that.options.scrollable;
                that.options.dataSource = dataSource;
                that._dataSource();
                that._pageable();
                that._thead();
                if (scrollable) {
                    if (scrollable.virtual) {
                        that.content.find('>.k-virtual-scrollable-wrap').scrollLeft(0);
                    } else {
                        that.content.scrollLeft(0);
                    }
                }
                if (that.options.groupable) {
                    that._groupable();
                }
                if (that.virtualScrollable) {
                    that.virtualScrollable.setDataSource(that.options.dataSource);
                }
                if (that.options.navigatable) {
                    that._navigatable();
                }
                if (that.options.selectable) {
                    that._selectable();
                }
                if (that.options.autoBind) {
                    dataSource.fetch();
                }
            },
            options: {
                name: 'Grid',
                columns: [],
                toolbar: null,
                autoBind: true,
                filterable: false,
                scrollable: true,
                sortable: false,
                selectable: false,
                allowCopy: false,
                navigatable: false,
                pageable: false,
                persistSelection: false,
                editable: false,
                groupable: false,
                rowTemplate: '',
                altRowTemplate: '',
                noRecords: false,
                dataSource: {},
                height: null,
                resizable: false,
                reorderable: false,
                columnMenu: false,
                detailTemplate: null,
                columnResizeHandleWidth: 3,
                mobile: '',
                messages: {
                    editable: {
                        cancelDelete: CANCELDELETE,
                        confirmation: DELETECONFIRM,
                        confirmDelete: CONFIRMDELETE
                    },
                    commands: {
                        create: defaultCommands.create.text,
                        cancel: defaultCommands.cancel.text,
                        save: defaultCommands.save.text,
                        destroy: defaultCommands.destroy.text,
                        edit: defaultCommands.edit.text,
                        update: defaultCommands.update.text,
                        canceledit: defaultCommands.canceledit.text,
                        excel: defaultCommands.excel.text,
                        pdf: defaultCommands.pdf.text
                    },
                    noRecords: NORECORDS,
                    expandCollapseColumnHeader: ''
                }
            },
            destroy: function () {
                var that = this, element;
                that._angularItems('cleanup');
                that._destroyColumnAttachments();
                Widget.fn.destroy.call(that);
                this._navigatableTables = null;
                if (that._resizeHandler) {
                    $(window).off('resize' + NS, that._resizeHandler);
                }
                if (that.pager && that.pager.element) {
                    that.pager.destroy();
                }
                that.pager = null;
                if (that.groupable && that.groupable.element) {
                    that.groupable.element.kendoGroupable('destroy');
                }
                that.groupable = null;
                if (that.options.reorderable) {
                    that.wrapper.data('kendoReorderable').destroy();
                }
                if (that.selectable && that.selectable.element) {
                    that.selectable.destroy();
                    that.clearArea();
                    if (that.options.persistSelection === true) {
                        that._selectedIds = null;
                    }
                    if (that.copyHandler) {
                        that.wrapper.off('keydown', that.copyHandler);
                        that.unbind(that.copyHandler);
                    }
                    if (that.updateClipBoardState) {
                        that.unbind(that.updateClipBoardState);
                        that.updateClipBoardState = null;
                    }
                    if (that.clearAreaHandler) {
                        that.wrapper.off('keyup', that.clearAreaHandler);
                    }
                }
                that.selectable = null;
                if (that.resizable) {
                    that.resizable.destroy();
                    if (that._resizeUserEvents) {
                        if (that._resizeHandleDocumentClickHandler) {
                            $(document).off('click', that._resizeHandleDocumentClickHandler);
                        }
                        that._resizeUserEvents.destroy();
                        that._resizeUserEvents = null;
                    }
                    that.resizable = null;
                }
                if (that.virtualScrollable && that.virtualScrollable.element) {
                    that.virtualScrollable.destroy();
                }
                that.virtualScrollable = null;
                that._destroyEditable();
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
                    that._refreshHandler = that._progressHandler = that._errorHandler = null;
                }
                element = that.element.add(that.wrapper).add(that.table).add(that.thead).add(that.wrapper.find('>.k-grid-toolbar'));
                if (that.content) {
                    element = element.add(that.content).add(that.content.find('>.k-virtual-scrollable-wrap'));
                }
                if (that.lockedHeader) {
                    that._removeLockedContainers();
                }
                if (that.pane) {
                    that.pane.destroy();
                }
                if (that.minScreenResizeHandler) {
                    $(window).off('resize', that.minScreenResizeHandler);
                }
                if (that._draggableInstance && that._draggableInstance.element) {
                    that._draggableInstance.destroy();
                }
                that._draggableInstance = null;
                element.off(NS);
                kendo.destroy(that.wrapper);
                that.rowTemplate = that.altRowTemplate = that.lockedRowTemplate = that.lockedAltRowTemplate = that.detailTemplate = that.footerTemplate = that.groupFooterTemplate = that.lockedGroupFooterTemplate = that.noRecordsTemplate = null;
                that.scrollables = that.thead = that.tbody = that.element = that.table = that.content = that.footer = that.wrapper = that.lockedTable = that.lockedContent = that.lockedHeader = that.lockedFooter = that._groupableClickHandler = that._setContentWidthHandler = null;
            },
            getOptions: function () {
                var options = this.options;
                options.dataSource = null;
                var result = extend(true, {}, this.options);
                result.columns = kendo.deepExtend([], this.columns);
                var dataSource = this.dataSource;
                var initialData = dataSource.options.data && dataSource._data;
                dataSource.options.data = null;
                result.dataSource = $.extend(true, {}, dataSource.options);
                dataSource.options.data = initialData;
                result.dataSource.data = initialData;
                result.dataSource.page = dataSource.page();
                result.dataSource.filter = dataSource.filter();
                result.dataSource.pageSize = dataSource.pageSize();
                result.dataSource.sort = dataSource.sort();
                result.dataSource.group = dataSource.group();
                result.dataSource.aggregate = dataSource.aggregate();
                if (result.dataSource.transport) {
                    result.dataSource.transport.dataSource = null;
                }
                if (result.pageable && result.pageable.pageSize) {
                    result.pageable.pageSize = dataSource.pageSize();
                }
                result.$angular = undefined;
                return result;
            },
            setOptions: function (options) {
                var currentOptions = this.getOptions();
                kendo.deepExtend(currentOptions, options);
                if (!options.dataSource) {
                    currentOptions.dataSource = this.dataSource;
                }
                var wrapper = this.wrapper;
                var events = this._events;
                var element = this.element;
                this.destroy();
                this.options = null;
                if (this._isMobile) {
                    var mobileWrapper = wrapper.closest(kendo.roleSelector('pane')).parent();
                    mobileWrapper.after(wrapper);
                    mobileWrapper.remove();
                    wrapper.removeClass('k-grid-mobile');
                }
                if (wrapper[0] !== element[0]) {
                    wrapper.before(element);
                    wrapper.remove();
                }
                element.empty();
                this.init(element, currentOptions, events);
                this._setEvents(currentOptions);
            },
            items: function () {
                if (this.lockedContent) {
                    return this._items(this.tbody).add(this._items(this.lockedTable.children('tbody')));
                } else {
                    return this._items(this.tbody);
                }
            },
            _items: function (container) {
                return container.children().filter(function () {
                    var tr = $(this);
                    return !tr.hasClass('k-grouping-row') && !tr.hasClass('k-detail-row') && !tr.hasClass('k-group-footer');
                });
            },
            dataItems: function () {
                var dataItems = kendo.ui.DataBoundWidget.fn.dataItems.call(this);
                if (this.lockedContent) {
                    var n = dataItems.length, tmp = new Array(2 * n);
                    for (var i = n; --i >= 0;) {
                        tmp[i] = tmp[i + n] = dataItems[i];
                    }
                    dataItems = tmp;
                }
                return dataItems;
            },
            _destroyColumnAttachments: function () {
                var that = this;
                that.resizeHandle = null;
                if (!that.thead) {
                    return;
                }
                this.angular('cleanup', function () {
                    return { elements: that.thead.get() };
                });
                that.thead.add(that.lockedHeader).find('th').each(function () {
                    var th = $(this), filterMenu = th.data('kendoFilterMenu'), sortable = th.data('kendoColumnSorter'), columnMenu = th.data('kendoColumnMenu');
                    if (filterMenu) {
                        filterMenu.destroy();
                    }
                    if (sortable) {
                        sortable.destroy();
                    }
                    if (columnMenu) {
                        columnMenu.destroy();
                    }
                });
            },
            _attachCustomCommandsEvent: function () {
                var that = this, columns = leafColumns(that.columns || []), command, idx, length;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    command = columns[idx].command;
                    if (command) {
                        attachCustomCommandEvent(that, that.wrapper, command);
                    }
                }
            },
            _aria: function () {
                var id = this.element.attr('id') || 'aria';
                if (id) {
                    this._cellId = id + '_active_cell';
                }
            },
            _element: function () {
                var that = this, table = that.element;
                if (!table.is('table')) {
                    if (that.options.scrollable) {
                        table = that.element.find('> .k-grid-content > table');
                    } else {
                        table = that.element.children('table');
                    }
                    if (!table.length) {
                        table = $('<table />').appendTo(that.element);
                    }
                }
                if (isIE7) {
                    table.attr('cellspacing', 0);
                }
                that.table = table.attr('role', that._hasDetails() ? 'treegrid' : 'grid');
                that._wrapper();
            },
            _createResizeHandle: function (container, th) {
                var that = this;
                var indicatorWidth = that.options.columnResizeHandleWidth;
                var scrollable = that.options.scrollable;
                var resizeHandle = that.resizeHandle;
                var groups = this._groups();
                var left;
                if (resizeHandle && that.lockedContent && resizeHandle.data('th')[0] !== th[0]) {
                    resizeHandle.off(NS).remove();
                    resizeHandle = null;
                }
                if (!resizeHandle) {
                    resizeHandle = that.resizeHandle = $('<div class="k-resize-handle"><div class="k-resize-handle-inner"></div></div>');
                    container.append(resizeHandle);
                }
                if (!isRtl) {
                    left = th[0].offsetWidth;
                    var cells = leafDataCells(th.closest('thead')).filter(':visible');
                    for (var idx = 0; idx < cells.length; idx++) {
                        if (cells[idx] == th[0]) {
                            break;
                        }
                        left += cells[idx].offsetWidth;
                    }
                    if (groups > 0) {
                        left += outerWidth(container.find('.k-group-cell:first')) * groups;
                    }
                    if (that._hasDetails()) {
                        left += outerWidth(container.find('.k-hierarchy-cell:first'));
                    }
                } else {
                    left = th.position().left;
                    if (scrollable) {
                        var headerWrap = th.closest('.k-grid-header-wrap, .k-grid-header-locked'), ieCorrection = browser.msie ? headerWrap.scrollLeft() : 0, webkitCorrection = browser.webkit ? headerWrap[0].scrollWidth - headerWrap[0].offsetWidth - headerWrap.scrollLeft() : 0, firefoxCorrection = browser.mozilla ? headerWrap[0].scrollWidth - headerWrap[0].offsetWidth - (headerWrap[0].scrollWidth - headerWrap[0].offsetWidth - headerWrap.scrollLeft()) : 0;
                        left -= webkitCorrection - firefoxCorrection + ieCorrection;
                    }
                }
                resizeHandle.css({
                    top: th.position().top,
                    left: left - indicatorWidth,
                    height: outerHeight(th),
                    width: indicatorWidth * 3
                }).data('th', th).show();
                resizeHandle.off('dblclick' + NS).on('dblclick' + NS, function () {
                    that._autoFitLeafColumn(th.data('index'));
                });
            },
            _positionColumnResizeHandle: function () {
                var that = this, indicatorWidth = that.options.columnResizeHandleWidth, lockedHead = that.lockedHeader ? that.lockedHeader.find('thead:first') : $();
                that.thead.add(lockedHead).on('mousemove' + NS, 'th', function (e) {
                    var th = $(this);
                    if (th.hasClass('k-group-cell') || th.hasClass('k-hierarchy-cell')) {
                        return;
                    }
                    function getPageZoomStyle() {
                        var docZoom = parseFloat($(document.documentElement).css('zoom'));
                        if (isNaN(docZoom)) {
                            docZoom = 1;
                        }
                        var bodyZoom = parseFloat($(document.body).css('zoom'));
                        if (isNaN(bodyZoom)) {
                            bodyZoom = 1;
                        }
                        return docZoom * bodyZoom;
                    }
                    var clientX = e.clientX / getPageZoomStyle(), winScrollLeft = $(window).scrollLeft(), position = th.offset().left + (!isRtl ? this.offsetWidth : 0);
                    if (clientX + winScrollLeft > position - indicatorWidth && clientX + winScrollLeft < position + indicatorWidth) {
                        that._createResizeHandle(th.closest('div'), th);
                    } else if (that.resizeHandle) {
                        that.resizeHandle.hide();
                    } else {
                        cursor(that.wrapper, '');
                    }
                });
            },
            _resizeHandleDocumentClick: function (e) {
                if ($(e.target).closest('.k-column-active').length) {
                    return;
                }
                $(document).off(e);
                this._hideResizeHandle();
            },
            _hideResizeHandle: function () {
                if (this.resizeHandle) {
                    this.resizeHandle.data('th').removeClass('k-column-active');
                    if (this.lockedContent && !this._isMobile) {
                        this.resizeHandle.off(NS).remove();
                        this.resizeHandle = null;
                    } else {
                        this.resizeHandle.hide();
                    }
                }
            },
            _positionColumnResizeHandleTouch: function () {
                var that = this, lockedHead = that.lockedHeader ? that.lockedHeader.find('thead:first') : $();
                that._resizeUserEvents = new kendo.UserEvents(lockedHead.add(that.thead), {
                    filter: 'th:not(.k-group-cell):not(.k-hierarchy-cell)',
                    threshold: 10,
                    hold: function (e) {
                        var th = $(e.target);
                        e.preventDefault();
                        th.addClass('k-column-active');
                        that._createResizeHandle(th.closest('div'), th);
                        if (!that._resizeHandleDocumentClickHandler) {
                            that._resizeHandleDocumentClickHandler = proxy(that._resizeHandleDocumentClick, that);
                        }
                        $(document).on('click', that._resizeHandleDocumentClickHandler);
                    }
                });
            },
            _resizable: function () {
                var that = this, options = that.options, container, columnStart, columnWidth, columnMinWidth, gridWidth, isMobile = this._isMobile, scrollbar = !kendo.support.mobileOS ? kendo.support.scrollbar() : 0, isLocked, col, th;
                if (options.resizable) {
                    container = options.scrollable ? that.wrapper.find('.k-grid-header-wrap:first') : that.wrapper;
                    if (isMobile) {
                        that._positionColumnResizeHandleTouch(container);
                    } else {
                        that._positionColumnResizeHandle(container);
                    }
                    if (that.resizable) {
                        that.resizable.destroy();
                    }
                    that.resizable = new ui.Resizable(container.add(that.lockedHeader), {
                        handle: (!!options.scrollable ? '' : '>') + '.k-resize-handle',
                        hint: function (handle) {
                            return $('<div class="k-grid-resize-indicator" />').css({ height: outerHeight(handle.data('th')) + that.tbody.attr('clientHeight') });
                        },
                        start: function (e) {
                            th = $(e.currentTarget).data('th');
                            if (isMobile) {
                                that._hideResizeHandle();
                            }
                            var header = th.closest('table'), index = $.inArray(th[0], leafDataCells(th.closest('thead')).filter(':visible'));
                            isLocked = header.parent().hasClass('k-grid-header-locked');
                            var contentTable = isLocked ? that.lockedTable : that.table, footer = that.footer || $();
                            if (that.footer && that.lockedContent) {
                                footer = isLocked ? that.footer.children('.k-grid-footer-locked') : that.footer.children('.k-grid-footer-wrap');
                            }
                            cursor(that.wrapper, 'col-resize');
                            if (options.scrollable) {
                                col = header.find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')').add(contentTable.children('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')')).add(footer.find('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')'));
                            } else {
                                col = contentTable.children('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')');
                            }
                            columnStart = e.x.location;
                            columnWidth = outerWidth(th);
                            columnMinWidth = leafColumns(that.columns)[index].minResizableWidth || 10;
                            gridWidth = isLocked ? outerWidth(contentTable.children('tbody')) : outerWidth(that.tbody);
                            if (browser.webkit) {
                                that.wrapper.addClass('k-grid-column-resizing');
                            }
                        },
                        resize: function (e) {
                            var rtlMultiplier = isRtl ? -1 : 1, currentWidth = columnWidth + e.x.location * rtlMultiplier - columnStart * rtlMultiplier;
                            if (options.scrollable) {
                                var footer;
                                if (isLocked && that.lockedFooter) {
                                    footer = that.lockedFooter.children('table');
                                } else if (that.footer) {
                                    footer = that.footer.find('>.k-grid-footer-wrap>table');
                                }
                                if (!footer || !footer[0]) {
                                    footer = $();
                                }
                                var header = th.closest('table');
                                var contentTable = isLocked ? that.lockedTable : that.table;
                                var constrain = false;
                                var totalWidth = that.wrapper.width() - scrollbar;
                                var width = currentWidth;
                                if (isLocked && gridWidth - columnWidth + width > totalWidth) {
                                    width = columnWidth + (totalWidth - gridWidth - scrollbar * 2);
                                    if (width < 0) {
                                        width = currentWidth;
                                    }
                                    constrain = true;
                                }
                                if (width > 10 && width >= columnMinWidth) {
                                    col.css('width', width);
                                    if (gridWidth) {
                                        if (constrain) {
                                            width = totalWidth - scrollbar * 2;
                                        } else {
                                            width = gridWidth + e.x.location * rtlMultiplier - columnStart * rtlMultiplier;
                                        }
                                        contentTable.add(header).add(footer).css('width', width);
                                        if (!isLocked) {
                                            that._footerWidth = width;
                                        }
                                    }
                                }
                            } else if (currentWidth > 10 && currentWidth >= columnMinWidth) {
                                col.css('width', currentWidth);
                            }
                        },
                        resizeend: function () {
                            var newWidth = outerWidth(th), column, header;
                            cursor(that.wrapper, '');
                            if (browser.webkit) {
                                that.wrapper.removeClass('k-grid-column-resizing');
                            }
                            if (columnWidth != newWidth) {
                                header = that.lockedHeader ? that.lockedHeader.find('thead:first tr:first').add(that.thead.find('tr:first')) : th.parent();
                                var index = th.attr(kendo.attr('index'));
                                if (!index) {
                                    index = header.find('th:not(.k-group-cell):not(.k-hierarchy-cell)').index(th);
                                }
                                column = leafColumns(that.columns)[index];
                                column.width = newWidth;
                                that.trigger(COLUMNRESIZE, {
                                    column: column,
                                    oldWidth: columnWidth,
                                    newWidth: newWidth
                                });
                                that._applyLockedContainersWidth();
                                that._syncLockedContentHeight();
                                that._syncLockedHeaderHeight();
                            }
                            that._hideResizeHandle();
                            th = null;
                        }
                    });
                }
            },
            _draggable: function () {
                var that = this;
                if (that.options.reorderable) {
                    if (that._draggableInstance) {
                        that._draggableInstance.destroy();
                    }
                    var header = that.wrapper.children('.k-grid-header');
                    that._draggableInstance = that.wrapper.kendoDraggable({
                        group: kendo.guid(),
                        autoScroll: true,
                        filter: that.content ? '.k-grid-header:first ' + HEADERCELLS : 'table:first>.k-grid-header ' + HEADERCELLS,
                        dragstart: function () {
                            header.children('.k-grid-header-wrap').unbind('scroll' + NS + 'scrolling').bind('scroll' + NS + 'scrolling', function (e) {
                                if (that.virtualScrollable) {
                                    that.content.find('>.k-virtual-scrollable-wrap').scrollLeft(this.scrollLeft);
                                } else {
                                    that.scrollables.not(e.currentTarget).scrollLeft(this.scrollLeft);
                                }
                            });
                        },
                        dragend: function () {
                            header.children('.k-grid-header-wrap').unbind('scroll' + NS + 'scrolling');
                        },
                        drag: function () {
                            that._hideResizeHandle();
                        },
                        hint: function (target) {
                            var title = target.attr(kendo.attr('title'));
                            if (title) {
                                title = kendo.htmlEncode(title);
                            }
                            return $('<div class="k-header k-drag-clue" />').css({
                                width: target.width(),
                                paddingLeft: target.css('paddingLeft'),
                                paddingRight: target.css('paddingRight'),
                                lineHeight: target.height() + 'px',
                                paddingTop: target.css('paddingTop'),
                                paddingBottom: target.css('paddingBottom')
                            }).html(title || target.attr(kendo.attr('field')) || target.text()).prepend('<span class="k-icon k-drag-status k-i-cancel" />');
                        }
                    }).data('kendoDraggable');
                }
            },
            _reorderable: function () {
                var that = this;
                if (that.options.reorderable) {
                    if (that.wrapper.data('kendoReorderable')) {
                        that.wrapper.data('kendoReorderable').destroy();
                    }
                    var targetParentContainerIndex = function (columns, sourceIndex, targetIndex) {
                        var column = columns[sourceIndex];
                        var target = columns[targetIndex];
                        var parent = columnParent(column, that.columns);
                        columns = parent ? parent.columns : that.columns;
                        return inArray(target, columns);
                    };
                    that.wrapper.kendoReorderable({
                        draggable: that._draggableInstance,
                        dragOverContainers: function (sourceIndex, targetIndex) {
                            var columns = flatColumnsInDomOrder(that.columns);
                            return columns[sourceIndex].lockable !== false && targetParentContainerIndex(columns, sourceIndex, targetIndex) > -1;
                        },
                        inSameContainer: function (e) {
                            return $(e.source).parent()[0] === $(e.target).parent()[0] && targetParentContainerIndex(flatColumnsInDomOrder(that.columns), e.sourceIndex, e.targetIndex) > -1;
                        },
                        change: function (e) {
                            var columns = flatColumnsInDomOrder(that.columns);
                            var column = columns[e.oldIndex];
                            var newIndex = targetParentContainerIndex(columns, e.oldIndex, e.newIndex);
                            that.trigger(COLUMNREORDER, {
                                newIndex: newIndex,
                                oldIndex: inArray(column, columns),
                                column: column
                            });
                            that.reorderColumn(newIndex, column, e.position === 'before');
                        }
                    });
                }
            },
            _reorderHeader: function (sources, target, before) {
                var that = this;
                var sourcePosition = columnPosition(sources[0], that.columns);
                var destPosition = columnPosition(target, that.columns);
                var leafs = [];
                for (var idx = 0; idx < sources.length; idx++) {
                    if (sources[idx].columns) {
                        leafs = leafs.concat(sources[idx].columns);
                    }
                }
                var ths = elements(that.lockedHeader, that.thead, 'tr:eq(' + sourcePosition.row + ')>th.k-header:not(.k-group-cell,.k-hierarchy-cell)');
                var sourceLockedColumns = lockedColumns(sources).length;
                var targetLockedColumns = lockedColumns([target]).length;
                if (leafs.length) {
                    if (sourceLockedColumns > 0 && targetLockedColumns === 0) {
                        moveCellsBetweenContainers(sources, target, leafs, that.columns, that.lockedHeader.find('thead'), that.thead, this._groups());
                    } else if (sourceLockedColumns === 0 && targetLockedColumns > 0) {
                        moveCellsBetweenContainers(sources, target, leafs, that.columns, that.thead, that.lockedHeader.find('thead'), this._groups());
                    }
                    if (target.columns || sourcePosition.cell - destPosition.cell > 1 || destPosition.cell - sourcePosition.cell > 1) {
                        target = findReorderTarget(that.columns, target, sources[0], before);
                        if (target) {
                            that._reorderHeader(leafs, target, before);
                        }
                    }
                } else if (sourceLockedColumns !== targetLockedColumns) {
                    updateCellRowSpan(ths[sourcePosition.cell], that.columns, sourceLockedColumns);
                }
                reorder(ths, sourcePosition.cell, destPosition.cell, before, sources.length);
            },
            _reorderContent: function (sources, destination, before) {
                var that = this;
                var lockedRows = $();
                var source = sources[0];
                var visibleSources = visibleColumns(sources);
                var sourceIndex = inArray(source, leafColumns(that.columns));
                var destIndex = inArray(destination, leafColumns(that.columns));
                var colSourceIndex = inArray(source, visibleLeafColumns(that.columns));
                var colDest = inArray(destination, visibleLeafColumns(that.columns));
                var lockedCount = lockedColumns(that.columns).length;
                var isLocked = !!destination.locked;
                var footer = that.footer || that.wrapper.find('.k-grid-footer');
                var headerCol, footerCol;
                headerCol = footerCol = colDest;
                if (destination.hidden) {
                    if (isLocked) {
                        colDest = that.lockedTable.find('colgroup');
                        headerCol = that.lockedHeader.find('colgroup');
                        footerCol = $(that.lockedFooter).find('>table>colgroup');
                    } else {
                        colDest = that.tbody.prev();
                        headerCol = that.thead.prev();
                        footerCol = footer.find('.k-grid-footer-wrap').find('>table>colgroup');
                    }
                }
                if (that._hasFilterRow()) {
                    reorder(that.wrapper.find('.k-filter-row th:not(.k-group-cell,.k-hierarchy-cell)'), sourceIndex, destIndex, before, sources.length);
                }
                reorder(elements(that.lockedHeader, that.thead.prev(), 'col:not(.k-group-col,.k-hierarchy-col)'), colSourceIndex, headerCol, before, visibleSources.length);
                if (that.options.scrollable) {
                    reorder(elements(that.lockedTable, that.tbody.prev(), 'col:not(.k-group-col,.k-hierarchy-col)'), colSourceIndex, colDest, before, visibleSources.length);
                }
                if (footer && footer.length) {
                    reorder(elements(that.lockedFooter, footer.find('.k-grid-footer-wrap'), '>table>colgroup>col:not(.k-group-col,.k-hierarchy-col)'), colSourceIndex, footerCol, before, visibleSources.length);
                    reorder(footer.find('.k-footer-template>td:not(.k-group-cell,.k-hierarchy-cell)'), sourceIndex, destIndex, before, sources.length);
                }
                var rows = that.tbody.children(':not(.k-grouping-row,.k-detail-row)');
                if (that.lockedTable) {
                    if (lockedCount > destIndex) {
                        if (lockedCount <= sourceIndex) {
                            updateColspan(that.lockedTable.find('>tbody>tr.k-grouping-row'), that.table.find('>tbody>tr.k-grouping-row'), sources.length);
                        }
                    } else if (lockedCount > sourceIndex) {
                        updateColspan(that.table.find('>tbody>tr.k-grouping-row'), that.lockedTable.find('>tbody>tr.k-grouping-row'), sources.length);
                    }
                    lockedRows = that.lockedTable.find('>tbody>tr:not(.k-grouping-row,.k-detail-row)');
                }
                for (var idx = 0, length = rows.length; idx < length; idx += 1) {
                    reorder(elements(lockedRows[idx], rows[idx], '>td:not(.k-group-cell,.k-hierarchy-cell)'), sourceIndex, destIndex, before, sources.length);
                }
            },
            _autoFitLeafColumn: function (leafIndex) {
                this.autoFitColumn(leafColumns(this.columns)[leafIndex]);
            },
            autoFitColumn: function (column) {
                var that = this, options = that.options, columns = that.columns, index, th, headerTable, isLocked, visibleLocked = that.lockedHeader ? leafDataCells(that.lockedHeader.find('>table>thead')).filter(isCellVisible).length : 0, col, contentDiv, scrollLeft, notGroupOrHierarchyCol = 'col:not(.k-group-col):not(.k-hierarchy-col)', notGroupOrHierarchyVisibleCell = 'td:visible:not(.k-group-cell):not(.k-hierarchy-cell)';
                if (typeof column == 'number') {
                    column = columns[column];
                } else if (isPlainObject(column)) {
                    column = grep(flatColumns(columns), function (item) {
                        return item === column;
                    })[0];
                } else {
                    column = grep(flatColumns(columns), function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || !isVisible(column)) {
                    return;
                }
                index = inArray(column, leafColumns(columns));
                isLocked = column.locked;
                if (isLocked) {
                    headerTable = that.lockedHeader.children('table');
                } else {
                    headerTable = that.thead.parent();
                }
                th = headerTable.find('[data-index=\'' + index + '\']');
                var contentTable = isLocked ? that.lockedTable : that.table, footer = that.footer || $();
                if (that.footer && that.lockedContent) {
                    footer = isLocked ? that.footer.children('.k-grid-footer-locked') : that.footer.children('.k-grid-footer-wrap');
                }
                var footerTable = footer.find('table').first();
                if (that.lockedHeader && !isLocked) {
                    index -= visibleLocked;
                }
                for (var j = 0; j < columns.length; j++) {
                    if (columns[j] === column) {
                        break;
                    } else {
                        if (columns[j].hidden) {
                            index--;
                        }
                    }
                }
                if (options.scrollable) {
                    col = headerTable.find(notGroupOrHierarchyCol).eq(index).add(contentTable.children('colgroup').find(notGroupOrHierarchyCol).eq(index)).add(footerTable.find('colgroup').find(notGroupOrHierarchyCol).eq(index));
                    if (!isLocked) {
                        contentDiv = contentTable.parent();
                        scrollLeft = contentDiv.scrollLeft();
                    }
                } else {
                    col = contentTable.children('colgroup').find(notGroupOrHierarchyCol).eq(index);
                }
                var tables = headerTable.add(contentTable).add(footerTable);
                var oldColumnWidth = outerWidth(th);
                col.width('');
                tables.css('table-layout', 'fixed');
                col.width('auto');
                tables.addClass('k-autofitting');
                tables.css('table-layout', '');
                var newColumnWidth = Math.ceil(Math.max(outerWidth(th), outerWidth(contentTable.find('tr:not(.k-grouping-row)').eq(0).children(notGroupOrHierarchyVisibleCell).eq(index)), outerWidth(footerTable.find('tr').eq(0).children(notGroupOrHierarchyVisibleCell).eq(index)))) + 1;
                col.width(newColumnWidth);
                column.width = newColumnWidth;
                if (options.scrollable) {
                    var cols = headerTable.find('col'), colWidth, totalWidth = 0;
                    for (var idx = 0, length = cols.length; idx < length; idx += 1) {
                        colWidth = cols[idx].style.width;
                        if (colWidth && colWidth.indexOf('%') == -1) {
                            totalWidth += parseInt(colWidth, 10);
                        } else {
                            totalWidth = 0;
                            break;
                        }
                    }
                    if (totalWidth) {
                        tables.each(function () {
                            this.style.width = totalWidth + 'px';
                        });
                    }
                }
                if (browser.msie && browser.version == 8) {
                    tables.css('display', 'inline-table');
                    setTimeout(function () {
                        tables.css('display', 'table');
                    }, 1);
                }
                tables.removeClass('k-autofitting');
                if (scrollLeft) {
                    contentDiv.scrollLeft(scrollLeft);
                }
                that.trigger(COLUMNRESIZE, {
                    column: column,
                    oldWidth: oldColumnWidth,
                    newWidth: newColumnWidth
                });
                that._applyLockedContainersWidth();
                that._syncLockedContentHeight();
                that._syncLockedHeaderHeight();
            },
            reorderColumn: function (destIndex, column, before) {
                var that = this, parent = columnParent(column, that.columns), columns = parent ? parent.columns : that.columns, sourceIndex = inArray(column, columns), destColumn = columns[destIndex], lockChanged, isLocked = !!destColumn.locked, lockedCount = lockedColumns(that.columns).length;
                if (sourceIndex === destIndex) {
                    return;
                }
                if (!column.locked && isLocked && nonLockedColumns(that.columns).length == 1) {
                    return;
                }
                if (column.locked && !isLocked && lockedCount == 1) {
                    return;
                }
                that._hideResizeHandle();
                if (before === undefined) {
                    before = destIndex < sourceIndex;
                }
                var sourceColumns = [column];
                that._reorderHeader(sourceColumns, destColumn, before);
                if (that.lockedHeader) {
                    removeEmptyRows(that.thead);
                    removeEmptyRows(that.lockedHeader);
                }
                if (destColumn.columns) {
                    destColumn = leafColumns(destColumn.columns);
                    destColumn = destColumn[before ? 0 : destColumn.length - 1];
                }
                if (column.columns) {
                    sourceColumns = leafColumns(column.columns);
                }
                that._reorderContent(sourceColumns, destColumn, before);
                lockChanged = !!column.locked;
                lockChanged = lockChanged != isLocked;
                column.locked = isLocked;
                columns.splice(before ? destIndex : destIndex + 1, 0, column);
                columns.splice(sourceIndex < destIndex ? sourceIndex : sourceIndex + 1, 1);
                that._templates();
                that._updateColumnCellIndex();
                that._updateTablesWidth();
                that._applyLockedContainersWidth();
                that._syncLockedHeaderHeight();
                that._syncLockedContentHeight();
                that._updateFirstColumnClass();
                if (!lockChanged) {
                    return;
                }
                if (isLocked) {
                    that.trigger(COLUMNLOCK, { column: column });
                } else {
                    that.trigger(COLUMNUNLOCK, { column: column });
                }
            },
            _updateColumnCellIndex: function () {
                var header;
                var offset = 0;
                if (this.lockedHeader) {
                    header = this.lockedHeader.find('thead');
                    offset = updateCellIndex(header, lockedColumns(this.columns));
                }
                updateCellIndex(this.thead, nonLockedColumns(this.columns), offset);
            },
            lockColumn: function (column) {
                var columns = this.columns;
                if (typeof column == 'number') {
                    column = columns[column];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || column.locked || column.hidden) {
                    return;
                }
                var index = lockedColumns(columns).length - 1;
                this.reorderColumn(index, column, false);
            },
            unlockColumn: function (column) {
                var columns = this.columns;
                if (typeof column == 'number') {
                    column = columns[column];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || !column.locked || column.hidden) {
                    return;
                }
                var index = lockedColumns(columns).length;
                this.reorderColumn(index, column, true);
            },
            cellIndex: function (td) {
                var lockedColumnOffset = 0;
                if (this.lockedTable && !$.contains(this.lockedTable[0], td[0])) {
                    lockedColumnOffset = leafColumns(lockedColumns(this.columns)).length;
                }
                return $(td).parent().children('td:not(.k-group-cell,.k-hierarchy-cell)').index(td) + lockedColumnOffset;
            },
            _modelForContainer: function (container) {
                container = $(container);
                if (!container.is('tr') && this._editMode() !== 'popup') {
                    container = container.closest('tr');
                }
                var id = container.attr(kendo.attr('uid'));
                return this.dataSource.getByUid(id);
            },
            _editable: function () {
                var that = this, selectable = that.selectable && that.selectable.options.multiple, editable = that.options.editable, handler = function () {
                        var target = activeElement(), cell = that._editContainer;
                        if (cell && !$.contains(cell[0], target) && cell[0] !== target && !$(target).closest('.k-animation-container').length) {
                            if (that.editable.end()) {
                                that.closeCell();
                            }
                        }
                    };
                if (editable) {
                    this.wrapper.addClass('k-editable');
                    var mode = that._editMode();
                    if (mode === 'incell') {
                        if (editable.update !== false) {
                            that.wrapper.on(CLICK + NS, 'tr:not(.k-grouping-row) > td', function (e) {
                                var td = $(this), isLockedCell = that.lockedTable && td.closest('table')[0] === that.lockedTable[0];
                                if (td.hasClass('k-hierarchy-cell') || td.hasClass('k-detail-cell') || td.hasClass('k-group-cell') || td.hasClass('k-edit-cell') || td.has('a.k-grid-delete').length || td.has('button.k-grid-delete').length || td.closest('tbody')[0] !== that.tbody[0] && !isLockedCell || $(e.target).is(':input')) {
                                    return;
                                }
                                if (that.editable) {
                                    if (that.editable.end()) {
                                        if (selectable) {
                                            $(activeElement()).blur();
                                        }
                                        that.closeCell();
                                        that.editCell(td);
                                    }
                                } else {
                                    that.editCell(td);
                                }
                            }).on('focusin' + NS, function () {
                                if (!$.contains(this, activeElement())) {
                                    clearTimeout(that.timer);
                                    that.timer = null;
                                }
                            }).on('focusout' + NS, function () {
                                that.timer = setTimeout(handler, 1);
                            });
                        }
                    } else {
                        if (editable.update !== false) {
                            that.wrapper.on(CLICK + NS, 'tbody>tr:not(.k-detail-row,.k-grouping-row):visible a.k-grid-edit', function (e) {
                                e.preventDefault();
                                that.editRow($(this).closest('tr'));
                            });
                        }
                    }
                    if (editable.destroy !== false) {
                        that.wrapper.on(CLICK + NS, 'tbody>tr:not(.k-detail-row,.k-grouping-row):visible .k-grid-delete', function (e) {
                            e.preventDefault();
                            e.stopPropagation();
                            that.removeRow($(this).closest('tr'));
                        });
                    } else {
                        that.wrapper.on(CLICK + NS, 'tbody>tr:not(.k-detail-row,.k-grouping-row):visible button.k-grid-delete', function (e) {
                            e.stopPropagation();
                            if (!that._confirmation()) {
                                e.preventDefault();
                            }
                        });
                    }
                }
            },
            editCell: function (cell) {
                cell = $(cell);
                var that = this, column = leafColumns(that.columns)[that.cellIndex(cell)], model = that._modelForContainer(cell);
                that.closeCell();
                if (model && isColumnEditable(column, model) && !column.command) {
                    if (that.trigger(BEFOREEDIT, { model: model })) {
                        return;
                    }
                    that._attachModelChange(model);
                    that._editContainer = cell;
                    that.editable = cell.addClass('k-edit-cell').kendoEditable({
                        fields: {
                            field: column.field,
                            format: column.format,
                            editor: column.editor,
                            values: column.values
                        },
                        model: model,
                        target: that,
                        change: function (e) {
                            if (that.trigger(SAVE, {
                                    values: e.values,
                                    container: cell,
                                    model: model
                                })) {
                                e.preventDefault();
                            }
                        }
                    }).data('kendoEditable');
                    var tr = cell.parent().addClass('k-grid-edit-row');
                    if (that.lockedContent) {
                        adjustRowHeight(tr[0], that._relatedRow(tr).addClass('k-grid-edit-row')[0]);
                    }
                    that.trigger(EDIT, {
                        container: cell,
                        model: model
                    });
                }
            },
            _adjustLockedHorizontalScrollBar: function () {
                var table = this.table, content = table.parent();
                var scrollbar = table[0].offsetWidth > content[0].clientWidth ? kendo.support.scrollbar() : 0;
                this.lockedContent.height(content.height() - scrollbar);
            },
            _syncLockedContentHeight: function () {
                if (this.lockedTable) {
                    if (!this.touchScroller) {
                        this._adjustLockedHorizontalScrollBar();
                    }
                    this._adjustRowsHeight(this.table, this.lockedTable);
                }
            },
            _syncLockedHeaderHeight: function () {
                if (this.lockedHeader) {
                    var lockedTable = this.lockedHeader.children('table');
                    var table = this.thead.parent();
                    this._adjustRowsHeight(lockedTable, table);
                    syncTableHeight(lockedTable, table);
                }
            },
            _syncLockedFooterHeight: function () {
                if (this.lockedFooter && this.footer && this.footer.length) {
                    this._adjustRowsHeight(this.lockedFooter.children('table'), this.footer.find('.k-grid-footer-wrap > table'));
                }
            },
            _destroyEditable: function () {
                var that = this;
                var destroy = function () {
                    if (that.editable) {
                        var container = that.editView ? that.editView.element : that._editContainer;
                        if (container) {
                            container.off(CLICK + NS, 'a.k-grid-cancel', that._editCancelClickHandler);
                            container.off(CLICK + NS, 'a.k-grid-update', that._editUpdateClickHandler);
                        }
                        that._detachModelChange();
                        that.editable.destroy();
                        that.editable = null;
                        that._editContainer = null;
                        that._destroyEditView();
                    }
                };
                if (that.editable) {
                    if (that._editMode() === 'popup' && !that._isMobile) {
                        that._editContainer.data('kendoWindow').bind('deactivate', destroy).close();
                    } else {
                        destroy();
                    }
                }
                if (that._actionSheet) {
                    that._actionSheet.destroy();
                    that._actionSheet = null;
                }
            },
            _destroyEditView: function () {
                if (this.editView) {
                    this.editView.purge();
                    this.editView = null;
                    this.pane.navigate('');
                }
            },
            _attachModelChange: function (model) {
                var that = this;
                that._modelChangeHandler = function (e) {
                    that._modelChange({
                        field: e.field,
                        model: this
                    });
                };
                model.bind('change', that._modelChangeHandler);
            },
            _detachModelChange: function () {
                var that = this, container = that._editContainer, model = that._modelForContainer(container);
                if (model) {
                    model.unbind(CHANGE, that._modelChangeHandler);
                }
            },
            closeCell: function (isCancel) {
                var that = this, cell = that._editContainer, id, column, tr, model;
                if (!cell) {
                    return;
                }
                id = cell.closest('tr').attr(kendo.attr('uid'));
                model = that.dataSource.getByUid(id);
                if (isCancel && that.trigger('cancel', {
                        container: cell,
                        model: model
                    })) {
                    return;
                }
                that.trigger(CELLCLOSE, {
                    type: isCancel ? 'cancel' : 'save',
                    model: model,
                    container: cell
                });
                cell.removeClass('k-edit-cell');
                column = leafColumns(that.columns)[that.cellIndex(cell)];
                tr = cell.parent().removeClass('k-grid-edit-row');
                that._destroyEditable();
                that._displayCell(cell, column, model);
                if (cell.hasClass('k-dirty-cell')) {
                    $('<span class="k-dirty"/>').prependTo(cell);
                }
                that.trigger('itemChange', {
                    item: tr,
                    data: model,
                    ns: ui
                });
                if (that.lockedContent) {
                    adjustRowHeight(tr.css('height', '')[0], that._relatedRow(tr).css('height', '')[0]);
                }
            },
            _displayCell: function (cell, column, dataItem) {
                var that = this, state = {
                        storage: {},
                        count: 0
                    }, settings = extend({}, kendo.Template, that.options.templateSettings), tmpl = kendo.template(that._cellTmpl(column, state), settings);
                if (state.count > 0) {
                    tmpl = proxy(tmpl, state.storage);
                }
                cell.empty().html(tmpl(dataItem));
                that.angular('compile', function () {
                    return {
                        elements: cell,
                        data: [{ dataItem: dataItem }]
                    };
                });
            },
            removeRow: function (row) {
                if (!this._confirmation(row)) {
                    return;
                }
                this._removeRow(row);
            },
            _removeRow: function (row) {
                var that = this, model, mode = that._editMode();
                if (mode !== 'incell') {
                    that.cancelRow();
                }
                row = $(row);
                if (that.lockedContent) {
                    row = row.add(that._relatedRow(row));
                }
                row = row.hide();
                model = that._modelForContainer(row);
                if (model && !that.trigger(REMOVE, {
                        row: row,
                        model: model
                    })) {
                    that.dataSource.remove(model);
                    if (mode === 'inline' || mode === 'popup') {
                        that.dataSource.sync();
                    }
                } else if (mode === 'incell') {
                    that._destroyEditable();
                }
            },
            _editMode: function () {
                var mode = 'incell', editable = this.options.editable;
                if (editable !== true) {
                    if (typeof editable == 'string') {
                        mode = editable;
                    } else {
                        mode = editable.mode || mode;
                    }
                }
                return mode;
            },
            editRow: function (row) {
                var model;
                var that = this;
                if (row instanceof kendo.data.ObservableObject) {
                    model = row;
                } else {
                    row = $(row);
                    model = that._modelForContainer(row);
                }
                var mode = that._editMode();
                var container;
                that.cancelRow();
                if (model) {
                    row = that.tbody.children('[' + kendo.attr('uid') + '=' + model.uid + ']');
                    that._attachModelChange(model);
                    if (mode === 'popup') {
                        that._createPopupEditor(model);
                    } else if (mode === 'inline') {
                        that._createInlineEditor(row, model);
                    } else if (mode === 'incell') {
                        $(row).children(DATA_CELL).each(function () {
                            var cell = $(this);
                            var column = leafColumns(that.columns)[that.cellIndex(cell)];
                            model = that._modelForContainer(cell);
                            if (model && (!model.editable || model.editable(column.field)) && column.field) {
                                that.editCell(cell);
                                return false;
                            }
                        });
                    }
                    container = that.editView ? that.editView.element : that._editContainer;
                    if (container) {
                        if (!this._editCancelClickHandler) {
                            this._editCancelClickHandler = proxy(this._editCancelClick, this);
                        }
                        container.on(CLICK + NS, 'a.k-grid-cancel', this._editCancelClickHandler);
                        if (!this._editUpdateClickHandler) {
                            this._editUpdateClickHandler = proxy(this._editUpdateClick, this);
                        }
                        container.on(CLICK + NS, 'a.k-grid-update', this._editUpdateClickHandler);
                    }
                }
            },
            _editUpdateClick: function (e) {
                e.preventDefault();
                e.stopPropagation();
                this.saveRow();
            },
            _editCancelClick: function (e) {
                var that = this;
                var navigatable = that.options.navigatable;
                var model = that.editable.options.model;
                var container = that.editView ? that.editView.element : that._editContainer;
                e.preventDefault();
                e.stopPropagation();
                if (that.trigger('cancel', {
                        container: container,
                        model: model
                    })) {
                    return;
                }
                var currentIndex = that.items().index($(that.current()).parent());
                that.cancelRow();
                if (navigatable) {
                    that._setCurrent(that.items().eq(currentIndex).children().filter(NAVCELL).first());
                    focusTable(that.table, true);
                }
            },
            _createPopupEditor: function (model) {
                var that = this;
                var html = '<div ' + kendo.attr('uid') + '="' + model.uid + '" class="k-popup-edit-form' + (that._isMobile ? ' k-mobile-list' : '') + '"><div class="k-edit-form-container">';
                var column;
                var command;
                var fields = [];
                var idx;
                var length;
                var tmpl;
                var updateText;
                var cancelText;
                var tempCommand;
                var columns = leafColumns(that.columns);
                var attr;
                var editable = that.options.editable;
                var template = editable.template;
                var options = isPlainObject(editable) ? editable.window : {};
                var settings = extend({}, kendo.Template, that.options.templateSettings);
                if (that.trigger(BEFOREEDIT, { model: model })) {
                    return;
                }
                options = options || {};
                if (template) {
                    if (typeof template === STRING) {
                        template = window.unescape(template);
                    }
                    html += kendo.template(template, settings)(model);
                    for (idx = 0, length = columns.length; idx < length; idx++) {
                        column = columns[idx];
                        if (column.command) {
                            tempCommand = getCommand(column.command, 'edit');
                            if (tempCommand) {
                                command = tempCommand;
                            }
                        }
                    }
                } else {
                    for (idx = 0, length = columns.length; idx < length; idx++) {
                        column = columns[idx];
                        if (!column.command) {
                            html += '<div class="k-edit-label"><label for="' + column.field + '">' + (column.title || column.field || '') + '</label></div>';
                            if (isColumnEditable(column, model)) {
                                fields.push({
                                    field: column.field,
                                    format: column.format,
                                    editor: column.editor,
                                    values: column.values
                                });
                                html += '<div ' + kendo.attr('container-for') + '="' + column.field + '" class="k-edit-field"></div>';
                            } else {
                                var state = {
                                    storage: {},
                                    count: 0
                                };
                                tmpl = kendo.template(that._cellTmpl(column, state), settings);
                                if (state.count > 0) {
                                    tmpl = proxy(tmpl, state.storage);
                                }
                                html += '<div class="k-edit-field">' + tmpl(model) + '</div>';
                            }
                        } else if (column.command) {
                            tempCommand = getCommand(column.command, 'edit');
                            if (tempCommand) {
                                command = tempCommand;
                            }
                        }
                    }
                }
                if (command) {
                    if (isPlainObject(command)) {
                        if (command.text && isPlainObject(command.text)) {
                            updateText = command.text.update;
                            cancelText = command.text.cancel;
                        }
                        if (command.attr) {
                            attr = command.attr;
                        }
                    }
                }
                var container;
                if (!that._isMobile) {
                    html += '<div class="k-edit-buttons k-state-default">';
                    html += that._createButton({
                        name: 'update',
                        text: updateText,
                        attr: attr
                    }) + that._createButton({
                        name: 'canceledit',
                        text: cancelText,
                        attr: attr
                    });
                    html += '</div></div></div>';
                    container = that._editContainer = $(html).appendTo(that.wrapper).eq(0).kendoWindow(extend({
                        modal: true,
                        resizable: false,
                        draggable: true,
                        title: 'Edit',
                        visible: false,
                        close: function (e) {
                            if (e.userTriggered) {
                                e.sender.element.focus();
                                if (that.trigger('cancel', {
                                        container: container,
                                        model: model
                                    })) {
                                    e.preventDefault();
                                    return;
                                }
                                var currentIndex = that.items().index($(that.current()).parent());
                                that.cancelRow();
                                if (that.options.navigatable) {
                                    that._setCurrent(that.items().eq(currentIndex).children().filter(NAVCELL).first());
                                    focusTable(that.table, true);
                                }
                            }
                        }
                    }, options));
                } else {
                    html += '</div></div>';
                    that.editView = that.pane.append('<div data-' + kendo.ns + 'role="view" data-' + kendo.ns + 'use-native-scrolling="true" data-' + kendo.ns + 'init-widgets="false" class="k-grid-edit-form">' + '<div data-' + kendo.ns + 'role="header" class="k-header">' + that._createButton({
                        name: 'update',
                        text: updateText,
                        attr: attr
                    }) + (options.title || 'Edit') + that._createButton({
                        name: 'canceledit',
                        text: cancelText,
                        attr: attr
                    }) + '</div>' + html + '</div>');
                    container = that._editContainer = that.editView.element.find('.k-popup-edit-form');
                }
                that.editable = that._editContainer.kendoEditable({
                    fields: fields,
                    model: model,
                    clearContainer: false,
                    target: that
                }).data('kendoEditable');
                if (that._isMobile) {
                    container.find('input[type=checkbox],input[type=radio]').parent('.k-edit-field').addClass('k-check').prev('.k-edit-label').addClass('k-check').click(function () {
                        $(this).next().children('input').click();
                    });
                }
                that._openPopUpEditor();
                that.trigger(EDIT, {
                    container: container,
                    model: model
                });
            },
            _openPopUpEditor: function () {
                if (!this._isMobile) {
                    this._editContainer.data('kendoWindow').center().open();
                } else {
                    this.pane.navigate(this.editView, this._editAnimation);
                }
            },
            _createInlineEditor: function (row, model) {
                var that = this;
                var column;
                var cell;
                var command;
                var fields = [];
                if (that.trigger(BEFOREEDIT, { model: model })) {
                    return;
                }
                if (that.lockedContent) {
                    row = row.add(that._relatedRow(row));
                }
                row.children(':not(.k-group-cell,.k-hierarchy-cell)').each(function () {
                    cell = $(this);
                    column = leafColumns(that.columns)[that.cellIndex(cell)];
                    if (!column.command && isColumnEditable(column, model)) {
                        fields.push({
                            field: column.field,
                            format: column.format,
                            editor: column.editor,
                            values: column.values
                        });
                        cell.attr(kendo.attr('container-for'), column.field);
                        cell.empty();
                    } else if (column.command) {
                        command = getCommand(column.command, 'edit');
                        if (command) {
                            cell.empty();
                            var updateText, cancelText, attr;
                            if (isPlainObject(command)) {
                                if (command.text && isPlainObject(command.text)) {
                                    updateText = command.text.update;
                                    cancelText = command.text.cancel;
                                }
                                if (command.attr) {
                                    attr = command.attr;
                                }
                            }
                            $(that._createButton({
                                name: 'update',
                                text: updateText,
                                attr: attr
                            }) + that._createButton({
                                name: 'canceledit',
                                text: cancelText,
                                attr: attr
                            })).appendTo(cell);
                        }
                    }
                });
                that._editContainer = row;
                that.editable = new kendo.ui.Editable(row.addClass('k-grid-edit-row'), {
                    target: that,
                    fields: fields,
                    model: model,
                    clearContainer: false
                });
                if (row.length > 1) {
                    adjustRowHeight(row[0], row[1]);
                    that._applyLockedContainersWidth();
                }
                that.trigger(EDIT, {
                    container: row,
                    model: model
                });
            },
            cancelRow: function (notify) {
                var that = this, container = that._editContainer, model;
                if (container) {
                    model = that._modelForContainer(container);
                    if (notify && that.trigger('cancel', {
                            container: container,
                            model: model
                        })) {
                        return;
                    }
                    that._destroyEditable();
                    that.dataSource.cancelChanges(model);
                    if (that._editMode() !== 'popup') {
                        that._displayRow(container);
                    } else {
                        that._displayRow(that.tbody.find('[' + kendo.attr('uid') + '=' + model.uid + ']'));
                    }
                }
            },
            saveRow: function () {
                var container = this._editContainer;
                var model = this._modelForContainer(container);
                var deferred = $.Deferred();
                if (!container || !this.editable) {
                    return deferred.resolve().promise();
                }
                if (!this.editable.end() || this.trigger(SAVE, {
                        container: container,
                        model: model
                    })) {
                    return deferred.reject().promise();
                }
                return this.dataSource.sync();
            },
            _displayRow: function (row) {
                var that = this, model = that._modelForContainer(row), related, newRow, nextRow, isSelected = row.hasClass('k-state-selected'), isAlt = row.hasClass('k-alt');
                if (model) {
                    if (that.lockedContent) {
                        related = $((isAlt ? that.lockedAltRowTemplate : that.lockedRowTemplate)(model));
                        that._relatedRow(row.last()).replaceWith(related);
                    }
                    that.angular('cleanup', function () {
                        return { elements: row.get() };
                    });
                    newRow = $((isAlt ? that.altRowTemplate : that.rowTemplate)(model));
                    row.replaceWith(newRow);
                    that.trigger('itemChange', {
                        item: newRow,
                        data: model,
                        ns: ui
                    });
                    if (related && related.length) {
                        that.trigger('itemChange', {
                            item: related,
                            data: model,
                            ns: ui
                        });
                    }
                    var angularElements = newRow;
                    var angularData = [{ dataItem: model }];
                    if (related && related.length) {
                        angularElements = newRow.add(related);
                        angularData.push({ dataItem: model });
                    }
                    that.angular('compile', function () {
                        return {
                            elements: angularElements.get(),
                            data: angularData
                        };
                    });
                    if (isSelected && that.options.selectable) {
                        that.select(newRow.add(related));
                    }
                    if (related) {
                        adjustRowHeight(newRow[0], related[0]);
                    }
                    nextRow = newRow.next();
                    if (nextRow.hasClass('k-detail-row') && nextRow.is(':visible')) {
                        newRow.find('.k-hierarchy-cell .k-icon').removeClass('k-i-expand').addClass('k-i-collapse');
                    }
                }
            },
            _showMessage: function (messages, row) {
                var that = this;
                if (!that._isMobile) {
                    return window.confirm(messages.title);
                }
                var template = kendo.template('<ul>' + '<li class="km-actionsheet-title">#:title#</li>' + '<li><a href="\\#" class="k-button k-grid-delete">#:confirmDelete#</a></li>' + '</ul>');
                var html = $(template(messages)).appendTo(that.view.element);
                var actionSheet = that._actionSheet = new kendo.mobile.ui.ActionSheet(html, {
                    cancel: messages.cancelDelete,
                    cancelTemplate: '<li class="km-actionsheet-cancel"><a class="k-button" href="\\#">#:cancel#</a></li>',
                    close: function () {
                        this.destroy();
                    },
                    command: function (e) {
                        var item = $(e.currentTarget).parent();
                        if (!item.hasClass('km-actionsheet-cancel')) {
                            that._removeRow(row);
                        }
                    },
                    popup: that._actionSheetPopupOptions
                });
                actionSheet.open(row);
                return false;
            },
            _confirmation: function (row) {
                var that = this, editable = that.options.editable, confirmation = editable === true || typeof editable === STRING ? that.options.messages.editable.confirmation : editable.confirmation;
                if (isPlainObject(editable) && typeof editable.mode === STRING && typeof confirmation !== STRING && confirmation !== false) {
                    confirmation = that.options.messages.editable.confirmation;
                }
                if (confirmation !== false && confirmation != null) {
                    if (typeof confirmation === FUNCTION) {
                        confirmation = confirmation(that._modelForContainer(row));
                    }
                    return that._showMessage({
                        confirmDelete: editable.confirmDelete || that.options.messages.editable.confirmDelete,
                        cancelDelete: editable.cancelDelete || that.options.messages.editable.cancelDelete,
                        title: confirmation === true ? that.options.messages.editable.confirmation : confirmation
                    }, row);
                }
                return true;
            },
            cancelChanges: function () {
                this.dataSource.cancelChanges();
            },
            saveChanges: function () {
                var that = this;
                if ((that.editable && that.editable.end() || !that.editable) && !that.trigger(SAVECHANGES)) {
                    that.dataSource.sync();
                }
            },
            addRow: function () {
                var that = this, index, dataSource = that.dataSource, mode = that._editMode(), createAt = that.options.editable.createAt || '', pageSize = dataSource.pageSize(), view = dataSource.view() || [];
                if (that.editable && that.editable.end() || !that.editable) {
                    if (mode != 'incell') {
                        that.cancelRow();
                    }
                    index = dataSource.indexOf(view[0]);
                    if (createAt.toLowerCase() == 'bottom') {
                        index += view.length;
                        if (pageSize && !dataSource.options.serverPaging && pageSize <= view.length) {
                            index -= 1;
                        }
                    }
                    if (index < 0) {
                        if (dataSource.page() > dataSource.totalPages()) {
                            index = (dataSource.page() - 1) * pageSize;
                        } else {
                            index = 0;
                        }
                    }
                    var model = dataSource.insert(index, {}), id = model.uid, table = that.lockedContent ? that.lockedTable : that.table, row = table.find('tr[' + kendo.attr('uid') + '=' + id + ']'), cell = row.children('td:not(.k-group-cell,.k-hierarchy-cell)').eq(that._firstEditableColumnIndex(row));
                    if (mode === 'inline' && row.length) {
                        that.editRow(row);
                    } else if (mode === 'popup') {
                        that.editRow(model);
                    } else if (cell.length) {
                        that.editCell(cell);
                    }
                    if (createAt.toLowerCase() == 'bottom' && that.lockedContent) {
                        that.lockedContent[0].scrollTop = that.content[0].scrollTop = that.table[0].offsetHeight;
                    }
                }
            },
            _firstEditableColumnIndex: function (container) {
                var that = this, column, columns = leafColumns(that.columns), idx, length, model = that._modelForContainer(container);
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    if (model && (!model.editable || model.editable(column.field)) && !column.command && column.field && column.hidden !== true) {
                        return idx;
                    }
                }
                return -1;
            },
            _toolbar: function () {
                var that = this, wrapper = that.wrapper, toolbar = that.options.toolbar, editable = that.options.editable, container;
                if (toolbar) {
                    container = that.wrapper.find('.k-grid-toolbar');
                    if (!container.length) {
                        if (!isFunction(toolbar)) {
                            toolbar = typeof toolbar === STRING ? toolbar : that._toolbarTmpl(toolbar).replace(templateHashRegExp, '\\#');
                            toolbar = proxy(kendo.template(toolbar), that);
                        }
                        container = $('<div class="k-header k-grid-toolbar" />').html(toolbar({})).prependTo(wrapper);
                        that.angular('compile', function () {
                            return { elements: container.get() };
                        });
                    }
                    if (editable && editable.create !== false) {
                        container.on(CLICK + NS, '.k-grid-add', function (e) {
                            e.preventDefault();
                            that.addRow();
                        }).on(CLICK + NS, '.k-grid-cancel-changes', function (e) {
                            e.preventDefault();
                            that.cancelChanges();
                        }).on(CLICK + NS, '.k-grid-save-changes', function (e) {
                            e.preventDefault();
                            that.saveChanges();
                        });
                    }
                    container.on(CLICK + NS, '.k-grid-excel', function (e) {
                        e.preventDefault();
                        that.saveAsExcel();
                    });
                    container.on(CLICK + NS, '.k-grid-pdf', function (e) {
                        e.preventDefault();
                        that.saveAsPDF();
                    });
                }
            },
            _toolbarTmpl: function (commands) {
                var that = this, idx, length, html = '';
                if (isArray(commands)) {
                    for (idx = 0, length = commands.length; idx < length; idx++) {
                        html += that._createButton(commands[idx]);
                    }
                }
                return html;
            },
            _createButton: function (command) {
                var template = command.template || COMMANDBUTTONTMPL, commandName = typeof command === STRING ? command : command.name || command.text, className = defaultCommands[commandName] ? defaultCommands[commandName].className : 'k-grid-' + (commandName || '').replace(/\s/g, ''), options = {
                        className: className,
                        text: commandName,
                        imageClass: '',
                        attr: '',
                        iconClass: ''
                    }, messages = this.options.messages.commands, attributeClassMatch;
                if (!commandName && !(isPlainObject(command) && command.template)) {
                    throw new Error('Custom commands should have name specified');
                }
                if (isPlainObject(command)) {
                    command = extend(true, {}, command);
                    if (command.className && inArray(options.className, command.className.split(' ')) < 0) {
                        command.className += ' ' + options.className;
                    } else if (command.className === undefined) {
                        command.className = options.className;
                    }
                    if (commandName === 'edit' && isPlainObject(command.text)) {
                        command = extend(true, {}, command);
                        command.text = command.text.edit;
                    }
                    if (command.attr) {
                        if (isPlainObject(command.attr)) {
                            command.attr = stringifyAttributes(command.attr);
                        }
                        if (typeof command.attr === STRING) {
                            attributeClassMatch = command.attr.match(/class="(.+?)"/);
                            if (attributeClassMatch && inArray(attributeClassMatch[1], command.className.split(' ')) < 0) {
                                command.className += ' ' + attributeClassMatch[1];
                            }
                        }
                    }
                    options = extend(true, options, defaultCommands[commandName], { text: messages[commandName] }, command);
                } else {
                    options = extend(true, options, defaultCommands[commandName], { text: messages[commandName] });
                }
                return kendo.template(template)(options);
            },
            _hasFooters: function () {
                return !!this.footerTemplate || !!this.groupFooterTemplate || this.footer && this.footer.length > 0 || this.wrapper.find('.k-grid-footer').length > 0;
            },
            _groupable: function () {
                var that = this;
                if (that._groupableClickHandler) {
                    that.table.add(that.lockedTable).off(CLICK + NS, that._groupableClickHandler);
                } else {
                    that._groupableClickHandler = function (e) {
                        var element = $(this), group = element.closest('tr');
                        if (element.hasClass('k-i-collapse')) {
                            that.collapseGroup(group);
                        } else {
                            that.expandGroup(group);
                        }
                        e.preventDefault();
                        e.stopPropagation();
                    };
                }
                if (that._isLocked()) {
                    that.lockedTable.on(CLICK + NS, '.k-grouping-row .k-i-expand, .k-grouping-row .k-i-collapse', that._groupableClickHandler);
                } else {
                    that.table.on(CLICK + NS, '.k-grouping-row .k-i-expand, .k-grouping-row .k-i-collapse', that._groupableClickHandler);
                }
                that._attachGroupable();
            },
            _attachGroupable: function () {
                var that = this, wrapper = that.wrapper, groupable = that.options.groupable, draggables = HEADERCELLS + '[' + kendo.attr('field') + ']', filter = that.content ? '.k-grid-header:first ' + draggables : 'table:first>.k-grid-header ' + draggables;
                if (groupable && groupable.enabled !== false) {
                    if (!wrapper.has('div.k-grouping-header')[0]) {
                        $('<div>&nbsp;</div>').addClass('k-grouping-header').prependTo(wrapper);
                    }
                    if (that.groupable) {
                        that.groupable.destroy();
                    }
                    that.groupable = new ui.Groupable(wrapper, extend({}, groupable, {
                        draggable: that._draggableInstance,
                        groupContainer: '>div.k-grouping-header',
                        dataSource: that.dataSource,
                        draggableElements: filter,
                        filter: filter,
                        allowDrag: that.options.reorderable,
                        change: function (e) {
                            if (that.trigger('group', { groups: e.groups })) {
                                e.preventDefault();
                            }
                        }
                    }));
                }
            },
            _continuousItems: function (filter, cell) {
                if (!this.lockedContent) {
                    return;
                }
                var that = this;
                var elements = that.table.add(that.lockedTable);
                var lockedItems = $(filter, elements[0]);
                var nonLockedItems = $(filter, elements[1]);
                var columns = cell ? lockedColumns(that.columns).length : 1;
                var nonLockedColumns = cell ? that.columns.length - columns : 1;
                var result = [];
                for (var idx = 0; idx < lockedItems.length; idx += columns) {
                    push.apply(result, lockedItems.slice(idx, idx + columns));
                    push.apply(result, nonLockedItems.splice(0, nonLockedColumns));
                }
                return result;
            },
            _selectable: function () {
                var that = this, multi, cell, notString = [], isLocked = that._isLocked(), selectable = that.options.selectable, dataSourceOptions = that.dataSource.options;
                if (selectable) {
                    if (that.selectable) {
                        that.selectable.destroy();
                    }
                    if (that.options.persistSelection === true) {
                        if (!dataSourceOptions.schema || !dataSourceOptions.schema.model || !dataSourceOptions.schema.model.id) {
                            throw new Error('Selection persistence requires a data source with a model that has e defined id');
                        }
                        that._selectedIds = {};
                    }
                    selectable = kendo.ui.Selectable.parseOptions(selectable);
                    multi = selectable.multiple;
                    cell = selectable.cell;
                    if (that._hasDetails()) {
                        notString[notString.length] = '.k-detail-row';
                    }
                    if (that.options.groupable || that._hasFooters()) {
                        notString[notString.length] = '.k-grouping-row,.k-group-footer';
                    }
                    notString = notString.join(',');
                    if (notString !== '') {
                        notString = ':not(' + notString + ')';
                    }
                    var elements = that.table;
                    if (isLocked) {
                        elements = elements.add(that.lockedTable);
                    }
                    var filter = '>' + (cell ? SELECTION_CELL_SELECTOR : 'tbody>tr' + notString);
                    that.selectable = new kendo.ui.Selectable(elements, {
                        filter: filter,
                        aria: true,
                        multiple: multi,
                        change: function () {
                            if (that.options.persistSelection && !cell) {
                                var key, dataItem, allRows = that.tbody.children(':not(.k-grouping-row,.k-detail-row)'), modelId = dataSourceOptions.schema.model.id, selectedViewIds = {};
                                this.value().each(function () {
                                    dataItem = that.dataItem(this);
                                    selectedViewIds[dataItem[modelId]] = true;
                                });
                                for (var i = 0; i < allRows.length; i++) {
                                    dataItem = that.dataItem(allRows[i]);
                                    key = dataItem[modelId];
                                    if (selectedViewIds[key]) {
                                        that._selectedIds[key] = true;
                                    } else {
                                        delete that._selectedIds[key];
                                    }
                                }
                            }
                            that.trigger(CHANGE);
                        },
                        useAllItems: isLocked && multi && cell,
                        relatedTarget: function (items) {
                            if (cell || !isLocked) {
                                return;
                            }
                            var related;
                            var result = $();
                            for (var idx = 0, length = items.length; idx < length; idx++) {
                                related = that._relatedRow(items[idx]);
                                if (inArray(related[0], items) < 0) {
                                    result = result.add(related);
                                }
                            }
                            return result;
                        },
                        continuousItems: function () {
                            return that._continuousItems(filter, cell);
                        }
                    });
                    if (that.options.navigatable) {
                        elements.on('keydown' + NS, function (e) {
                            var current = that.current();
                            var target = e.target;
                            if (e.keyCode === keys.SPACEBAR && $.inArray(target, elements) > -1 && !current.is('.k-edit-cell,.k-header') && current.parent().is(':not(.k-grouping-row,.k-detail-row,.k-group-footer)')) {
                                e.preventDefault();
                                e.stopPropagation();
                                current = cell ? current : current.parent();
                                if (isLocked && !cell) {
                                    current = current.add(that._relatedRow(current));
                                }
                                if (multi) {
                                    if (!e.ctrlKey) {
                                        that.selectable.clear();
                                    } else {
                                        if (current.hasClass(SELECTED)) {
                                            current.removeClass(SELECTED);
                                            that.trigger(CHANGE);
                                            return;
                                        }
                                    }
                                } else {
                                    that.selectable.clear();
                                }
                                that.selectable.value(current);
                            }
                        });
                    }
                }
            },
            _clipboard: function () {
                var options = this.options;
                var selectable = options.selectable;
                if (selectable && options.allowCopy) {
                    var grid = this;
                    if (!options.navigatable) {
                        grid.table.add(grid.lockedTable).attr('tabindex', 0).on('mousedown' + NS + ' keydown' + NS, '.k-detail-cell', function (e) {
                            if (e.target !== e.currentTarget) {
                                e.stopImmediatePropagation();
                            }
                        }).on('mousedown' + NS, NAVROW + '>' + NAVCELL, proxy(tableClick, grid));
                    }
                    grid.copyHandler = proxy(grid.copySelection, grid);
                    grid.updateClipBoardState = function () {
                        if (grid.areaClipBoard) {
                            grid.areaClipBoard.val(grid.getTSV()).focus().select();
                        }
                    };
                    grid.bind('change', grid.updateClipBoardState);
                    grid.wrapper.on('keydown', grid.copyHandler);
                    grid.clearAreaHandler = proxy(grid.clearArea, grid);
                    grid.wrapper.on('keyup', grid.clearAreaHandler);
                }
            },
            copySelection: function (e) {
                if (e instanceof jQuery.Event && !(e.ctrlKey || e.metaKey) || $(e.target).is('input:visible,textarea:visible') || window.getSelection && window.getSelection().toString() || document.selection && document.selection.createRange().text) {
                    return;
                }
                if (!this.areaClipBoard) {
                    this.areaClipBoard = $('<textarea />').css({
                        position: 'fixed',
                        top: '50%',
                        left: '50%',
                        opacity: 0,
                        width: 0,
                        height: 0
                    }).appendTo(this.wrapper);
                }
                this.areaClipBoard.val(this.getTSV()).focus().select();
            },
            getTSV: function () {
                var grid = this;
                var selected = grid.select();
                var delimeter = '\t';
                var allowCopy = grid.options.allowCopy;
                var onlyVisible = true;
                if ($.isPlainObject(allowCopy) && allowCopy.delimeter) {
                    delimeter = allowCopy.delimeter;
                }
                var text = '';
                if (selected.length) {
                    if (selected.eq(0).is('tr')) {
                        selected = selected.find('td:not(.k-group-cell)');
                    }
                    if (onlyVisible) {
                        selected.filter(':visible');
                    }
                    var result = [];
                    var cellsOffset = this.columns.length;
                    var lockedCols = grid._isLocked() && lockedColumns(grid.columns).length;
                    var inLockedArea = true;
                    $.each(selected, function (idx, cell) {
                        cell = $(cell);
                        var tr = cell.closest('tr');
                        var rowIndex = tr.index();
                        var cellIndex = cell.index();
                        if (onlyVisible) {
                            cellIndex -= cell.prevAll(':hidden').length;
                        }
                        if (lockedCols && inLockedArea) {
                            inLockedArea = $.contains(grid.lockedTable[0], cell[0]);
                        }
                        if (grid._groups() && inLockedArea) {
                            cellIndex -= grid._groups();
                        }
                        cellIndex = inLockedArea ? cellIndex : cellIndex + lockedCols;
                        if (cellsOffset > cellIndex) {
                            cellsOffset = cellIndex;
                        }
                        var cellText = cell.text();
                        if (!result[rowIndex]) {
                            result[rowIndex] = [];
                        }
                        result[rowIndex][cellIndex] = cellText;
                    });
                    var rowsOffset = result.length;
                    result = $.each(result, function (idx, val) {
                        if (val) {
                            result[idx] = val.slice(cellsOffset);
                            if (rowsOffset > idx) {
                                rowsOffset = idx;
                            }
                        }
                    });
                    $.each(result.slice(rowsOffset), function (idx, val) {
                        if (val) {
                            text += val.join(delimeter) + '\r\n';
                        } else {
                            text += '\r\n';
                        }
                    });
                }
                return text;
            },
            clearArea: function (e) {
                var table;
                if (this.areaClipBoard && e && e.target === this.areaClipBoard[0]) {
                    if (this.options.navigatable) {
                        table = $(this.current()).closest('table');
                    } else {
                        table = this.table;
                    }
                    focusTable(table, true);
                }
                if (this.areaClipBoard) {
                    this.areaClipBoard.remove();
                    this.areaClipBoard = null;
                }
            },
            _minScreenSupport: function () {
                var any = this.hideMinScreenCols();
                if (any) {
                    this.minScreenResizeHandler = proxy(this.hideMinScreenCols, this);
                    $(window).on('resize', this.minScreenResizeHandler);
                }
            },
            hideMinScreenCols: function () {
                var cols = this.columns, screenWidth = window.innerWidth > 0 ? window.innerWidth : screen.width;
                return this._iterateMinScreenCols(cols, screenWidth);
            },
            _iterateMinScreenCols: function (cols, screenWidth) {
                var any = false;
                for (var i = 0; i < cols.length; i++) {
                    var col = cols[i];
                    var minWidth = col.minScreenWidth;
                    if (minWidth !== undefined && minWidth !== null) {
                        any = true;
                        if (minWidth > screenWidth) {
                            this.hideColumn(col);
                        } else {
                            this.showColumn(col);
                        }
                    }
                    if (!col.hidden && col.columns) {
                        any = this._iterateMinScreenCols(col.columns, screenWidth) || any;
                    }
                }
                return any;
            },
            _relatedRow: function (row) {
                var lockedTable = this.lockedTable;
                row = $(row);
                if (!lockedTable) {
                    return row;
                }
                var table = row.closest(this.table.add(this.lockedTable));
                var index = table.find('>tbody>tr').index(row);
                table = table[0] === this.table[0] ? lockedTable : this.table;
                return table.find('>tbody>tr').eq(index);
            },
            clearSelection: function () {
                var that = this;
                that.selectable.clear();
                that.trigger(CHANGE);
            },
            select: function (items) {
                var that = this, selectable = that.selectable;
                items = that.table.add(that.lockedTable).find(items);
                if (items.length) {
                    if (!selectable.options.multiple) {
                        selectable.clear();
                        items = items.first();
                    }
                    if (that._isLocked()) {
                        items = items.add(items.map(function () {
                            return that._relatedRow(this);
                        }));
                    }
                    selectable.value(items);
                    return;
                }
                return selectable.value();
            },
            selectedKeyNames: function () {
                var that = this, ids = [];
                for (var property in that._selectedIds) {
                    ids.push(property);
                }
                ids.sort();
                return ids;
            },
            _updateCurrentAttr: function (current, next) {
                var headerId = $(current).data('headerId');
                $(current).removeClass(FOCUSED).closest('table').removeAttr('aria-activedescendant');
                if (headerId) {
                    headerId = headerId.replace(this._cellId, '');
                    $(current).attr('id', headerId);
                } else {
                    $(current).removeAttr('id');
                }
                next.data('headerId', next.attr('id')).attr('id', this._cellId).addClass(FOCUSED).closest('table').attr('aria-activedescendant', this._cellId);
                this._current = next;
            },
            _scrollCurrent: function () {
                var current = this._current;
                var scrollable = this.options.scrollable;
                if (!current || !scrollable) {
                    return;
                }
                var row = current.parent();
                var tableContainer = row.closest('table').parent();
                var isInLockedContainer = tableContainer.is('.k-grid-content-locked,.k-grid-header-locked');
                var isInContent = tableContainer.is('.k-grid-content-locked,.k-grid-content,.k-virtual-scrollable-wrap');
                var scrollableContainer = $(this.content).find('>.k-virtual-scrollable-wrap').addBack().last()[0];
                if (isInContent) {
                    if (scrollable.virtual) {
                        var rowIndex = Math.max(inArray(row[0], this._items(row.parent())), 0);
                        this._rowVirtualIndex = this.virtualScrollable.itemIndex(rowIndex);
                        this.virtualScrollable.scrollIntoView(row);
                    } else {
                        this._scrollTo(this._relatedRow(row)[0], scrollableContainer);
                    }
                }
                if (this.lockedContent) {
                    this.lockedContent[0].scrollTop = scrollableContainer.scrollTop;
                }
                if (!isInLockedContainer) {
                    this._scrollTo(current[0], scrollableContainer);
                }
            },
            current: function (next) {
                return this._setCurrent(next, true);
            },
            _setCurrent: function (next, preventTrigger) {
                var current = this._current;
                next = $(next);
                if (next.length) {
                    if (!current || current[0] !== next[0]) {
                        this._updateCurrentAttr(current, next);
                        this._scrollCurrent();
                        if (!preventTrigger) {
                            this.trigger(NAVIGATE, { element: next });
                        }
                    }
                }
                return this._current;
            },
            _removeCurrent: function () {
                if (this._current) {
                    this._current.removeClass(FOCUSED);
                    this._current = null;
                }
            },
            _scrollTo: function (element, container) {
                var elementToLowercase = element.tagName.toLowerCase();
                var isHorizontal = elementToLowercase === 'td' || elementToLowercase === 'th';
                var elementOffset = element[isHorizontal ? 'offsetLeft' : 'offsetTop'];
                var elementOffsetDir = element[isHorizontal ? 'offsetWidth' : 'offsetHeight'];
                var containerScroll = container[isHorizontal ? 'scrollLeft' : 'scrollTop'];
                var containerOffsetDir = container[isHorizontal ? 'clientWidth' : 'clientHeight'];
                var bottomDistance = elementOffset + elementOffsetDir;
                var result = 0;
                var ieCorrection = 0;
                var firefoxCorrection = 0;
                if (isRtl && isHorizontal) {
                    var table = $(element).closest('table')[0];
                    if (browser.msie) {
                        ieCorrection = table.offsetLeft;
                    } else if (browser.mozilla) {
                        firefoxCorrection = table.offsetLeft - kendo.support.scrollbar();
                    }
                }
                containerScroll = Math.abs(containerScroll + ieCorrection - firefoxCorrection);
                if (containerScroll > elementOffset) {
                    result = elementOffset;
                } else if (bottomDistance > containerScroll + containerOffsetDir) {
                    if (elementOffsetDir <= containerOffsetDir) {
                        result = bottomDistance - containerOffsetDir;
                    } else {
                        result = elementOffset;
                    }
                } else {
                    result = containerScroll;
                }
                result = Math.abs(result + ieCorrection) + firefoxCorrection;
                container[isHorizontal ? 'scrollLeft' : 'scrollTop'] = result;
            },
            _navigatable: function () {
                var that = this;
                if (!that.options.navigatable) {
                    return;
                }
                var dataTables = that.table.add(that.lockedTable);
                var headerTables = that.thead.parent().add($('>table', that.lockedHeader));
                var tables = dataTables;
                if (that.options.scrollable) {
                    tables = tables.add(headerTables);
                    headerTables.attr(TABINDEX, -1);
                }
                this._navigatableTables = tables;
                tables.off('mousedown' + NS + ' focus' + NS + ' focusout' + NS + ' keydown' + NS);
                headerTables.on('keydown' + NS, proxy(that._openHeaderMenu, that)).find('a.k-link').attr('tabIndex', -1);
                dataTables.attr(TABINDEX, math.max(dataTables.attr(TABINDEX) || 0, 0)).on('mousedown' + NS + ' keydown' + NS, '.k-detail-cell', function (e) {
                    if (e.target !== e.currentTarget) {
                        e.stopImmediatePropagation();
                    }
                });
                tables.on(kendo.support.touch ? 'touchstart' + NS : 'mousedown' + NS, NAVROW + '>' + NAVCELL, proxy(tableClick, that)).on('focus' + NS, proxy(that._tableFocus, that)).on('focusout' + NS, proxy(that._tableBlur, that)).on('keydown' + NS, proxy(that._tableKeyDown, that));
            },
            _openHeaderMenu: function (e) {
                if (e.altKey && e.keyCode == keys.DOWN) {
                    this.current().find('.k-grid-filter, .k-header-column-menu').click();
                    e.stopImmediatePropagation();
                }
            },
            _setTabIndex: function (table) {
                this._navigatableTables.attr(TABINDEX, -1);
                table.attr(TABINDEX, 0);
            },
            _tableFocus: function (e) {
                if (kendo.support.touch) {
                    return;
                }
                var current = this.current();
                var table = $(e.currentTarget);
                if (current && current.is(':visible')) {
                    current.addClass(FOCUSED);
                } else {
                    this._setCurrent(table.find(FIRSTNAVITEM));
                }
                this._setTabIndex(table);
            },
            _tableBlur: function () {
                var current = this.current();
                if (current) {
                    current.removeClass(FOCUSED);
                }
            },
            _tableKeyDown: function (e) {
                var current = this.current();
                var requestInProgress = this.virtualScrollable && this.virtualScrollable.fetching();
                var target = $(e.target);
                var canHandle = !e.isDefaultPrevented() && !target.is(':button,a,:input,a>.k-icon');
                if (requestInProgress) {
                    e.preventDefault();
                    return;
                }
                current = current ? current : $(this.lockedTable).add(this.table).find(FIRSTNAVITEM);
                if (!current.length) {
                    return;
                }
                var handled = false;
                if (canHandle && e.keyCode == keys.UP) {
                    handled = this._moveUp(current);
                }
                if (canHandle && e.keyCode == keys.DOWN) {
                    handled = this._moveDown(current);
                }
                if (canHandle && e.keyCode == (isRtl ? keys.LEFT : keys.RIGHT)) {
                    handled = this._moveRight(current, e.altKey);
                }
                if (canHandle && e.keyCode == (isRtl ? keys.RIGHT : keys.LEFT)) {
                    handled = this._moveLeft(current, e.altKey);
                }
                if (canHandle && e.keyCode == keys.PAGEDOWN) {
                    handled = this._handlePageDown();
                }
                if (canHandle && e.keyCode == keys.PAGEUP) {
                    handled = this._handlePageUp();
                }
                if (e.keyCode == keys.ENTER || e.keyCode == keys.F2) {
                    handled = this._handleEnterKey(current, e.currentTarget, target);
                }
                if (e.keyCode == keys.ESC) {
                    handled = this._handleEscKey(current, e.currentTarget);
                }
                if (e.keyCode == keys.TAB) {
                    handled = this._handleTabKey(current, e.currentTarget, e.shiftKey);
                }
                if (handled) {
                    e.preventDefault();
                    e.stopPropagation();
                }
            },
            _moveLeft: function (current, altKey) {
                var next, index;
                var row = current.parent();
                var container = row.parent();
                if (altKey) {
                    this.collapseRow(row);
                } else {
                    index = container.find(NAVROW).index(row);
                    next = this._prevHorizontalCell(container, current, index);
                    if (!next[0]) {
                        container = this._horizontalContainer(container);
                        next = this._prevHorizontalCell(container, current, index);
                        if (next[0] !== current[0]) {
                            focusTable(container.parent(), true);
                        }
                    }
                    this._setCurrent(next);
                }
                return true;
            },
            _moveRight: function (current, altKey) {
                var next, index;
                var row = current.parent();
                var container = row.parent();
                if (altKey) {
                    this.expandRow(row);
                } else {
                    index = container.find(NAVROW).index(row);
                    next = this._nextHorizontalCell(container, current, index);
                    if (!next[0]) {
                        container = this._horizontalContainer(container, true);
                        next = this._nextHorizontalCell(container, current, index);
                        if (next[0] !== current[0]) {
                            focusTable(container.parent(), true);
                        }
                    }
                    this._setCurrent(next);
                }
                return true;
            },
            _moveUp: function (current) {
                var container = current.parent().parent();
                var next = this._prevVerticalCell(container, current);
                if (!next[0]) {
                    container = this._verticalContainer(container, true);
                    next = this._prevVerticalCell(container, current);
                    if (next[0]) {
                        focusTable(container.parent(), true);
                    }
                }
                this._setCurrent(next);
                return true;
            },
            _moveDown: function (current) {
                var container = current.parent().parent();
                var next = this._nextVerticalCell(container, current);
                if (!next[0]) {
                    container = this._verticalContainer(container);
                    next = this._nextVerticalCell(container, current);
                    if (next[0]) {
                        focusTable(container.parent(), true);
                    }
                }
                this._setCurrent(next);
                return true;
            },
            _handlePageDown: function () {
                if (!this.options.pageable) {
                    return false;
                }
                this.dataSource.page(this.dataSource.page() + 1);
                return true;
            },
            _handlePageUp: function () {
                if (!this.options.pageable) {
                    return false;
                }
                this.dataSource.page(this.dataSource.page() - 1);
                return true;
            },
            _handleTabKey: function (current, currentTable, shiftKey) {
                var isInCell = this.options.editable && this._editMode() == 'incell';
                var cell;
                if (!isInCell || current.is('th')) {
                    return false;
                }
                cell = $(activeElement()).closest('.k-edit-cell');
                if (cell[0] && cell[0] !== current[0]) {
                    current = cell;
                }
                cell = this._tabNext(current, currentTable, shiftKey);
                if (cell.length) {
                    this._handleEditing(current, cell, cell.closest('table'));
                    return true;
                }
                return false;
            },
            _handleEscKey: function (current, currentTable) {
                var active = activeElement();
                var isInCell = this._editMode() == 'incell';
                if (!isInEdit(current)) {
                    if (current.has(active).length) {
                        focusTable(currentTable, true);
                        return true;
                    }
                    return false;
                }
                if (isInCell) {
                    this.closeCell(true);
                } else {
                    var currentIndex = $(current).parent().index();
                    if (active) {
                        active.blur();
                    }
                    this.cancelRow(true);
                    if (currentIndex >= 0) {
                        this._setCurrent(this.items().eq(currentIndex).children(NAVCELL).first());
                    }
                }
                if (browser.msie && browser.version < 9) {
                    document.body.focus();
                }
                focusTable(currentTable, true);
                return true;
            },
            _toggleCurrent: function (current, editable) {
                var row = current.parent();
                if (row.is('.k-grouping-row')) {
                    row.find('.k-icon:first').click();
                    return true;
                }
                if (!editable && row.is('.k-master-row')) {
                    row.find('.k-icon:first').click();
                    return true;
                }
                return false;
            },
            _handleEnterKey: function (current, currentTable, target) {
                var editable = this.options.editable && this.options.editable.update !== false;
                var container = target.closest('[role=gridcell]');
                if (!target.is('table') && !$.contains(current[0], target[0])) {
                    current = container;
                }
                if (current.is('th')) {
                    current.find('.k-link').click();
                    return true;
                }
                if (this._toggleCurrent(current, editable)) {
                    return true;
                }
                var focusable = current.find(':kendoFocusable:first');
                if (focusable[0] && !current.hasClass('k-edit-cell') && current.hasClass('k-state-focused')) {
                    focusable.focus();
                    return true;
                }
                if (editable && !target.is(':button,.k-button,textarea')) {
                    if (!container[0]) {
                        container = current;
                    }
                    this._handleEditing(container, false, currentTable);
                    return true;
                }
                return false;
            },
            _nextHorizontalCell: function (table, current, originalIndex) {
                var cells = current.nextAll(DATA_CELL);
                if (!cells.length) {
                    var rows = table.find(NAVROW);
                    var rowIndex = rows.index(current.parent());
                    if (rowIndex == -1) {
                        if (current.hasClass('k-header')) {
                            var headerRows = [];
                            mapColumnToCellRows([lockedColumns(this.columns)[0]], childColumnsCells(rows.eq(0).children().first()), headerRows, 0, 0);
                            if (headerRows[originalIndex]) {
                                return headerRows[originalIndex][0];
                            }
                            return current;
                        }
                        if (current.parent().hasClass('k-filter-row')) {
                            return rows.last().children(DATA_CELL).first();
                        }
                        return rows.eq(originalIndex).children(DATA_CELL).first();
                    }
                }
                return cells.first();
            },
            _prevHorizontalCell: function (table, current, originalIndex) {
                var cells = current.prevAll(DATA_CELL);
                if (!cells.length) {
                    var rows = table.find(NAVROW);
                    var rowIndex = rows.index(current.parent());
                    if (rowIndex == -1) {
                        if (current.hasClass('k-header')) {
                            var headerRows = [];
                            var columns = lockedColumns(this.columns);
                            mapColumnToCellRows([columns[columns.length - 1]], childColumnsCells(rows.eq(0).children().last()), headerRows, 0, 0);
                            if (headerRows[originalIndex]) {
                                return headerRows[originalIndex][0];
                            }
                            return current;
                        }
                        if (current.parent().hasClass('k-filter-row')) {
                            return rows.last().children(DATA_CELL).last();
                        }
                        return rows.eq(originalIndex).children(DATA_CELL).last();
                    }
                }
                return cells.first();
            },
            _currentDataIndex: function (table, current) {
                var index = current.attr('data-index');
                if (!index) {
                    return undefined;
                }
                var lockedColumnsCount = lockedColumns(this.columns).length;
                if (lockedColumnsCount && !table.closest('div').hasClass('k-grid-content-locked')[0]) {
                    return index - lockedColumnsCount;
                }
                return index;
            },
            _prevVerticalCell: function (container, current) {
                var cells;
                var row = current.parent();
                var rows = container.children(NAVROW);
                var rowIndex = rows.index(row);
                var index = this._currentDataIndex(container, current);
                if (index || current.hasClass('k-header')) {
                    cells = parentColumnsCells(current);
                    return cells.eq(cells.length - 2);
                }
                index = row.children(DATA_CELL).index(current);
                if (row.hasClass('k-filter-row')) {
                    return leafDataCells(container).eq(index);
                }
                if (rowIndex == -1) {
                    row = container.find('.k-filter-row');
                    if (!row[0]) {
                        return leafDataCells(container).eq(index);
                    }
                } else {
                    row = rowIndex === 0 ? $() : rows.eq(rowIndex - 1);
                }
                cells = row.children(DATA_CELL);
                if (cells.length > index) {
                    return cells.eq(index);
                }
                return cells.eq(0);
            },
            _nextVerticalCell: function (container, current) {
                var cells;
                var row = current.parent();
                var rows = container.children(NAVROW);
                var rowIndex = rows.index(row);
                var index = this._currentDataIndex(container, current);
                if (rowIndex != -1 && index === undefined && current.hasClass('k-header')) {
                    return childColumnsCells(current).eq(1);
                }
                index = index ? parseInt(index, 10) : row.children(DATA_CELL).index(current);
                if (rowIndex == -1) {
                    row = rows.eq(0);
                } else {
                    row = rows.eq(rowIndex + current[0].rowSpan);
                }
                cells = row.children(DATA_CELL);
                if (cells.length > index) {
                    return cells.eq(index);
                }
                return cells.eq(0);
            },
            _verticalContainer: function (container, up) {
                var table = container.parent();
                var length = this._navigatableTables.length;
                var step = Math.floor(length / 2);
                var index = inArray(table[0], this._navigatableTables);
                if (up) {
                    step *= -1;
                }
                index += step;
                if (index >= 0 || index < length) {
                    table = this._navigatableTables.eq(index);
                }
                return table.find(up ? 'thead' : 'tbody');
            },
            _horizontalContainer: function (container, right) {
                var length = this._navigatableTables.length;
                if (length <= 2) {
                    return container;
                }
                var table = container.parent();
                var index = inArray(table[0], this._navigatableTables);
                index += right ? 1 : -1;
                if (right && (index == 2 || index == length)) {
                    return container;
                }
                if (!right && (index == 1 || index < 0)) {
                    return container;
                }
                return this._navigatableTables.eq(index).find('thead, tbody');
            },
            _tabNext: function (current, currentTable, back) {
                var switchRow = true;
                var next = back ? current.prevAll(DATA_CELL + ':first') : current.nextAll(':visible:first');
                if (!next.length) {
                    next = current.parent();
                    if (this.lockedTable) {
                        switchRow = back && currentTable == this.lockedTable[0] || !back && currentTable == this.table[0];
                        next = this._relatedRow(next);
                    }
                    if (switchRow) {
                        next = next[back ? 'prevAll' : 'nextAll']('tr:not(.k-grouping-row):not(.k-detail-row):visible:first');
                    }
                    next = next.children(DATA_CELL + (back ? ':last' : ':first'));
                }
                return next;
            },
            _handleEditing: function (current, next, table) {
                var that = this, active = $(activeElement()), mode = that._editMode(), isIE = browser.msie, oldIE = isIE && browser.version < 9, editContainer = that._editContainer, focusable, editable = that.options.editable && that.options.editable.update !== false, isEdited;
                table = $(table);
                if (mode == 'incell') {
                    isEdited = current.hasClass('k-edit-cell');
                } else {
                    isEdited = current.parent().hasClass('k-grid-edit-row');
                }
                if (that.editable) {
                    if ($.contains(editContainer[0], active[0])) {
                        if (browser.opera || oldIE) {
                            active.blur().change().triggerHandler('blur');
                        } else {
                            active.blur();
                            if (isIE) {
                                active.blur();
                            }
                        }
                    }
                    if (!that.editable) {
                        focusTable(table);
                        return;
                    }
                    if (that.editable.end()) {
                        if (mode == 'incell') {
                            that.closeCell();
                        } else {
                            that.saveRow();
                            isEdited = true;
                        }
                    } else {
                        if (mode == 'incell') {
                            that._setCurrent(editContainer);
                        } else {
                            that._setCurrent(editContainer.children().filter(DATA_CELL).first());
                        }
                        focusable = editContainer.find(':kendoFocusable:first')[0];
                        if (focusable) {
                            focusable.focus();
                        }
                        return;
                    }
                }
                if (next) {
                    that._setCurrent(next);
                }
                if (oldIE) {
                    document.body.focus();
                }
                focusTable(table, true);
                if (!editable) {
                    return;
                }
                if (!isEdited && !next || next) {
                    if (mode == 'incell') {
                        that.editCell(that.current());
                    } else {
                        that.editRow(that.current().parent());
                    }
                }
            },
            _wrapper: function () {
                var that = this, table = that.table, height = that.options.height, wrapper = that.element;
                if (!wrapper.is('div')) {
                    wrapper = wrapper.wrap('<div/>').parent();
                }
                that.wrapper = wrapper.addClass('k-grid k-widget k-display-block');
                if (height) {
                    that.wrapper.css(HEIGHT, height);
                    table.css(HEIGHT, 'auto');
                }
                that._initMobile();
            },
            _initMobile: function () {
                var options = this.options;
                var that = this;
                this._isMobile = options.mobile === true && kendo.support.mobileOS || options.mobile === 'phone' || options.mobile === 'tablet';
                if (this._isMobile) {
                    var html = this.wrapper.addClass('k-grid-mobile').wrap('<div data-' + kendo.ns + 'stretch="true" data-' + kendo.ns + 'role="view" ' + 'data-' + kendo.ns + 'init-widgets="false"></div>').parent();
                    this.pane = kendo.mobile.ui.Pane.wrap(html);
                    this.view = this.pane.view();
                    this._actionSheetPopupOptions = $(document.documentElement).hasClass('km-root') ? { modal: false } : {
                        align: 'bottom center',
                        position: 'bottom center',
                        effect: 'slideIn:up'
                    };
                    if (options.height) {
                        this.pane.element.parent().css(HEIGHT, options.height);
                    }
                    this._editAnimation = 'slide';
                    this.view.bind('show', function () {
                        if (that._isLocked()) {
                            that._updateTablesWidth();
                            that._applyLockedContainersWidth();
                            that._syncLockedContentHeight();
                            that._syncLockedHeaderHeight();
                            that._syncLockedFooterHeight();
                        }
                    });
                }
            },
            _tbody: function () {
                var that = this, table = that.table, tbody;
                tbody = table.find('>tbody');
                if (!tbody.length) {
                    tbody = $('<tbody/>').appendTo(table);
                }
                that.tbody = tbody.attr('role', 'rowgroup');
            },
            _scrollable: function () {
                var that = this, header, table, options = that.options, scrollable = options.scrollable, hasVirtualScroll = scrollable !== true && scrollable.virtual && !that.virtualScrollable, scrollbar = !kendo.support.kineticScrollNeeded || hasVirtualScroll ? kendo.support.scrollbar() : 0;
                if (scrollable) {
                    header = that.wrapper.children('.k-grid-header');
                    if (!header[0]) {
                        header = $('<div class="k-grid-header" />').insertBefore(that.table);
                    }
                    header.css(isRtl ? 'padding-left' : 'padding-right', scrollable.virtual ? scrollbar + 1 : scrollbar);
                    table = $('<table role="grid" />');
                    if (isIE7) {
                        table.attr('cellspacing', 0);
                    }
                    table.width(that.table[0].style.width);
                    table.append(that.thead);
                    header.empty().append($('<div class="k-grid-header-wrap k-auto-scrollable" />').append(table));
                    that.content = that.table.parent();
                    if (that.content.is('.k-virtual-scrollable-wrap, .km-scroll-container')) {
                        that.content = that.content.parent();
                    }
                    if (!that.content.is('.k-grid-content, .k-virtual-scrollable-wrap')) {
                        that.content = that.table.wrap('<div class="k-grid-content k-auto-scrollable" />').parent();
                    }
                    if (hasVirtualScroll) {
                        that.virtualScrollable = new VirtualScrollable(that.content, {
                            dataSource: that.dataSource,
                            itemHeight: function () {
                                return that._averageRowHeight();
                            }
                        });
                    }
                    that.scrollables = header.children('.k-grid-header-wrap').add(that.content);
                    var footer = that.wrapper.find('.k-grid-footer');
                    if (footer.length) {
                        that.scrollables = that.scrollables.add(footer.children('.k-grid-footer-wrap'));
                    }
                    if (scrollable.virtual) {
                        that.content.find('>.k-virtual-scrollable-wrap').unbind('scroll' + NS).bind('scroll' + NS, function () {
                            that.scrollables.scrollLeft(this.scrollLeft);
                            if (that.lockedContent) {
                                that.lockedContent[0].scrollTop = this.scrollTop;
                            }
                        });
                    } else {
                        that.content.unbind('scroll' + NS).bind('scroll' + NS, function (e) {
                            that.scrollables.not(e.currentTarget).scrollLeft(this.scrollLeft);
                            if (that.lockedContent && e.currentTarget == that.content[0]) {
                                that.lockedContent[0].scrollTop = this.scrollTop;
                            }
                        });
                        var touchScroller = that.content.data('kendoTouchScroller');
                        if (touchScroller) {
                            touchScroller.destroy();
                        }
                        touchScroller = kendo.touchScroller(that.content);
                        if (touchScroller && touchScroller.movable) {
                            that.touchScroller = touchScroller;
                            touchScroller.movable.bind('change', function (e) {
                                that.scrollables.scrollLeft(-e.sender.x);
                                if (that.lockedContent) {
                                    that.lockedContent.scrollTop(-e.sender.y);
                                }
                            });
                            that.one(DATABOUND, function (e) {
                                e.sender.wrapper.addClass('k-grid-backface');
                            });
                        }
                    }
                }
            },
            _renderNoRecordsContent: function () {
                var that = this;
                if (that.options.noRecords) {
                    var noRecordsElement = that.table.parent().children('.' + NORECORDSCLASS);
                    if (noRecordsElement.length) {
                        that.angular('cleanup', function () {
                            return { elements: noRecordsElement.get() };
                        });
                        noRecordsElement.remove();
                    }
                    if (!that.dataSource || !that.dataSource.view().length) {
                        noRecordsElement = $(that.noRecordsTemplate({})).insertAfter(that.table);
                        that.angular('compile', function () {
                            return {
                                elements: noRecordsElement.get(),
                                data: [{}]
                            };
                        });
                    }
                }
            },
            _setContentWidth: function (scrollLeft) {
                var that = this, hiddenDivClass = 'k-grid-content-expander', hiddenDiv = '<div class="' + hiddenDivClass + '"></div>', resizable = that.resizable, expander;
                if (that.options.scrollable && that.wrapper.is(':visible')) {
                    expander = that.table.parent().children('.' + hiddenDivClass);
                    that._setContentWidthHandler = proxy(that._setContentWidth, that);
                    if (!that.dataSource || !that.dataSource.view().length) {
                        if (!expander[0]) {
                            expander = $(hiddenDiv).appendTo(that.table.parent());
                            if (resizable) {
                                resizable.bind('resize', that._setContentWidthHandler);
                            }
                        }
                        if (that.thead) {
                            expander.width(that.thead.width());
                            if (!isNaN(parseFloat(scrollLeft, 10))) {
                                that.content.scrollLeft(scrollLeft);
                            }
                        }
                    } else if (expander[0]) {
                        expander.remove();
                        if (resizable) {
                            resizable.unbind('resize', that._setContentWidthHandler);
                        }
                    }
                    that._applyLockedContainersWidth();
                    if (that.lockedHeader && that.table[0].clientWidth === 0) {
                        that.table[0].style.width = '1px';
                    }
                }
            },
            _applyLockedContainersWidth: function () {
                if (this.options.scrollable && this.lockedHeader) {
                    var headerTable = this.thead.parent(), headerWrap = headerTable.parent(), contentWidth = this.wrapper[0].clientWidth, groups = this._groups(), scrollbar = kendo.support.scrollbar(), cols = this.lockedHeader.find('>table>colgroup>col:not(.k-group-col, .k-hierarchy-col)'), nonLockedCols = headerTable.find('>colgroup>col:not(.k-group-col, .k-hierarchy-col)'), width = columnsWidth(cols), nonLockedColsWidth = columnsWidth(nonLockedCols), footerWrap;
                    if (groups > 0) {
                        width += outerWidth(this.lockedHeader.find('.k-group-cell:first')) * groups;
                    }
                    if (width >= contentWidth) {
                        width = contentWidth - 3 * scrollbar;
                    }
                    this.lockedHeader.add(this.lockedContent).width(width);
                    headerWrap[0].style.width = headerWrap.parent().width() - width - 2 + 'px';
                    headerTable.add(this.table).width(nonLockedColsWidth);
                    if (this.virtualScrollable) {
                        contentWidth -= scrollbar;
                    }
                    this.content[0].style.width = contentWidth - width - 2 + 'px';
                    if (this.lockedFooter && this.lockedFooter.length) {
                        this.lockedFooter.width(width);
                        footerWrap = this.footer.find('.k-grid-footer-wrap');
                        footerWrap[0].style.width = headerWrap[0].clientWidth + 'px';
                        footerWrap.children().first().width(nonLockedColsWidth);
                    }
                }
            },
            _setContentHeight: function () {
                var that = this, options = that.options, height = that.wrapper.innerHeight(), header = that.wrapper.children('.k-grid-header'), scrollbar = kendo.support.scrollbar();
                if (options.scrollable && that.wrapper.is(':visible')) {
                    height -= outerHeight(header);
                    if (that.pager) {
                        height -= outerHeight(that.pager.element);
                    }
                    if (options.groupable) {
                        height -= outerHeight(that.wrapper.children('.k-grouping-header'));
                    }
                    if (options.toolbar) {
                        height -= outerHeight(that.wrapper.children('.k-grid-toolbar'));
                    }
                    if (that.footerTemplate) {
                        height -= outerHeight(that.wrapper.children('.k-grid-footer'));
                    }
                    var isGridHeightSet = function (el) {
                        var initialHeight, newHeight;
                        if (el[0].style.height) {
                            return true;
                        } else {
                            initialHeight = el.height();
                        }
                        el.height('auto');
                        newHeight = el.height();
                        if (initialHeight != newHeight) {
                            el.height('');
                            return true;
                        }
                        el.height('');
                        return false;
                    };
                    if (isGridHeightSet(that.wrapper)) {
                        if (height > scrollbar * 2) {
                            if (that.lockedContent) {
                                scrollbar = that.table[0].offsetWidth > that.table.parent()[0].clientWidth ? scrollbar : 0;
                                that.lockedContent.height(height - scrollbar);
                            }
                            that.content.height(height);
                        } else {
                            that.content.height(scrollbar * 2 + 1);
                        }
                    }
                }
            },
            _averageRowHeight: function () {
                var that = this, itemsCount = that._items(that.tbody).length, rowHeight = that._rowHeight;
                if (itemsCount === 0) {
                    return rowHeight;
                }
                if (!that._rowHeight) {
                    that._rowHeight = rowHeight = outerHeight(that.table) / itemsCount;
                    that._sum = rowHeight;
                    that._measures = 1;
                }
                var currentRowHeight = outerHeight(that.table) / itemsCount;
                if (rowHeight !== currentRowHeight) {
                    that._measures++;
                    that._sum += currentRowHeight;
                    that._rowHeight = that._sum / that._measures;
                }
                return rowHeight;
            },
            _dataSource: function () {
                var that = this, options = that.options, pageable, dataSource = options.dataSource;
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                if (isPlainObject(dataSource)) {
                    extend(dataSource, {
                        table: that.table,
                        fields: that.columns
                    });
                    pageable = options.pageable;
                    if (isPlainObject(pageable) && pageable.pageSize !== undefined) {
                        dataSource.pageSize = pageable.pageSize;
                    }
                }
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                    that._progressHandler = proxy(that._requestStart, that);
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = DataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(ERROR, that._errorHandler);
            },
            _error: function () {
                this._progress(false);
            },
            _requestStart: function () {
                this._progress(true);
            },
            _modelChange: function (e) {
                var that = this, tbody = that.tbody, model = e.model, row = that.tbody.find('tr[' + kendo.attr('uid') + '=' + model.uid + ']'), relatedRow, cell, column, isAlt = row.hasClass('k-alt'), tmp, idx = that._items(tbody).index(row), isLocked = that.lockedContent, selectable, selectableRow, childCells, originalCells, length;
                if (isLocked) {
                    relatedRow = that._relatedRow(row);
                }
                if (row.add(relatedRow).children('.k-edit-cell').length && !that.options.rowTemplate) {
                    row.add(relatedRow).children(':not(.k-group-cell,.k-hierarchy-cell)').each(function () {
                        cell = $(this);
                        column = leafColumns(that.columns)[that.cellIndex(cell)];
                        if (column.field === e.field) {
                            if (!cell.hasClass('k-edit-cell')) {
                                that._displayCell(cell, column, model);
                                $('<span class="k-dirty"/>').prependTo(cell);
                            } else {
                                cell.addClass('k-dirty-cell');
                            }
                        }
                    });
                } else if (!row.hasClass('k-grid-edit-row')) {
                    selectableRow = $().add(row);
                    if (isLocked) {
                        tmp = (isAlt ? that.lockedAltRowTemplate : that.lockedRowTemplate)(model);
                        selectableRow = selectableRow.add(relatedRow);
                        relatedRow.replaceWith(tmp);
                    }
                    that.angular('cleanup', function () {
                        return { elements: selectableRow.get() };
                    });
                    tmp = (isAlt ? that.altRowTemplate : that.rowTemplate)(model);
                    row.replaceWith(tmp);
                    tmp = that._items(tbody).eq(idx);
                    var angularData = [{ dataItem: model }];
                    if (isLocked) {
                        row = row.add(relatedRow);
                        relatedRow = that._relatedRow(tmp)[0];
                        adjustRowHeight(tmp[0], relatedRow);
                        tmp = tmp.add(relatedRow);
                        angularData.push({ dataItem: model });
                    }
                    that.angular('compile', function () {
                        return {
                            elements: tmp.get(),
                            data: angularData
                        };
                    });
                    selectable = that.options.selectable;
                    if (selectable && row.hasClass('k-state-selected')) {
                        that.select(tmp);
                    }
                    originalCells = selectableRow.children(':not(.k-group-cell,.k-hierarchy-cell)');
                    childCells = tmp.children(':not(.k-group-cell,.k-hierarchy-cell)');
                    for (idx = 0, length = that.columns.length; idx < length; idx++) {
                        column = that.columns[idx];
                        cell = childCells.eq(idx);
                        if (selectable && originalCells.eq(idx).hasClass('k-state-selected')) {
                            cell.addClass('k-state-selected');
                        }
                        if (column.field === e.field) {
                            $('<span class="k-dirty"/>').prependTo(cell);
                        }
                    }
                    that.trigger('itemChange', {
                        item: tmp,
                        data: model,
                        ns: ui
                    });
                }
            },
            _pageable: function () {
                var that = this, wrapper, pageable = that.options.pageable;
                if (pageable) {
                    wrapper = that.wrapper.children('div.k-grid-pager');
                    if (!wrapper.length) {
                        wrapper = $('<div class="k-pager-wrap k-grid-pager"/>').appendTo(that.wrapper);
                    }
                    if (that.pager) {
                        that.pager.destroy();
                    }
                    if (typeof pageable === 'object' && pageable instanceof kendo.ui.Pager) {
                        that.pager = pageable;
                    } else {
                        that.pager = new kendo.ui.Pager(wrapper, extend({}, pageable, { dataSource: that.dataSource }));
                    }
                    that.pager.bind('pageChange', function (e) {
                        if (that.trigger('page', { page: e.index })) {
                            e.preventDefault();
                        }
                    });
                }
            },
            _footer: function () {
                var that = this, aggregates = that.dataSource.aggregates(), html = '', footerTemplate = that.footerTemplate, options = that.options, footerWrap, footer = that.footer || that.wrapper.find('.k-grid-footer');
                if (footerTemplate) {
                    html = $(that._wrapFooter(footerTemplate(aggregates)));
                    if (footer.length) {
                        var tmp = html;
                        that.angular('cleanup', function () {
                            return { elements: footer.get() };
                        });
                        footer.replaceWith(tmp);
                        footer = that.footer = tmp;
                    } else {
                        if (options.scrollable) {
                            footer = that.footer = options.pageable ? html.insertBefore(that.wrapper.children('div.k-grid-pager')) : html.appendTo(that.wrapper);
                        } else {
                            footer = that.footer = html.insertBefore(that.tbody);
                        }
                    }
                    that.angular('compile', function () {
                        return {
                            elements: footer.find('td:not(.k-group-cell, .k-hierarchy-cell)').get(),
                            data: map(that.columns, function (col) {
                                return {
                                    column: col,
                                    aggregate: aggregates[col.field]
                                };
                            })
                        };
                    });
                } else if (footer && !that.footer) {
                    that.footer = footer;
                }
                if (footer.length) {
                    if (options.scrollable) {
                        footerWrap = footer.attr('tabindex', -1).children('.k-grid-footer-wrap');
                        that.scrollables = $(that.scrollables.filter(function () {
                            return !$(this).is('.k-grid-footer-wrap');
                        }).toArray()).add(footerWrap);
                    }
                    if (that._footerWidth) {
                        footer.find('table').css('width', that._footerWidth);
                    }
                    if (footerWrap) {
                        var offset = that.content.scrollLeft();
                        if (options.scrollable !== true && options.scrollable.virtual) {
                            offset = that.wrapper.find('.k-virtual-scrollable-wrap').scrollLeft();
                        }
                        footerWrap.scrollLeft(offset);
                    }
                }
                if (that.lockedContent) {
                    that._appendLockedColumnFooter();
                    that._applyLockedContainersWidth();
                    that._syncLockedFooterHeight();
                }
            },
            _wrapFooter: function (footerRow) {
                var that = this, html = '', scrollbar = !kendo.support.mobileOS ? kendo.support.scrollbar() : 0;
                if (that.options.scrollable) {
                    html = $('<div class="k-grid-footer"><div class="k-grid-footer-wrap"><table' + (isIE7 ? ' cellspacing="0"' : '') + '><tbody>' + footerRow + '</tbody></table></div></div>');
                    that._appendCols(html.find('table'));
                    html.css(isRtl ? 'padding-left' : 'padding-right', scrollbar);
                    return html;
                }
                return '<tfoot class="k-grid-footer">' + footerRow + '</tfoot>';
            },
            _columnMenu: function () {
                var that = this, menu, columns = leafColumns(that.columns), column, options = that.options, columnMenu = options.columnMenu, menuOptions, sortable, filterable, cells, hasMultiColumnHeaders = grep(that.columns, function (item) {
                        return item.columns !== undefined;
                    }).length > 0, isMobile = this._isMobile, initCallback = function (e) {
                        that.trigger(COLUMNMENUINIT, {
                            field: e.field,
                            container: e.container
                        });
                    }, openCallback = function (e) {
                        that.trigger(COLUMNMENUOPEN, {
                            field: e.field,
                            container: e.container
                        });
                    }, closeCallback = function (element) {
                        focusTable(element.closest('table'), true);
                    }, sortHandler = function (e) {
                        if (that.trigger('sort', { sort: e.sort })) {
                            e.preventDefault();
                        }
                    }, filterHandler = function (e) {
                        if (that.trigger('filter', {
                                filter: e.filter,
                                field: e.field
                            })) {
                            e.preventDefault();
                        }
                    }, $angular = options.$angular;
                if (columnMenu) {
                    if (typeof columnMenu == 'boolean') {
                        columnMenu = {};
                    }
                    cells = leafDataCells(that.thead);
                    for (var idx = 0, length = cells.length; idx < length; idx++) {
                        column = columns[idx];
                        var cell = cells.eq(idx);
                        if (!column.command && (column.field || cell.attr('data-' + kendo.ns + 'field'))) {
                            menu = cell.data('kendoColumnMenu');
                            if (menu) {
                                menu.destroy();
                            }
                            sortable = column.sortable !== false && columnMenu.sortable !== false && options.sortable !== false ? extend({}, options.sortable, { compare: (column.sortable || {}).compare }) : false;
                            filterable = options.filterable && column.filterable !== false && columnMenu.filterable !== false ? extend({ pane: that.pane }, options.filterable, column.filterable) : false;
                            if (column.filterable && column.filterable.dataSource) {
                                filterable.forceUnique = false;
                                filterable.checkSource = column.filterable.dataSource;
                            }
                            if (filterable) {
                                filterable.format = column.format;
                            }
                            menuOptions = {
                                dataSource: that.dataSource,
                                values: column.values,
                                columns: columnMenu.columns,
                                sortable: sortable,
                                filterable: filterable,
                                messages: columnMenu.messages,
                                owner: that,
                                closeCallback: closeCallback,
                                init: initCallback,
                                open: openCallback,
                                pane: that.pane,
                                sort: sortHandler,
                                filtering: filterHandler,
                                filter: isMobile ? ':not(.k-column-active)' : '',
                                lockedColumns: !hasMultiColumnHeaders && column.lockable !== false && lockedColumns(columns).length > 0
                            };
                            if ($angular) {
                                menuOptions.$angular = $angular;
                            }
                            cell.kendoColumnMenu(menuOptions);
                        }
                    }
                }
            },
            _headerCells: function () {
                return this.thead.find('th').filter(function () {
                    var th = $(this);
                    return !th.hasClass('k-group-cell') && !th.hasClass('k-hierarchy-cell');
                });
            },
            _filterable: function () {
                var that = this, columns = leafColumns(that.columns), filterMenu, cells, cell, filterInit = function (e) {
                        that.trigger(FILTERMENUINIT, {
                            field: e.field,
                            container: e.container
                        });
                    }, closeCallback = function (element) {
                        focusTable(element.closest('table'), true);
                    }, filterHandler = function (e) {
                        if (that.trigger('filter', {
                                filter: e.filter,
                                field: e.field
                            })) {
                            e.preventDefault();
                        }
                    }, filterOpen = function (e) {
                        that.trigger(FILTERMENUOPEN, {
                            field: e.field,
                            container: e.container
                        });
                    }, filterable = that.options.filterable;
                if (filterable && typeof filterable.mode == STRING && filterable.mode.indexOf('menu') == -1) {
                    filterable = false;
                }
                if (filterable && !that.options.columnMenu) {
                    cells = leafDataCells(that.thead);
                    for (var idx = 0, length = cells.length; idx < length; idx++) {
                        cell = cells.eq(idx);
                        if (columns[idx].filterable !== false && !columns[idx].command && (columns[idx].field || cell.attr('data-' + kendo.ns + 'field'))) {
                            filterMenu = cell.data('kendoFilterMenu');
                            if (filterMenu) {
                                filterMenu.destroy();
                            }
                            filterMenu = cell.data('kendoFilterMultiCheck');
                            if (filterMenu) {
                                filterMenu.destroy();
                            }
                            var columnFilterable = columns[idx].filterable;
                            var options = extend({}, filterable, columnFilterable, {
                                dataSource: that.dataSource,
                                values: columns[idx].values,
                                format: columns[idx].format,
                                closeCallback: closeCallback,
                                title: columns[idx].title || columns[idx].field,
                                init: filterInit,
                                open: filterOpen,
                                pane: that.pane,
                                change: filterHandler
                            });
                            if (columnFilterable && columnFilterable.messages) {
                                options.messages = extend(true, {}, filterable.messages, columnFilterable.messages);
                            }
                            if (columnFilterable && columnFilterable.dataSource) {
                                options.forceUnique = false;
                                options.checkSource = columnFilterable.dataSource;
                            }
                            if (columnFilterable && columnFilterable.multi) {
                                cell.kendoFilterMultiCheck(options);
                            } else {
                                cell.kendoFilterMenu(options);
                            }
                        }
                    }
                }
            },
            _filterRow: function () {
                var that = this;
                if (!that._hasFilterRow()) {
                    return;
                }
                var settings;
                var $angular = that.options.$angular;
                var columns = leafColumns(that.columns), filterable = that.options.filterable, rowheader = that.thead.find('.k-filter-row'), filterHandler = function (e) {
                        if (that.trigger('filter', {
                                filter: e.filter,
                                field: e.field
                            })) {
                            e.preventDefault();
                        }
                    };
                this._updateHeader(this.dataSource.group().length);
                for (var i = 0; i < columns.length; i++) {
                    var suggestDataSource, col = columns[i], operators = that.options.filterable.operators, customDataSource = false, th = $('<th/>'), field = col.field;
                    if (col.hidden) {
                        th.hide();
                    }
                    rowheader.append(th);
                    if (field && col.filterable !== false) {
                        var cellOptions = col.filterable && col.filterable.cell || {};
                        suggestDataSource = that.options.dataSource;
                        if (suggestDataSource instanceof DataSource) {
                            suggestDataSource = that.options.dataSource.options;
                        }
                        var messages = extend(true, {}, filterable.messages);
                        if (col.filterable) {
                            extend(true, messages, col.filterable.messages);
                        }
                        if (cellOptions.enabled === false) {
                            th.html('&nbsp;');
                            continue;
                        }
                        if (cellOptions.dataSource) {
                            suggestDataSource = cellOptions.dataSource;
                            customDataSource = true;
                        }
                        if (col.filterable && col.filterable.operators) {
                            operators = col.filterable.operators;
                        }
                        settings = {
                            column: col,
                            dataSource: that.dataSource,
                            suggestDataSource: suggestDataSource,
                            customDataSource: customDataSource,
                            field: field,
                            messages: messages,
                            values: col.values,
                            template: cellOptions.template,
                            delay: cellOptions.delay,
                            inputWidth: cellOptions.inputWidth,
                            suggestionOperator: cellOptions.suggestionOperator,
                            minLength: cellOptions.minLength,
                            dataTextField: cellOptions.dataTextField,
                            operator: cellOptions.operator,
                            operators: operators,
                            showOperators: cellOptions.showOperators,
                            change: filterHandler
                        };
                        if ($angular) {
                            settings.$angular = $angular;
                        }
                        $('<span/>').attr(kendo.attr('field'), field).appendTo(th).kendoFilterCell(settings);
                    } else {
                        th.html('&nbsp;');
                    }
                }
            },
            _sortable: function () {
                var that = this, columns = leafColumns(that.columns), column, sorterInstance, cell, sortable = that.options.sortable, sortHandler = function (e) {
                        if (that.trigger('sort', { sort: e.sort })) {
                            e.preventDefault();
                        }
                    };
                if (sortable) {
                    var cells = leafDataCells(that.thead);
                    for (var idx = 0, length = cells.length; idx < length; idx++) {
                        column = columns[idx];
                        if (column.sortable !== false && !column.command && column.field) {
                            cell = cells.eq(idx);
                            sorterInstance = cell.data('kendoColumnSorter');
                            if (sorterInstance) {
                                sorterInstance.destroy();
                            }
                            cell.attr('data-' + kendo.ns + 'field', column.field).kendoColumnSorter(extend({}, sortable, column.sortable, {
                                dataSource: that.dataSource,
                                aria: true,
                                filter: ':not(.k-column-active)',
                                change: sortHandler
                            }));
                        }
                    }
                    cells = null;
                }
            },
            _columns: function (columns) {
                var that = this, table = that.table, encoded, cols = table.find('col'), lockedCols, dataSource = that.options.dataSource;
                columns = columns.length ? columns : map(table.find('th'), function (th, idx) {
                    th = $(th);
                    var sortable = th.attr(kendo.attr('sortable')), filterable = th.attr(kendo.attr('filterable')), type = th.attr(kendo.attr('type')), groupable = th.attr(kendo.attr('groupable')), field = th.attr(kendo.attr('field')), title = th.attr(kendo.attr('title')), menu = th.attr(kendo.attr('menu'));
                    if (!field) {
                        field = th.text().replace(/\s|[^A-z0-9]/g, '');
                    }
                    return {
                        field: field,
                        type: type,
                        title: title,
                        sortable: sortable !== 'false',
                        filterable: filterable !== 'false',
                        groupable: groupable !== 'false',
                        menu: menu,
                        template: th.attr(kendo.attr('template')),
                        width: cols.eq(idx).css('width')
                    };
                });
                encoded = !(that.table.find('tbody tr').length > 0 && (!dataSource || !dataSource.transport));
                if (that.options.scrollable) {
                    var initialColumns = columns;
                    lockedCols = lockedColumns(columns);
                    columns = nonLockedColumns(columns);
                    if (lockedCols.length > 0 && columns.length === 0) {
                        throw new Error('There should be at least one non locked column');
                    }
                    normalizeHeaderCells(that.element.find('tr:has(th):first'), initialColumns);
                    columns = lockedCols.concat(columns);
                }
                that.columns = normalizeColumns(columns, encoded);
            },
            _groups: function () {
                var group = this.dataSource.group();
                return group ? group.length : 0;
            },
            _tmpl: function (rowTemplate, columns, alt, skipGroupCells) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), idx, length = columns.length, template, state = {
                        storage: {},
                        count: 0
                    }, column, type, hasDetails = that._hasDetails(), className = [], groups = that._groups(), navigatable = that.options.navigatable;
                if (!rowTemplate) {
                    rowTemplate = '<tr';
                    if (alt) {
                        className.push('k-alt');
                    }
                    if (hasDetails) {
                        className.push('k-master-row');
                    }
                    if (className.length) {
                        rowTemplate += ' class="' + className.join(' ') + '"';
                    }
                    if (length) {
                        rowTemplate += ' ' + kendo.attr('uid') + '="#=' + kendo.expr('uid', settings.paramName) + '#"';
                    }
                    rowTemplate += ' role=\'row\'>';
                    if (groups > 0 && !skipGroupCells) {
                        rowTemplate += groupCells(groups);
                    }
                    if (hasDetails) {
                        rowTemplate += '<td class="k-hierarchy-cell"><a class="k-icon k-i-expand" href="\\#" ' + ARIALABEL + '="' + EXPAND + '" tabindex="-1"></a></td>';
                    }
                    for (idx = 0; idx < length; idx++) {
                        column = columns[idx];
                        template = column.template;
                        type = typeof template;
                        rowTemplate += '<td' + stringifyAttributes(column.attributes);
                        if (navigatable) {
                            rowTemplate += ' aria-describedby=\'' + column.headerAttributes.id + '\'';
                        }
                        rowTemplate += ' role=\'gridcell\'>';
                        rowTemplate += that._cellTmpl(column, state);
                        rowTemplate += '</td>';
                    }
                    rowTemplate += '</tr>';
                }
                rowTemplate = kendo.template(rowTemplate, settings);
                if (state.count > 0) {
                    return proxy(rowTemplate, state.storage);
                }
                return rowTemplate;
            },
            _headerCellText: function (column) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), template = column.headerTemplate, type = typeof template, text = column.title || column.field || '';
                if (type === FUNCTION) {
                    text = kendo.template(template, settings)({});
                } else if (type === STRING) {
                    text = template;
                }
                return text;
            },
            _cellTmpl: function (column, state) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), template = column.template, paramName = settings.paramName, field = column.field, html = '', idx, length, format = column.format, type = typeof template, columnValues = column.values;
                if (column.command) {
                    if (isArray(column.command)) {
                        for (idx = 0, length = column.command.length; idx < length; idx++) {
                            if (column.command[idx].visible) {
                                html += kendo.format('#= {0}(data)? \'{1}\':\'\' #', column.command[idx].visible, that._createButton(column.command[idx]).replace(templateHashRegExp, '\\#'));
                            } else {
                                html += that._createButton(column.command[idx]).replace(templateHashRegExp, '\\#');
                            }
                        }
                        return html;
                    }
                    return that._createButton(column.command).replace(templateHashRegExp, '\\#');
                }
                if (type === FUNCTION) {
                    state.storage['tmpl' + state.count] = template;
                    html += '#=this.tmpl' + state.count + '(' + paramName + ')#';
                    state.count++;
                } else if (type === STRING) {
                    html += template;
                } else if (columnValues && columnValues.length && isPlainObject(columnValues[0]) && 'value' in columnValues[0] && field) {
                    html += '#var v =' + kendo.stringify(convertToObject(columnValues)).replace(templateHashRegExp, '\\#') + '#';
                    html += '#var f = v[';
                    if (!settings.useWithBlock) {
                        html += paramName + '.';
                    }
                    html += field + ']#';
                    html += '${f != null ? f : \'\'}';
                } else {
                    html += column.encoded ? '#:' : '#=';
                    if (format) {
                        html += 'kendo.format("' + format.replace(formatRegExp, '\\$1') + '",';
                    }
                    if (field) {
                        field = kendo.expr(field, paramName);
                        html += field + '==null?\'\':' + field;
                    } else {
                        html += '\'\'';
                    }
                    if (format) {
                        html += ')';
                    }
                    html += '#';
                }
                return html;
            },
            _templates: function () {
                var that = this, options = that.options, dataSource = that.dataSource, groups = dataSource.group(), footer = that.footer || that.wrapper.find('.k-grid-footer'), aggregates = dataSource.aggregate(), columnLeafs = leafColumns(that.columns), columnsLocked = leafColumns(lockedColumns(that.columns)), columns = options.scrollable ? leafColumns(nonLockedColumns(that.columns)) : columnLeafs;
                if (options.scrollable && columnsLocked.length) {
                    if (options.rowTemplate || options.altRowTemplate) {
                        throw new Error('Having both row template and locked columns is not supported');
                    }
                    that.rowTemplate = that._tmpl(options.rowTemplate, columns, false, true);
                    that.altRowTemplate = that._tmpl(options.altRowTemplate || options.rowTemplate, columns, true, true);
                    that.lockedRowTemplate = that._tmpl(options.rowTemplate, columnsLocked);
                    that.lockedAltRowTemplate = that._tmpl(options.altRowTemplate || options.rowTemplate, columnsLocked, true);
                } else {
                    that.rowTemplate = that._tmpl(options.rowTemplate, columns);
                    that.altRowTemplate = that._tmpl(options.altRowTemplate || options.rowTemplate, columns, true);
                }
                if (that._hasDetails()) {
                    that.detailTemplate = that._detailTmpl(options.detailTemplate || '');
                }
                if (that._group && !isEmptyObject(aggregates) || !isEmptyObject(aggregates) && !footer.length || grep(columnLeafs, function (column) {
                        return column.footerTemplate;
                    }).length) {
                    that.footerTemplate = that._footerTmpl(columnLeafs, aggregates, 'footerTemplate', 'k-footer-template');
                }
                if (groups && grep(columnLeafs, function (column) {
                        return column.groupFooterTemplate;
                    }).length) {
                    aggregates = $.map(groups, function (g) {
                        return g.aggregates;
                    });
                    that.groupFooterTemplate = that._footerTmpl(columns, aggregates, 'groupFooterTemplate', 'k-group-footer', columnsLocked.length);
                    if (options.scrollable && columnsLocked.length) {
                        that.lockedGroupFooterTemplate = that._footerTmpl(columnsLocked, aggregates, 'groupFooterTemplate', 'k-group-footer');
                    }
                }
                if (that.options.noRecords) {
                    that.noRecordsTemplate = that._noRecordsTmpl();
                }
            },
            _noRecordsTmpl: function () {
                var wrapper = '<div class="{0}">{1}</div>';
                var defaultTemplate = '<div class="k-grid-norecords-template"{1}>{0}</div>';
                var scrollableNoGridHeightStyles = this.options.scrollable && !this.wrapper[0].style.height ? ' style="margin:0 auto;position:static;"' : '';
                var state = {
                    storage: {},
                    count: 0
                };
                var settings = $.extend({}, kendo.Template, this.options.templateSettings);
                var paramName = settings.paramName;
                var template;
                var html = '';
                var type;
                var tmpl;
                if (this.options.noRecords.template) {
                    template = this.options.noRecords.template;
                } else {
                    template = kendo.format(defaultTemplate, this.options.messages.noRecords, scrollableNoGridHeightStyles);
                }
                type = typeof template;
                if (type === 'function') {
                    state.storage['tmpl' + state.count] = template;
                    html += '#=this.tmpl' + state.count + '(' + paramName + ')#';
                    state.count++;
                } else if (type === 'string') {
                    html += template;
                }
                tmpl = kendo.template(kendo.format(wrapper, NORECORDSCLASS, html), settings);
                if (state.count > 0) {
                    tmpl = $.proxy(tmpl, state.storage);
                }
                return tmpl;
            },
            _footerTmpl: function (columns, aggregates, templateName, rowClass, skipGroupCells) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), paramName = settings.paramName, html = '', idx, length, template, type, storage = {}, count = 0, scope = {}, groups = that._groups(), fieldsMap = that.dataSource._emptyAggregates(aggregates), column;
                html += '<tr class="' + rowClass + '">';
                if (groups > 0 && !skipGroupCells) {
                    html += groupCells(groups);
                }
                if (that._hasDetails()) {
                    html += '<td class="k-hierarchy-cell">&nbsp;</td>';
                }
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    template = column[templateName];
                    type = typeof template;
                    html += '<td' + stringifyAttributes(column.footerAttributes) + '>';
                    if (template) {
                        if (type !== FUNCTION) {
                            scope = fieldsMap[column.field] ? extend({}, settings, { paramName: paramName + '[\'' + column.field + '\']' }) : {};
                            template = kendo.template(template, scope);
                        }
                        storage['tmpl' + count] = template;
                        html += '#=this.tmpl' + count + '(' + paramName + ')#';
                        count++;
                    } else {
                        html += '&nbsp;';
                    }
                    html += '</td>';
                }
                html += '</tr>';
                html = kendo.template(html, settings);
                if (count > 0) {
                    return proxy(html, storage);
                }
                return html;
            },
            _detailTmpl: function (template) {
                var that = this, html = '', settings = extend({}, kendo.Template, that.options.templateSettings), paramName = settings.paramName, templateFunctionStorage = {}, templateFunctionCount = 0, groups = that._groups(), colspan = visibleColumns(leafColumns(that.columns)).length, type = typeof template;
                html += '<tr class="k-detail-row">';
                if (groups > 0) {
                    html += groupCells(groups);
                }
                html += '<td class="k-hierarchy-cell"></td><td class="k-detail-cell"' + (colspan ? ' colspan="' + colspan + '"' : '') + '>';
                if (type === FUNCTION) {
                    templateFunctionStorage['tmpl' + templateFunctionCount] = template;
                    html += '#=this.tmpl' + templateFunctionCount + '(' + paramName + ')#';
                    templateFunctionCount++;
                } else {
                    html += template;
                }
                html += '</td></tr>';
                html = kendo.template(html, settings);
                if (templateFunctionCount > 0) {
                    return proxy(html, templateFunctionStorage);
                }
                return html;
            },
            _hasDetails: function () {
                var that = this;
                return that.options.detailTemplate !== null || (that._events[DETAILINIT] || []).length;
            },
            _hasFilterRow: function () {
                var filterable = this.options.filterable;
                var hasFiltering = filterable && typeof filterable.mode == STRING && filterable.mode.indexOf('row') != -1;
                var columns = this.columns;
                var columnsWithoutFiltering = $.grep(columns, function (col) {
                    return col.filterable === false;
                });
                if (columns.length && columnsWithoutFiltering.length == columns.length) {
                    hasFiltering = false;
                }
                return hasFiltering;
            },
            _details: function () {
                var that = this;
                if (that.options.scrollable && that._hasDetails() && lockedColumns(that.columns).length) {
                    throw new Error('Having both detail template and locked columns is not supported');
                }
                that.table.on(CLICK + NS, '.k-hierarchy-cell .k-i-expand, .k-hierarchy-cell .k-i-collapse', function (e) {
                    var button = $(this), expanding = button.hasClass('k-i-expand'), masterRow = button.closest('tr.k-master-row'), detailRow, detailTemplate = that.detailTemplate, data, hasDetails = that._hasDetails(), ariaLabelText = expanding ? COLLAPSE : EXPAND;
                    button.toggleClass('k-i-expand', !expanding).toggleClass('k-i-collapse', expanding).attr(ARIALABEL, ariaLabelText);
                    detailRow = masterRow.next();
                    if (hasDetails && !detailRow.hasClass('k-detail-row')) {
                        data = that.dataItem(masterRow);
                        detailRow = $(detailTemplate(data)).addClass(masterRow.hasClass('k-alt') ? 'k-alt' : '').insertAfter(masterRow);
                        that.angular('compile', function () {
                            return {
                                elements: detailRow.get(),
                                data: [{ dataItem: data }]
                            };
                        });
                        that.trigger(DETAILINIT, {
                            masterRow: masterRow,
                            detailRow: detailRow,
                            data: data,
                            detailCell: detailRow.find('.k-detail-cell')
                        });
                    }
                    that.trigger(expanding ? DETAILEXPAND : DETAILCOLLAPSE, {
                        masterRow: masterRow,
                        detailRow: detailRow
                    });
                    detailRow.toggle(expanding);
                    if (that._current) {
                        that._current.attr('aria-expanded', expanding);
                    }
                    e.preventDefault();
                    return false;
                });
            },
            dataItem: function (tr) {
                tr = $(tr)[0];
                if (!tr) {
                    return null;
                }
                var rows = this.tbody.children(), classesRegEx = /k-grouping-row|k-detail-row|k-group-footer/, idx = tr.sectionRowIndex, j, correctIdx;
                correctIdx = idx;
                for (j = 0; j < idx; j++) {
                    if (classesRegEx.test(rows[j].className)) {
                        correctIdx--;
                    }
                }
                return this._data[correctIdx];
            },
            expandRow: function (tr) {
                $(tr).find('> td .k-i-expand').click();
            },
            collapseRow: function (tr) {
                $(tr).find('> td .k-i-collapse').click();
            },
            _createHeaderCells: function (columns, rowSpan) {
                var that = this, idx, th, text, html = '', length, leafs = leafColumns(that.columns), field;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    th = columns[idx].column || columns[idx];
                    text = that._headerCellText(th);
                    field = '';
                    var index = inArray(th, leafs);
                    if (!th.command) {
                        if (th.field) {
                            field = kendo.attr('field') + '=\'' + th.field + '\' ';
                        }
                        html += '<th scope=\'col\' role=\'columnheader\' ' + field;
                        html += ' aria-haspopup=\'true\'';
                        if (rowSpan && !columns[idx].colSpan) {
                            html += ' rowspan=\'' + rowSpan + '\'';
                        }
                        if (columns[idx].colSpan > 1) {
                            html += 'colspan="' + (columns[idx].colSpan - hiddenLeafColumnsCount(th.columns)) + '" ';
                            html += kendo.attr('colspan') + '=\'' + columns[idx].colSpan + '\'';
                        }
                        if (th.title) {
                            html += kendo.attr('title') + '="' + th.title.replace('"', '&quot;').replace(/'/g, '\'') + '" ';
                        }
                        if (th.groupable !== undefined) {
                            html += kendo.attr('groupable') + '=\'' + th.groupable + '\' ';
                        }
                        if (th.aggregates && th.aggregates.length) {
                            html += kendo.attr('aggregates') + '=\'' + th.aggregates + '\'';
                        }
                        if (index > -1) {
                            html += kendo.attr('index') + '=\'' + index + '\'';
                        }
                        html += stringifyAttributes(th.headerAttributes);
                        html += '>' + text + '</th>';
                    } else {
                        html += '<th scope=\'col\'' + stringifyAttributes(th.headerAttributes);
                        if (rowSpan && !columns[idx].colSpan) {
                            html += ' rowspan=\'' + rowSpan + '\'';
                        }
                        if (index > -1) {
                            html += kendo.attr('index') + '=\'' + index + '\'';
                        }
                        html += '>' + text + '</th>';
                    }
                }
                return html;
            },
            _appendLockedColumnContent: function () {
                var columns = this.columns, idx, colgroup = this.table.find('colgroup'), cols = colgroup.find('col:not(.k-group-col,.k-hierarchy-col)'), length, lockedCols = $(), skipHiddenCount = 0, container, colSpan, spanIdx, colOffset = 0;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    if (columns[idx].locked) {
                        if (isVisible(columns[idx])) {
                            colSpan = 1;
                            if (columns[idx].columns) {
                                colSpan = leafColumns(columns[idx].columns).length - hiddenLeafColumnsCount(columns[idx].columns);
                            }
                            colSpan = colSpan || 1;
                            for (spanIdx = 0; spanIdx < colSpan; spanIdx++) {
                                lockedCols = lockedCols.add(cols.eq(idx + colOffset + spanIdx - skipHiddenCount));
                            }
                            colOffset += colSpan - 1;
                        } else {
                            skipHiddenCount++;
                        }
                    }
                }
                container = $('<div class="k-grid-content-locked"><table' + (isIE7 ? ' cellspacing="0"' : '') + '><colgroup/><tbody></tbody></table></div>');
                colgroup.detach();
                container.find('colgroup').append(lockedCols);
                colgroup.insertBefore(this.table.find('tbody'));
                this.lockedContent = container.insertBefore(this.content);
                this.lockedTable = container.children('table');
            },
            _appendLockedColumnFooter: function () {
                var that = this;
                var footer = that.footer;
                var cells = footer.find('.k-footer-template>td');
                var cols = footer.find('.k-grid-footer-wrap>table>colgroup>col');
                var html = $('<div class="k-grid-footer-locked"><table><colgroup /><tbody><tr class="k-footer-template"></tr></tbody></table></div>');
                var idx, length;
                var groups = that._groups();
                var lockedCells = $(), lockedCols = $();
                lockedCells = lockedCells.add(cells.filter('.k-group-cell'));
                for (idx = 0, length = leafColumns(lockedColumns(that.columns)).length; idx < length; idx++) {
                    lockedCells = lockedCells.add(cells.eq(idx + groups));
                }
                lockedCols = lockedCols.add(cols.filter('.k-group-col'));
                for (idx = 0, length = visibleColumns(leafColumns(visibleLockedColumns(that.columns))).length; idx < length; idx++) {
                    lockedCols = lockedCols.add(cols.eq(idx + groups));
                }
                lockedCells.appendTo(html.find('tr'));
                lockedCols.appendTo(html.find('colgroup'));
                that.lockedFooter = html.prependTo(footer);
            },
            _appendLockedColumnHeader: function (container) {
                var that = this, columns = this.columns, idx, html, length, colgroup, tr, trFilter, table, header, filtercellCells, rows = [], skipHiddenCount = 0, cols = $(), hasFilterRow = that._hasFilterRow(), filterCellOffset = 0, filterCells = $(), cell, leafColumnsCount = 0, cells = $();
                colgroup = that.thead.prev().find('col:not(.k-group-col,.k-hierarchy-col)');
                header = that.thead.find('tr:first .k-header:not(.k-group-cell,.k-hierarchy-cell)');
                filtercellCells = that.thead.find('.k-filter-row').find('th:not(.k-group-cell,.k-hierarchy-cell)');
                var colOffset = 0;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    if (columns[idx].locked) {
                        cell = header.eq(idx);
                        leafColumnsCount = leafColumns(columns[idx].columns || []).length;
                        if (isVisible(columns[idx])) {
                            var colSpan = null;
                            if (columns[idx].columns) {
                                colSpan = leafColumnsCount - hiddenLeafColumnsCount(columns[idx].columns);
                            }
                            colSpan = colSpan || 1;
                            for (var spanIdx = 0; spanIdx < colSpan; spanIdx++) {
                                cols = cols.add(colgroup.eq(idx + colOffset + spanIdx - skipHiddenCount));
                            }
                            colOffset += colSpan - 1;
                        }
                        mapColumnToCellRows([columns[idx]], childColumnsCells(cell), rows, 0, 0);
                        leafColumnsCount = leafColumnsCount || 1;
                        for (var j = 0; j < leafColumnsCount; j++) {
                            filterCells = filterCells.add(filtercellCells.eq(filterCellOffset + j));
                        }
                        filterCellOffset += leafColumnsCount;
                    }
                    if (columns[idx].columns) {
                        skipHiddenCount += hiddenLeafColumnsCount(columns[idx].columns);
                    }
                    if (!isVisible(columns[idx])) {
                        skipHiddenCount++;
                    }
                }
                if (rows.length) {
                    html = '<div class="k-grid-header-locked" style="width:1px"><table' + (isIE7 ? ' cellspacing="0"' : '') + '><colgroup/><thead>';
                    html += new Array(rows.length + 1).join('<tr></tr>');
                    html += (hasFilterRow ? '<tr class="k-filter-row" />' : '') + '</thead></table></div>';
                    table = $(html);
                    colgroup = table.find('colgroup');
                    colgroup.append(that.thead.prev().find('col.k-group-col').add(cols));
                    tr = table.find('thead tr:not(.k-filter-row)');
                    for (idx = 0, length = rows.length; idx < length; idx++) {
                        cells = toJQuery(rows[idx]);
                        tr.eq(idx).append(that.thead.find('tr:eq(' + idx + ') .k-group-cell').add(cells));
                    }
                    var count = removeEmptyRows(this.thead);
                    if (rows.length < count) {
                        removeRowSpanValue(table, count - rows.length);
                    }
                    trFilter = table.find('.k-filter-row');
                    trFilter.append(that.thead.find('.k-filter-row .k-group-cell').add(filterCells));
                    this.lockedHeader = table.prependTo(container);
                    this.thead.find('.k-group-cell').remove();
                    return true;
                }
                return false;
            },
            _removeLockedContainers: function () {
                var elements = this.lockedHeader.add(this.lockedContent).add(this.lockedFooter);
                kendo.destroy(elements);
                elements.off(NS).remove();
                this.lockedHeader = this.lockedContent = this.lockedFooter = null;
                this.selectable = null;
            },
            _thead: function () {
                var that = this, columns = that.columns, hasDetails = that._hasDetails() && columns.length, hasFilterRow = that._hasFilterRow(), idx, html = '', thead = that.table.find('>thead'), hasTHead = that.element.find('thead:first').length > 0, tr;
                if (!thead.length) {
                    thead = $('<thead/>').insertBefore(that.tbody);
                }
                if (that.lockedHeader && that.thead) {
                    tr = that.thead.find('tr:has(th):not(.k-filter-row)').html('');
                    tr.remove();
                    tr = $();
                    that._removeLockedContainers();
                } else if (hasTHead) {
                    tr = that.element.find('thead:first tr:has(th):not(.k-filter-row)');
                } else {
                    tr = that.element.find('tr:has(th):first');
                }
                if (!tr.length) {
                    tr = thead.children().first();
                    if (!tr.length) {
                        var rows = [{
                                rowSpan: 1,
                                cells: [],
                                index: 0
                            }];
                        that._prepareColumns(rows, columns);
                        for (idx = 0; idx < rows.length; idx++) {
                            html += '<tr>';
                            if (hasDetails) {
                                html += '<th class="k-hierarchy-cell" scope="col">' + that.options.messages.expandCollapseColumnHeader + '</th>';
                            }
                            html += that._createHeaderCells(rows[idx].cells, rows[idx].rowSpan);
                            html += '</tr>';
                        }
                        tr = $(html);
                    }
                }
                if (hasFilterRow) {
                    var filterRow = $('<tr/>');
                    filterRow.addClass('k-filter-row');
                    if (hasDetails || tr.find('.k-hierarchy-cell').length) {
                        filterRow.prepend('<th class="k-hierarchy-cell" scope="col">&nbsp;</th>');
                    }
                    var existingFilterRow = (that.thead || thead).find('.k-filter-row');
                    if (existingFilterRow.length) {
                        kendo.destroy(existingFilterRow);
                        existingFilterRow.remove();
                    }
                    thead.append(filterRow);
                }
                if (!tr.children().length) {
                    html = '';
                    if (hasDetails) {
                        html += '<th class="k-hierarchy-cell" scope="col">&nbsp;</th>';
                    }
                    html += that._createHeaderCells(columns);
                    tr.html(html);
                } else if (hasDetails && !tr.find('.k-hierarchy-cell')[0]) {
                    tr.prepend('<th class="k-hierarchy-cell" scope="col">&nbsp;</th>');
                }
                tr.attr('role', 'row').find('th').addClass('k-header');
                if (!that.options.scrollable) {
                    thead.addClass('k-grid-header');
                }
                tr.find('script').remove().end().prependTo(thead);
                if (that.thead) {
                    that._destroyColumnAttachments();
                }
                this.angular('cleanup', function () {
                    return { elements: thead.find('th').get() };
                });
                this.angular('compile', function () {
                    return {
                        elements: thead.find('th').get(),
                        data: map(columns, function (col) {
                            return { column: col };
                        })
                    };
                });
                that.thead = thead.attr('role', 'rowgroup');
                that._sortable();
                that._filterable();
                that._filterRow();
                that._scrollable();
                that._updateCols();
                that._columnMenu();
                var syncHeight;
                var hasLockedColumns = this.options.scrollable && lockedColumns(this.columns).length;
                if (hasLockedColumns) {
                    syncHeight = that._appendLockedColumnHeader(that.thead.closest('.k-grid-header'));
                    that._appendLockedColumnContent();
                    that.lockedContent.bind('DOMMouseScroll' + NS + ' mousewheel' + NS, proxy(that._wheelScroll, that));
                }
                that._updateColumnCellIndex();
                that._updateFirstColumnClass();
                that._resizable();
                that._draggable();
                that._reorderable();
                that._updateHeader(that._groups());
                if (hasLockedColumns) {
                    if (syncHeight) {
                        that._syncLockedHeaderHeight();
                    }
                    that._applyLockedContainersWidth();
                }
                if (that.groupable) {
                    that._attachGroupable();
                }
            },
            _retrieveFirstColumn: function (columns, rows) {
                var result = $();
                if (rows.length && columns[0]) {
                    var column = columns[0];
                    while (column.columns && column.columns.length) {
                        column = column.columns[0];
                        rows = rows.filter(':not(:first())');
                    }
                    result = result.add(rows);
                }
                return result;
            },
            _updateFirstColumnClass: function () {
                var that = this, columns = that.columns || [], hasDetails = that._hasDetails() && columns.length;
                if (!hasDetails && !that._groups()) {
                    var tr = that.thead.find('>tr:not(.k-filter-row):not(:first)');
                    columns = nonLockedColumns(columns);
                    var rows = that._retrieveFirstColumn(columns, tr);
                    if (that._isLocked()) {
                        tr = that.lockedHeader.find('thead>tr:not(.k-filter-row):not(:first)');
                        columns = lockedColumns(that.columns);
                        rows = rows.add(that._retrieveFirstColumn(columns, tr));
                    }
                    rows.each(function () {
                        var ths = $(this).find('th');
                        ths.removeClass('k-first');
                        ths.eq(0).addClass('k-first');
                    });
                }
            },
            _prepareColumns: function (rows, columns, parentCell, parentRow) {
                var row = parentRow || rows[rows.length - 1];
                var childRow = rows[row.index + 1];
                var totalColSpan = 0;
                for (var idx = 0; idx < columns.length; idx++) {
                    var cell = {
                        column: columns[idx],
                        colSpan: 0
                    };
                    row.cells.push(cell);
                    if (columns[idx].columns && columns[idx].columns.length) {
                        if (!childRow) {
                            childRow = {
                                rowSpan: 0,
                                cells: [],
                                index: rows.length
                            };
                            rows.push(childRow);
                        }
                        cell.colSpan = columns[idx].columns.length;
                        this._prepareColumns(rows, columns[idx].columns, cell, childRow);
                        totalColSpan += cell.colSpan - 1;
                        row.rowSpan = rows.length - row.index;
                    }
                }
                if (parentCell) {
                    parentCell.colSpan += totalColSpan;
                }
            },
            _wheelScroll: function (e) {
                if (e.ctrlKey) {
                    return;
                }
                var content = this.content;
                if (this.options.scrollable.virtual) {
                    content = this.virtualScrollable.verticalScrollbar;
                }
                var scrollTop = content.scrollTop(), delta = kendo.wheelDeltaY(e);
                if (delta) {
                    if (content[0].scrollHeight > content[0].clientHeight && (content[0].scrollTop < content[0].scrollHeight - content[0].clientHeight && delta < 0 || content[0].scrollTop > 0 && delta > 0)) {
                        e.preventDefault();
                    }
                    content.scrollTop(scrollTop + -delta);
                }
            },
            _isLocked: function () {
                return this.lockedHeader != null;
            },
            _updateHeaderCols: function () {
                var table = this.thead.parent().add(this.table);
                if (this._isLocked()) {
                    normalizeCols(table, visibleLeafColumns(visibleNonLockedColumns(this.columns)), this._hasDetails(), 0);
                } else {
                    normalizeCols(table, visibleLeafColumns(visibleColumns(this.columns)), this._hasDetails(), 0);
                }
            },
            _updateCols: function (table) {
                table = table || this.thead.parent().add(this.table);
                this._appendCols(table, this._isLocked());
            },
            _updateLockedCols: function (table) {
                if (this._isLocked()) {
                    table = table || this.lockedHeader.find('table').add(this.lockedTable);
                    normalizeCols(table, visibleLeafColumns(visibleLockedColumns(this.columns)), this._hasDetails(), this._groups());
                }
            },
            _appendCols: function (table, locked) {
                if (locked) {
                    normalizeCols(table, visibleLeafColumns(visibleNonLockedColumns(this.columns)), this._hasDetails(), 0);
                } else {
                    normalizeCols(table, visibleLeafColumns(visibleColumns(this.columns)), this._hasDetails(), this._groups());
                }
            },
            _autoColumns: function (schema) {
                if (schema && schema.toJSON) {
                    var that = this, field, encoded;
                    schema = schema.toJSON();
                    encoded = !(that.table.find('tbody tr').length > 0 && (!that.dataSource || !that.dataSource.transport));
                    for (field in schema) {
                        that.columns.push({
                            field: field,
                            encoded: encoded,
                            headerAttributes: { id: kendo.guid() }
                        });
                    }
                    that._thead();
                    that._templates();
                }
            },
            _rowsHtml: function (data, templates) {
                var that = this, html = '', idx, rowTemplate = templates.rowTemplate, altRowTemplate = templates.altRowTemplate, length;
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (idx % 2) {
                        html += altRowTemplate(data[idx]);
                    } else {
                        html += rowTemplate(data[idx]);
                    }
                    that._data.push(data[idx]);
                }
                return html;
            },
            _groupRowHtml: function (group, colspan, level, groupHeaderBuilder, templates, skipColspan) {
                var that = this, html = '', idx, length, field = group.field, column = grep(leafColumns(that.columns), function (column) {
                        return column.field == field;
                    })[0] || {}, template = column.groupHeaderTemplate, text = (column.title || field) + ': ' + formatGroupValue(group.value, column.format, column.values, column.encoded), footerDefaults = that._groupAggregatesDefaultObject || {}, groupItems = group.items, aggregates = extend({}, footerDefaults, group.aggregates), headerData = extend({}, {
                        field: group.field,
                        value: group.value,
                        items: groupItems,
                        aggregates: aggregates
                    }, group.aggregates[group.field]), groupFooterTemplate = templates.groupFooterTemplate;
                if (template) {
                    text = typeof template === FUNCTION ? template(headerData) : kendo.template(template)(headerData);
                }
                html += groupHeaderBuilder(colspan, level, text);
                if (group.hasSubgroups) {
                    for (idx = 0, length = groupItems.length; idx < length; idx++) {
                        html += that._groupRowHtml(groupItems[idx], skipColspan ? colspan : colspan - 1, level + 1, groupHeaderBuilder, templates, skipColspan);
                    }
                } else {
                    html += that._rowsHtml(groupItems, templates);
                }
                if (groupFooterTemplate) {
                    var footerData = {};
                    for (var aggregate in aggregates) {
                        footerData[aggregate] = extend({}, aggregates[aggregate], {
                            group: {
                                field: group.field,
                                value: group.value,
                                items: groupItems
                            }
                        });
                    }
                    html += groupFooterTemplate(footerData);
                }
                return html;
            },
            collapseGroup: function (group) {
                group = $(group);
                var level, groupable = this.options.groupable, showFooter = groupable.showFooter, footerCount = showFooter ? 0 : 1, offset, relatedGroup = $(), idx, length, tr;
                if (this._isLocked()) {
                    if (!group.closest('div').hasClass('k-grid-content-locked')) {
                        relatedGroup = group.nextAll('tr');
                        group = this.lockedTable.find('>tbody>tr:eq(' + group.index() + ')');
                    } else {
                        relatedGroup = this.tbody.children('tr:eq(' + group.index() + ')').nextAll('tr');
                    }
                }
                level = group.find('.k-group-cell').length;
                group.find('.k-i-collapse').addClass('k-i-expand').removeClass('k-i-collapse');
                group.find('td[aria-expanded=\'true\']:first').attr('aria-expanded', false).find('a').attr(ARIALABEL, EXPAND);
                group = group.nextAll('tr');
                var toHide = [];
                for (idx = 0, length = group.length; idx < length; idx++) {
                    tr = group.eq(idx);
                    offset = tr.find('.k-group-cell').length;
                    if (tr.hasClass('k-grouping-row')) {
                        footerCount++;
                    } else if (tr.hasClass('k-group-footer')) {
                        footerCount--;
                    }
                    if (offset <= level || tr.hasClass('k-group-footer') && footerCount < 0) {
                        break;
                    }
                    if (relatedGroup.length) {
                        toHide.push(relatedGroup[idx]);
                    }
                    toHide.push(tr[0]);
                }
                $(toHide).hide();
            },
            expandGroup: function (group) {
                group = $(group);
                var that = this, showFooter = that.options.groupable.showFooter, level, tr, offset, relatedGroup = $(), idx, length, footersVisibility = [], groupsCount = 1;
                if (this._isLocked()) {
                    if (!group.closest('div').hasClass('k-grid-content-locked')) {
                        relatedGroup = group.nextAll('tr');
                        group = this.lockedTable.find('>tbody>tr:eq(' + group.index() + ')');
                    } else {
                        relatedGroup = this.tbody.children('tr:eq(' + group.index() + ')').nextAll('tr');
                    }
                }
                level = group.find('.k-group-cell').length;
                group.find('.k-i-expand').addClass('k-i-collapse').removeClass('k-i-expand');
                group.find('td[aria-expanded=\'false\']:first').attr('aria-expanded', true).find('a').attr(ARIALABEL, COLLAPSE);
                group = group.nextAll('tr');
                for (idx = 0, length = group.length; idx < length; idx++) {
                    tr = group.eq(idx);
                    offset = tr.find('.k-group-cell').length;
                    if (offset <= level) {
                        break;
                    }
                    if (offset == level + 1 && !tr.hasClass('k-detail-row')) {
                        tr.show();
                        relatedGroup.eq(idx).show();
                        if (tr.hasClass('k-grouping-row') && tr.find('.k-icon').hasClass('k-i-collapse')) {
                            that.expandGroup(tr);
                        }
                        if (tr.hasClass('k-master-row') && tr.find('.k-icon').hasClass('k-i-collapse')) {
                            tr.next().show();
                            relatedGroup.eq(idx + 1).show();
                        }
                    }
                    if (tr.hasClass('k-grouping-row')) {
                        if (showFooter) {
                            footersVisibility.push(tr.is(':visible'));
                        }
                        groupsCount++;
                    }
                    if (tr.hasClass('k-group-footer')) {
                        if (showFooter) {
                            tr.toggle(footersVisibility.pop());
                        }
                        if (groupsCount == 1) {
                            tr.show();
                            relatedGroup.eq(idx).show();
                        } else {
                            groupsCount--;
                        }
                    }
                }
            },
            _updateHeader: function (groups) {
                var that = this, container = that._isLocked() ? that.lockedHeader.find('thead') : that.thead, filterCells = container.find('tr.k-filter-row').find('th.k-group-cell').length, length = container.find('tr:first').find('th.k-group-cell').length, rows = container.children('tr:not(:first)').filter(function () {
                        return !$(this).children(':visible').length;
                    });
                if (groups > length) {
                    $(new Array(groups - length + 1).join('<th class="k-group-cell k-header" scope="col">' + that.options.messages.expandCollapseColumnHeader + '</th>')).prependTo(container.children('tr:not(.k-filter-row)'));
                    if (that.element.is(':visible')) {
                        rows.find('th.k-group-cell').hide();
                    }
                } else if (groups < length) {
                    container.find('tr').each(function () {
                        $(this).find('th.k-group-cell').filter(':eq(' + groups + '),' + ':gt(' + groups + ')').remove();
                    });
                }
                if (groups > filterCells) {
                    $(new Array(groups - filterCells + 1).join('<th class="k-group-cell k-header" scope="col">&nbsp;</th>')).prependTo(container.find('.k-filter-row'));
                }
            },
            _firstDataItem: function (data, grouped) {
                if (data && grouped) {
                    if (data.hasSubgroups) {
                        data = this._firstDataItem(data.items[0], grouped);
                    } else {
                        data = data.items[0];
                    }
                }
                return data;
            },
            _updateTablesWidth: function () {
                var that = this, tables;
                if (!that._isLocked()) {
                    return;
                }
                tables = $('>.k-grid-footer>.k-grid-footer-wrap>table', that.wrapper).add(that.thead.parent()).add(that.table);
                that._footerWidth = tableWidth(tables.eq(0));
                tables.width(that._footerWidth);
                tables = $('>.k-grid-footer>.k-grid-footer-locked>table', that.wrapper).add(that.lockedHeader.find('>table')).add(that.lockedTable);
                tables.width(tableWidth(tables.eq(0)));
            },
            hideColumn: function (column) {
                var that = this, cell, tables, idx, cols, colWidth, position, width = 0, headerCellIndex, length, footer = that.footer || that.wrapper.find('.k-grid-footer'), columns = that.columns, visibleLocked = that.lockedHeader ? leafDataCells(that.lockedHeader.find('>table>thead')).filter(isCellVisible).length : 0, columnIndex;
                if (typeof column == 'number') {
                    column = columns[column];
                } else if (isPlainObject(column)) {
                    column = grep(flatColumns(columns), function (item) {
                        return item === column;
                    })[0];
                } else {
                    column = grep(flatColumns(columns), function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || !isVisible(column)) {
                    return;
                }
                if (column.columns && column.columns.length) {
                    position = columnVisiblePosition(column, columns);
                    setColumnVisibility(column, false);
                    setCellVisibility(elements($('>table>thead', that.lockedHeader), that.thead, '>tr:eq(' + position.row + ')>th'), position.cell, false);
                    for (idx = 0; idx < column.columns.length; idx++) {
                        this.hideColumn(column.columns[idx]);
                    }
                    that.trigger(COLUMNHIDE, { column: column });
                    return;
                }
                columnIndex = inArray(column, visibleColumns(leafColumns(columns)));
                setColumnVisibility(column, false);
                that._setParentsVisibility(column, false);
                that._templates();
                that._updateCols();
                that._updateLockedCols();
                var container = that.thead;
                headerCellIndex = columnIndex;
                if (that.lockedHeader && visibleLocked > columnIndex) {
                    container = that.lockedHeader.find('>table>thead');
                } else {
                    headerCellIndex -= visibleLocked;
                }
                cell = leafDataCells(container).filter(isCellVisible).eq(headerCellIndex);
                cell[0].style.display = 'none';
                setCellVisibility(elements($('>table>thead', that.lockedHeader), that.thead, '>tr.k-filter-row>th'), columnIndex, false);
                if (footer[0]) {
                    that._updateCols(footer.find('>.k-grid-footer-wrap>table'));
                    that._updateLockedCols(footer.find('>.k-grid-footer-locked>table'));
                    setCellVisibility(footer.find('.k-footer-template>td'), columnIndex, false);
                }
                if (that.lockedTable && visibleLocked > columnIndex) {
                    hideColumnCells(that.lockedTable.find('>tbody>tr'), columnIndex);
                } else {
                    hideColumnCells(that.tbody.children(), columnIndex - visibleLocked);
                }
                if (that.lockedTable) {
                    that._updateTablesWidth();
                    that._applyLockedContainersWidth();
                    that._syncLockedContentHeight();
                    that._syncLockedHeaderHeight();
                    that._syncLockedFooterHeight();
                } else {
                    cols = that.thead.prev().find('col');
                    for (idx = 0, length = cols.length; idx < length; idx += 1) {
                        colWidth = cols[idx].style.width;
                        if (colWidth && colWidth.indexOf('%') == -1) {
                            width += parseInt(colWidth, 10);
                        } else {
                            width = 0;
                            break;
                        }
                    }
                    tables = $('>.k-grid-header table:first,>.k-grid-footer table:first', that.wrapper).add(that.table);
                    that._footerWidth = null;
                    if (width) {
                        tables.each(function () {
                            this.style.width = width + 'px';
                        });
                        that._footerWidth = width;
                    }
                    if (browser.msie && browser.version == 8) {
                        tables.css('display', 'inline-table');
                        setTimeout(function () {
                            tables.css('display', 'table');
                        }, 1);
                    }
                }
                that._updateFirstColumnClass();
                that.trigger(COLUMNHIDE, { column: column });
            },
            _setParentsVisibility: function (column, visible) {
                var columns = this.columns;
                var idx;
                var parents = [];
                var parent;
                var position;
                var cell;
                var colSpan;
                var predicate = visible ? function (p) {
                    return visibleColumns(p.columns).length && p.hidden;
                } : function (p) {
                    return !visibleColumns(p.columns).length && !p.hidden;
                };
                if (columnParents(column, columns, parents) && parents.length) {
                    for (idx = parents.length - 1; idx >= 0; idx--) {
                        parent = parents[idx];
                        position = columnPosition(parent, columns);
                        cell = elements($('>table>thead', this.lockedHeader), this.thead, '>tr:eq(' + position.row + ')>th:not(.k-group-cell):not(.k-hierarchy-cell)').eq(position.cell);
                        if (predicate(parent)) {
                            setColumnVisibility(parent, visible);
                            cell[0].style.display = visible ? '' : 'none';
                        }
                        if (cell.filter('[' + kendo.attr('colspan') + ']').length) {
                            colSpan = parseInt(cell.attr(kendo.attr('colspan')), 10);
                            cell[0].colSpan = colSpan - hiddenLeafColumnsCount(parent.columns) || 1;
                        }
                    }
                }
            },
            showColumn: function (column) {
                var that = this, idx, length, cell, tables, width, headerCellIndex, position, colWidth, cols, columns = that.columns, footer = that.footer || that.wrapper.find('.k-grid-footer'), lockedColumnsCount = that.lockedHeader ? leafDataCells(that.lockedHeader.find('>table>thead')).length : 0, columnIndex;
                if (typeof column == 'number') {
                    column = columns[column];
                } else if (isPlainObject(column)) {
                    column = grep(flatColumns(columns), function (item) {
                        return item === column;
                    })[0];
                } else {
                    column = grep(flatColumns(columns), function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || isVisible(column)) {
                    return;
                }
                if (column.columns && column.columns.length) {
                    position = columnPosition(column, columns);
                    setColumnVisibility(column, true);
                    setCellVisibility(elements($('>table>thead', that.lockedHeader), that.thead, '>tr:eq(' + position.row + ')>th'), position.cell, true);
                    for (idx = 0; idx < column.columns.length; idx++) {
                        this.showColumn(column.columns[idx]);
                    }
                    that.trigger(COLUMNSHOW, { column: column });
                    return;
                }
                columnIndex = inArray(column, leafColumns(columns));
                setColumnVisibility(column, true);
                that._setParentsVisibility(column, true);
                that._templates();
                that._updateCols();
                that._updateLockedCols();
                var container = that.thead;
                headerCellIndex = columnIndex;
                if (that.lockedHeader && lockedColumnsCount > columnIndex) {
                    container = that.lockedHeader.find('>table>thead');
                } else {
                    headerCellIndex -= lockedColumnsCount;
                }
                cell = leafDataCells(container).eq(headerCellIndex);
                cell[0].style.display = '';
                setCellVisibility(elements($('>table>thead', that.lockedHeader), that.thead, '>tr.k-filter-row>th'), columnIndex, true);
                if (footer[0]) {
                    that._updateCols(footer.find('>.k-grid-footer-wrap>table'));
                    that._updateLockedCols(footer.find('>.k-grid-footer-locked>table'));
                    setCellVisibility(footer.find('.k-footer-template>td'), columnIndex, true);
                }
                if (that.lockedTable && lockedColumnsCount > columnIndex) {
                    showColumnCells(that.lockedTable.find('>tbody>tr'), columnIndex);
                } else {
                    showColumnCells(that.tbody.children(), columnIndex - lockedColumnsCount);
                }
                if (that.lockedTable) {
                    that._updateTablesWidth();
                    that._applyLockedContainersWidth();
                    that._syncLockedContentHeight();
                    that._syncLockedHeaderHeight();
                } else {
                    tables = $('>.k-grid-header table:first,>.k-grid-footer table:first', that.wrapper).add(that.table);
                    if (!column.width) {
                        tables.width('');
                    } else {
                        width = 0;
                        cols = that.thead.prev().find('col');
                        for (idx = 0, length = cols.length; idx < length; idx += 1) {
                            colWidth = cols[idx].style.width;
                            if (colWidth.indexOf('%') > -1) {
                                width = 0;
                                break;
                            }
                            width += parseInt(colWidth, 10);
                        }
                        that._footerWidth = null;
                        if (width) {
                            tables.each(function () {
                                this.style.width = width + 'px';
                            });
                            that._footerWidth = width;
                        }
                    }
                }
                that._updateFirstColumnClass();
                that.trigger(COLUMNSHOW, { column: column });
            },
            _progress: function (toggle) {
                var element = this.element;
                if (this._editContainer && this._editMode() === 'popup') {
                    element = this._editContainer;
                } else if (this.lockedContent) {
                    element = this.wrapper;
                } else if (this.element.is('table')) {
                    element = this.element.parent();
                } else if (this.content && this.content.length) {
                    element = this.content;
                }
                kendo.ui.progress(element, toggle);
            },
            _resize: function (size, force) {
                this._syncLockedContentHeight();
                this._syncLockedHeaderHeight();
                if (this.content) {
                    this._setContentWidth();
                    this._setContentHeight();
                }
                if (this.virtualScrollable && (force || this._rowHeight)) {
                    if (force) {
                        this._rowHeight = null;
                    }
                    this.virtualScrollable.repaintScrollbar();
                }
            },
            _isActiveInTable: function () {
                var active = activeElement();
                if (!active) {
                    return false;
                }
                return this.table[0] === active || $.contains(this.table[0], active) || this._isLocked() && (this.lockedTable[0] === active || $.contains(this.lockedTable[0], active));
            },
            refresh: function (e) {
                var that = this, data = that.dataSource.view(), navigatable = that.options.navigatable, currentIndex, current = $(that.current()), isCurrentInHeader = false, groups = (that.dataSource.group() || []).length, colspan = groups + visibleLeafColumns(visibleColumns(that.columns)).length;
                if (e && e.action === 'itemchange' && that.editable) {
                    return;
                }
                if (e && e.action === 'remove' && that.editable && that.editable.options.model && inArray(that.editable.options.model, e.items) > -1) {
                    that.editable.options.model.unbind(CHANGE, that._modelChangeHandler);
                }
                e = e || {};
                if (that.trigger('dataBinding', {
                        action: e.action || 'rebind',
                        index: e.index,
                        items: e.items
                    })) {
                    return;
                }
                that._angularItems('cleanup');
                if (navigatable && (that._isActiveInTable() || that._editContainer && that._editContainer.data('kendoWindow'))) {
                    isCurrentInHeader = current.is('th');
                    currentIndex = Math.max(that.cellIndex(current), 0);
                }
                that._destroyEditable();
                that._progress(false);
                that._hideResizeHandle();
                that._data = [];
                if (!that.columns.length) {
                    that._autoColumns(that._firstDataItem(data[0], groups));
                    colspan = groups + that.columns.length;
                }
                that._group = groups > 0 || that._group;
                if (that._group) {
                    that._templates();
                    that._updateCols();
                    that._updateLockedCols();
                    that._updateHeader(groups);
                    that._group = groups > 0;
                }
                that._renderContent(data, colspan, groups);
                that._renderLockedContent(data, colspan, groups);
                that._footer();
                that._renderNoRecordsContent();
                that._setContentHeight();
                that._setContentWidth(that.content && that.content.scrollLeft());
                if (that.lockedTable) {
                    if (that.options.scrollable.virtual) {
                        that.content.find('>.k-virtual-scrollable-wrap').trigger('scroll');
                    } else if (that.touchScroller) {
                        that.touchScroller.movable.trigger('change');
                    } else {
                        that.wrapper.one('scroll', function (e) {
                            e.stopPropagation();
                        });
                        that.content.trigger('scroll');
                    }
                }
                that._restoreCurrent(currentIndex, isCurrentInHeader);
                if (that.touchScroller) {
                    that.touchScroller.contentResized();
                }
                if (that.selectable) {
                    that.selectable.resetTouchEvents();
                }
                that._muteAngularRebind(function () {
                    that._angularItems('compile');
                });
                if (that.options.selectable && !kendo.ui.Selectable.parseOptions(that.options.selectable).cell && that.options.persistSelection) {
                    that._restoreSelection();
                }
                that.trigger(DATABOUND);
            },
            _restoreCurrent: function (currentIndex, isCurrentInHeader) {
                if (currentIndex === undefined || currentIndex < 0) {
                    return;
                }
                this._removeCurrent();
                if (isCurrentInHeader) {
                    this._setCurrent(this.thead.find('th:not(.k-group-cell)').eq(currentIndex));
                } else {
                    var rowIndex = 0;
                    if (this._rowVirtualIndex) {
                        rowIndex = this.virtualScrollable.position(this._rowVirtualIndex);
                    } else {
                        currentIndex = 0;
                    }
                    var row = $();
                    if (this.lockedTable) {
                        row = this.lockedTable.find('>tbody>tr').eq(rowIndex);
                    }
                    row = row.add(this.tbody.children().eq(rowIndex));
                    var td = row.find('>td:not(.k-group-cell):not(.k-hierarchy-cell)').eq(currentIndex);
                    this._setCurrent(td);
                }
                if (this._current) {
                    focusTable(this._current.closest('table')[0], true);
                }
            },
            _restoreSelection: function () {
                var that = this, rows = that.tbody.children(':not(.k-grouping-row,.k-detail-row)');
                rows = grep(rows, function (row) {
                    var dataItemKey = that.dataItem(row)[that.dataSource.options.schema.model.id];
                    if (that._selectedIds[dataItemKey]) {
                        return row;
                    }
                });
                that.select(rows);
            },
            _angularItems: function (cmd) {
                kendo.ui.DataBoundWidget.fn._angularItems.call(this, cmd);
                if (cmd === 'cleanup') {
                    this._cleanupDetailItems();
                }
                this._angularGroupItems(cmd);
                this._angularGroupFooterItems(cmd);
            },
            _cleanupDetailItems: function () {
                var that = this;
                if (that._hasDetails()) {
                    that.angular('cleanup', function () {
                        return { elements: that.tbody.children('.k-detail-row') };
                    });
                    that.tbody.find('.k-detail-cell').empty();
                }
            },
            _angularGroupItems: function (cmd) {
                var that = this, container = that.tbody;
                if (that.lockedContent) {
                    container = that.lockedTable.find('tbody');
                }
                if (that._group) {
                    that.angular(cmd, function () {
                        return {
                            elements: container.children('.k-grouping-row'),
                            data: $.map(groupRows(that.dataSource.view()), function (dataItem) {
                                return { dataItem: dataItem };
                            })
                        };
                    });
                }
            },
            _angularGroupFooterItems: function (cmd) {
                var that = this, container = that.tbody;
                if (that.lockedContent) {
                    container = that.element;
                }
                if (that._group && that.groupFooterTemplate) {
                    that.angular(cmd, function () {
                        return {
                            elements: container.find('.k-group-footer'),
                            data: $.map(groupFooters(that.dataSource.view()), function (dataItem) {
                                return { dataItem: dataItem };
                            })
                        };
                    });
                }
            },
            _renderContent: function (data, colspan, groups) {
                var that = this, idx, length, html = '', isLocked = that.lockedContent != null, templates = {
                        rowTemplate: that.rowTemplate,
                        altRowTemplate: that.altRowTemplate,
                        groupFooterTemplate: that.groupFooterTemplate
                    };
                colspan = isLocked ? colspan - visibleLeafColumns(visibleLockedColumns(that.columns)).length : colspan;
                if (groups > 0) {
                    colspan = isLocked ? colspan - groups : colspan;
                    if (that.detailTemplate) {
                        colspan++;
                    }
                    if (that.groupFooterTemplate) {
                        that._groupAggregatesDefaultObject = that.dataSource.aggregates();
                    }
                    for (idx = 0, length = data.length; idx < length; idx++) {
                        html += that._groupRowHtml(data[idx], colspan, 0, isLocked ? groupRowLockedContentBuilder : groupRowBuilder, templates, isLocked);
                    }
                } else {
                    html += that._rowsHtml(data, templates);
                }
                that.tbody = appendContent(that.tbody, that.table, html, this.options.$angular);
            },
            _renderLockedContent: function (data, colspan, groups) {
                var html = '', idx, length, templates = {
                        rowTemplate: this.lockedRowTemplate,
                        altRowTemplate: this.lockedAltRowTemplate,
                        groupFooterTemplate: this.lockedGroupFooterTemplate
                    };
                if (this.lockedContent) {
                    var table = this.lockedTable;
                    if (groups > 0) {
                        colspan = colspan - visibleColumns(leafColumns(nonLockedColumns(this.columns))).length;
                        for (idx = 0, length = data.length; idx < length; idx++) {
                            html += this._groupRowHtml(data[idx], colspan, 0, groupRowBuilder, templates);
                        }
                    } else {
                        html = this._rowsHtml(data, templates);
                    }
                    appendContent(table.children('tbody'), table, html, this.options.$angular);
                    this._syncLockedContentHeight();
                }
            },
            _adjustRowsHeight: function (table1, table2) {
                var rows = table1[0].rows, length = rows.length, idx, rows2 = table2[0].rows, containers = table1.add(table2), containersLength = containers.length, heights = [];
                for (idx = 0; idx < length; idx++) {
                    if (!rows2[idx]) {
                        break;
                    }
                    if (rows[idx].style.height) {
                        rows[idx].style.height = rows2[idx].style.height = '';
                    }
                }
                for (idx = 0; idx < length; idx++) {
                    if (!rows2[idx]) {
                        break;
                    }
                    var offsetHeight1 = rows[idx].offsetHeight;
                    var offsetHeight2 = rows2[idx].offsetHeight;
                    var height = 0;
                    if (offsetHeight1 > offsetHeight2) {
                        height = offsetHeight1;
                    } else if (offsetHeight1 < offsetHeight2) {
                        height = offsetHeight2;
                    }
                    heights.push(height);
                }
                for (idx = 0; idx < containersLength; idx++) {
                    containers[idx].style.display = 'none';
                }
                for (idx = 0; idx < length; idx++) {
                    if (heights[idx]) {
                        rows[idx].style.height = rows2[idx].style.height = heights[idx] + 1 + 'px';
                    }
                }
                for (idx = 0; idx < containersLength; idx++) {
                    containers[idx].style.display = '';
                }
            }
        });
        if (kendo.ExcelMixin) {
            kendo.ExcelMixin.extend(Grid.prototype);
        }
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Grid.prototype);
            Grid.prototype._drawPDF_autoPageBreak = function (progress) {
                var grid = this;
                var result = new $.Deferred();
                var dataSource = grid.dataSource;
                var allPages = grid.options.pdf.allPages;
                var origBody = grid.wrapper.find('table[role="grid"] > tbody');
                var cont = $('<div>').css({
                    position: 'absolute',
                    left: -10000,
                    top: -10000
                });
                var clone = grid.wrapper.clone().css({
                    height: 'auto',
                    width: 'auto'
                }).appendTo(cont);
                clone.find('.k-grid-content').css({
                    height: 'auto',
                    width: 'auto',
                    overflow: 'visible'
                });
                clone.find('table[role="grid"]').css({
                    height: 'auto',
                    width: '100%',
                    overflow: 'visible'
                });
                clone.find('.k-grid-pager, .k-grid-toolbar, .k-grouping-header').remove();
                clone.find('.k-grid-header').css({ paddingRight: 0 });
                this._initPDFProgress(progress);
                var body = clone.find('table[role="grid"] > tbody').empty();
                var startingPage = dataSource.page();
                function resolve() {
                    if (allPages && startingPage !== undefined) {
                        dataSource.one('change', draw);
                        dataSource.page(startingPage);
                    } else {
                        grid.refresh();
                        draw();
                    }
                }
                function draw() {
                    cont.appendTo(document.body);
                    var options = $.extend({}, grid.options.pdf, {
                        _destructive: true,
                        progress: function (p) {
                            progress.notify({
                                page: p.page,
                                pageNumber: p.pageNum,
                                progress: 0.5 + p.pageNum / p.totalPages / 2,
                                totalPages: p.totalPages
                            });
                        }
                    });
                    kendo.drawing.drawDOM(clone, options).always(function () {
                        cont.remove();
                    }).then(function (group) {
                        result.resolve(group);
                    }).fail(function (err) {
                        result.reject(err);
                    });
                }
                function renderPage() {
                    var pageNum = dataSource.page();
                    var totalPages = allPages ? dataSource.totalPages() : 1;
                    body.append(origBody.find('tr'));
                    if (pageNum < totalPages) {
                        dataSource.page(pageNum + 1);
                    } else {
                        dataSource.unbind('change', renderPage);
                        resolve();
                    }
                }
                if (allPages) {
                    dataSource.bind('change', renderPage);
                    dataSource.page(1);
                } else {
                    renderPage();
                }
                return result.promise();
            };
            Grid.prototype._drawPDF = function (progress) {
                var grid = this;
                if (grid.options.pdf.paperSize && grid.options.pdf.paperSize != 'auto') {
                    return grid._drawPDF_autoPageBreak(progress);
                }
                var result = new $.Deferred();
                var dataSource = grid.dataSource;
                var allPages = grid.options.pdf.allPages;
                this._initPDFProgress(progress);
                var doc = new kendo.drawing.Group();
                var startingPage = dataSource.page();
                function resolve() {
                    if (allPages && startingPage !== undefined) {
                        dataSource.unbind('change', exportPage);
                        dataSource.one('change', function () {
                            result.resolve(doc);
                        });
                        dataSource.page(startingPage);
                    } else {
                        result.resolve(doc);
                    }
                }
                function exportPage() {
                    grid._drawPDFShadow({ width: grid.wrapper.width() }, { avoidLinks: grid.options.pdf.avoidLinks }).done(function (group) {
                        var pageNum = dataSource.page();
                        var totalPages = allPages ? dataSource.totalPages() : 1;
                        var args = {
                            page: group,
                            pageNumber: pageNum,
                            progress: pageNum / totalPages,
                            totalPages: totalPages
                        };
                        progress.notify(args);
                        doc.append(args.page);
                        if (pageNum < totalPages) {
                            dataSource.page(pageNum + 1);
                        } else {
                            resolve();
                        }
                    }).fail(function (err) {
                        result.reject(err);
                    });
                }
                if (allPages) {
                    dataSource.bind('change', exportPage);
                    dataSource.page(1);
                } else {
                    exportPage();
                }
                return result.promise();
            };
            Grid.prototype._initPDFProgress = function (deferred) {
                var loading = $('<div class=\'k-loading-pdf-mask\'><div class=\'k-loading-color\'/></div>');
                loading.prepend(this.wrapper.clone().css({
                    position: 'absolute',
                    top: 0,
                    left: 0
                }));
                this.wrapper.append(loading);
                var pb = $('<div class=\'k-loading-pdf-progress\'>').appendTo(loading).kendoProgressBar({
                    type: 'chunk',
                    chunkCount: 10,
                    min: 0,
                    max: 1,
                    value: 0
                }).data('kendoProgressBar');
                deferred.progress(function (e) {
                    pb.value(e.progress);
                }).always(function () {
                    kendo.destroy(loading);
                    loading.remove();
                });
            };
        }
        function syncTableHeight(table1, table2) {
            table1 = table1[0];
            table2 = table2[0];
            if (table1.rows.length !== table2.rows.length) {
                var lockedHeigth = table1.offsetHeight;
                var tableHeigth = table2.offsetHeight;
                var row;
                var diff;
                if (lockedHeigth > tableHeigth) {
                    row = table2.rows[table2.rows.length - 1];
                    if (filterRowRegExp.test(row.className)) {
                        row = table2.rows[table2.rows.length - 2];
                    }
                    diff = lockedHeigth - tableHeigth;
                } else {
                    row = table1.rows[table1.rows.length - 1];
                    if (filterRowRegExp.test(row.className)) {
                        row = table1.rows[table1.rows.length - 2];
                    }
                    diff = tableHeigth - lockedHeigth;
                }
                row.style.height = row.offsetHeight + diff + 'px';
            }
        }
        function adjustRowHeight(row1, row2) {
            var height;
            var offsetHeight1 = row1.offsetHeight;
            var offsetHeight2 = row2.offsetHeight;
            if (offsetHeight1 > offsetHeight2) {
                height = offsetHeight1 + 'px';
            } else if (offsetHeight1 < offsetHeight2) {
                height = offsetHeight2 + 'px';
            }
            if (height) {
                row1.style.height = row2.style.height = height;
            }
        }
        function getCommand(commands, name) {
            var idx, length, command;
            if (typeof commands === STRING && commands === name) {
                return commands;
            }
            if (isPlainObject(commands) && commands.name === name) {
                return commands;
            }
            if (isArray(commands)) {
                for (idx = 0, length = commands.length; idx < length; idx++) {
                    command = commands[idx];
                    if (typeof command === STRING && command === name || command.name === name) {
                        return command;
                    }
                }
            }
            return null;
        }
        function focusTable(table, direct) {
            var msie = browser.msie || browser.edge;
            if (direct === true) {
                table = $(table);
                var scrollTop, scrollLeft;
                scrollTop = table.parent().scrollTop();
                scrollLeft = table.parent().scrollLeft();
                if (msie) {
                    try {
                        table[0].setActive();
                    } catch (e) {
                        table[0].focus();
                    }
                } else {
                    table[0].focus();
                }
                table.parent().scrollTop(scrollTop).scrollLeft(scrollLeft);
            } else {
                $(table).one('focusin', function (e) {
                    e.preventDefault();
                }).focus();
            }
        }
        function isColumnEditable(column, model) {
            if (!column.field) {
                return false;
            }
            if (model.editable && !model.editable(column.field)) {
                return false;
            }
            if (column.editable && !column.editable(model)) {
                return false;
            }
            return true;
        }
        function isInputElement(element) {
            return $(element).is(':button,a,:input,a>.k-icon,textarea,span.k-select,span.k-icon,span.k-link,.k-input,.k-multiselect-wrap,.k-tool-icon');
        }
        function tableClick(e) {
            var currentTarget = $(e.currentTarget), isHeader = currentTarget.is('th'), table = this.table.add(this.lockedTable), headerTable = this.thead.parent().add($('>table', this.lockedHeader)), isInput = isInputElement(e.target), currentTable = currentTarget.closest('table')[0];
            if (kendo.support.touch) {
                return;
            }
            if (isInput && currentTarget.find(kendo.roleSelector('filtercell')).length) {
                this._setCurrent(currentTarget);
                return;
            }
            if (currentTable !== table[0] && currentTable !== table[1] && currentTable !== headerTable[0] && currentTable !== headerTable[1]) {
                return;
            }
            if ($(e.target).is('a.k-i-expand, a.k-i-collapse')) {
                return;
            }
            if (this.options.navigatable) {
                this._setCurrent(currentTarget);
            }
            if (isHeader || !isInput) {
                setTimeout(function () {
                    if (!(isIE8 && $(kendo._activeElement()).hasClass('k-widget'))) {
                        if (!isInputElement(kendo._activeElement())) {
                            focusTable(currentTable, true);
                        }
                    }
                });
            }
            if (isHeader) {
                e.preventDefault();
            }
        }
        function isInEdit(cell) {
            return cell && (cell.hasClass('k-edit-cell') || cell.parent().hasClass('k-grid-edit-row'));
        }
        function groupRowBuilder(colspan, level, text) {
            return '<tr role="row" class="k-grouping-row">' + groupCells(level) + '<td colspan="' + colspan + '" aria-expanded="true">' + '<p class="k-reset">' + '<a class="k-icon k-i-collapse" href="#" tabindex="-1" ' + ARIALABEL + '="' + COLLAPSE + '"></a>' + text + '</p></td></tr>';
        }
        function groupRowLockedContentBuilder(colspan) {
            return '<tr role="row" class="k-grouping-row">' + '<td colspan="' + colspan + '" aria-expanded="true">' + '<p class="k-reset">&nbsp;</p></td></tr>';
        }
        ui.plugin(Grid);
        ui.plugin(VirtualScrollable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.listview', [
        'kendo.data',
        'kendo.editable',
        'kendo.selectable'
    ], f);
}(function () {
    var __meta__ = {
        id: 'listview',
        name: 'ListView',
        category: 'web',
        description: 'The ListView widget offers rich support for interacting with data.',
        depends: ['data'],
        features: [
            {
                id: 'listview-editing',
                name: 'Editing',
                description: 'Support for record editing',
                depends: ['editable']
            },
            {
                id: 'listview-selection',
                name: 'Selection',
                description: 'Support for selection',
                depends: ['selectable']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, CHANGE = 'change', CANCEL = 'cancel', DATABOUND = 'dataBound', DATABINDING = 'dataBinding', Widget = kendo.ui.Widget, keys = kendo.keys, FOCUSSELECTOR = '>*:not(.k-loading-mask)', PROGRESS = 'progress', ERROR = 'error', FOCUSED = 'k-state-focused', SELECTED = 'k-state-selected', KEDITITEM = 'k-edit-item', EDIT = 'edit', REMOVE = 'remove', SAVE = 'save', CLICK = 'click', NS = '.kendoListView', proxy = $.proxy, activeElement = kendo._activeElement, progress = kendo.ui.progress, DataSource = kendo.data.DataSource;
        var ListView = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                var that = this;
                options = $.isArray(options) ? { dataSource: options } : options;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                that.wrapper = element = that.element;
                if (element[0].id) {
                    that._itemId = element[0].id + '_lv_active';
                }
                that._element();
                that._dataSource();
                that._templates();
                that._navigatable();
                that._selectable();
                that._pageable();
                that._crudHandlers();
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
                kendo.notify(that);
            },
            events: [
                CHANGE,
                CANCEL,
                DATABINDING,
                DATABOUND,
                EDIT,
                REMOVE,
                SAVE
            ],
            options: {
                name: 'ListView',
                autoBind: true,
                selectable: false,
                navigatable: false,
                template: '',
                altTemplate: '',
                editTemplate: ''
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._templates();
                if (this.selectable) {
                    this.selectable.destroy();
                    this.selectable = null;
                }
                this._selectable();
            },
            _templates: function () {
                var options = this.options;
                this.template = kendo.template(options.template || '');
                this.altTemplate = kendo.template(options.altTemplate || options.template);
                this.editTemplate = kendo.template(options.editTemplate || '');
            },
            _item: function (action) {
                return this.element.children()[action]();
            },
            items: function () {
                return this.element.children();
            },
            dataItem: function (element) {
                var attr = kendo.attr('uid');
                var uid = $(element).closest('[' + attr + ']').attr(attr);
                return this.dataSource.getByUid(uid);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.options.autoBind) {
                    dataSource.fetch();
                }
            },
            _unbindDataSource: function () {
                var that = this;
                that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
            },
            _dataSource: function () {
                var that = this;
                if (that.dataSource && that._refreshHandler) {
                    that._unbindDataSource();
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                    that._progressHandler = proxy(that._progress, that);
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = DataSource.create(that.options.dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(ERROR, that._errorHandler);
            },
            _progress: function () {
                progress(this.element, true);
            },
            _error: function () {
                progress(this.element, false);
            },
            _element: function () {
                this.element.addClass('k-widget k-listview').attr('role', 'listbox');
            },
            refresh: function (e) {
                var that = this, view = that.dataSource.view(), data, items, item, html = '', idx, length, template = that.template, altTemplate = that.altTemplate, active = activeElement();
                e = e || {};
                if (e.action === 'itemchange') {
                    if (!that._hasBindingTarget() && !that.editable) {
                        data = e.items[0];
                        item = that.items().filter('[' + kendo.attr('uid') + '=' + data.uid + ']');
                        if (item.length > 0) {
                            idx = item.index();
                            that.angular('cleanup', function () {
                                return { elements: [item] };
                            });
                            item.replaceWith(template(data));
                            item = that.items().eq(idx);
                            item.attr(kendo.attr('uid'), data.uid);
                            that.angular('compile', function () {
                                return {
                                    elements: [item],
                                    data: [{ dataItem: data }]
                                };
                            });
                            that.trigger('itemChange', {
                                item: item,
                                data: data
                            });
                        }
                    }
                    return;
                }
                if (that.trigger(DATABINDING, {
                        action: e.action || 'rebind',
                        items: e.items,
                        index: e.index
                    })) {
                    return;
                }
                that._angularItems('cleanup');
                that._destroyEditable();
                for (idx = 0, length = view.length; idx < length; idx++) {
                    if (idx % 2) {
                        html += altTemplate(view[idx]);
                    } else {
                        html += template(view[idx]);
                    }
                }
                that.element.html(html);
                items = that.items();
                for (idx = 0, length = view.length; idx < length; idx++) {
                    items.eq(idx).attr(kendo.attr('uid'), view[idx].uid).attr('role', 'option').attr('aria-selected', 'false');
                }
                if (that.element[0] === active && that.options.navigatable) {
                    that.current(items.eq(0));
                }
                that._angularItems('compile');
                that.trigger(DATABOUND, {
                    action: e.action || 'rebind',
                    items: e.items,
                    index: e.index
                });
            },
            _pageable: function () {
                var that = this, pageable = that.options.pageable, settings, pagerId;
                if ($.isPlainObject(pageable)) {
                    pagerId = pageable.pagerId;
                    settings = $.extend({}, pageable, {
                        dataSource: that.dataSource,
                        pagerId: null
                    });
                    that.pager = new kendo.ui.Pager($('#' + pagerId), settings);
                }
            },
            _selectable: function () {
                var that = this, multi, current, selectable = that.options.selectable, navigatable = that.options.navigatable;
                if (selectable) {
                    multi = kendo.ui.Selectable.parseOptions(selectable).multiple;
                    that.selectable = new kendo.ui.Selectable(that.element, {
                        aria: true,
                        multiple: multi,
                        filter: FOCUSSELECTOR,
                        change: function () {
                            that.trigger(CHANGE);
                        }
                    });
                    if (navigatable) {
                        that.element.on('keydown' + NS, function (e) {
                            if (e.keyCode === keys.SPACEBAR) {
                                current = that.current();
                                if (e.target == e.currentTarget) {
                                    e.preventDefault();
                                }
                                if (multi) {
                                    if (!e.ctrlKey) {
                                        that.selectable.clear();
                                    } else {
                                        if (current && current.hasClass(SELECTED)) {
                                            current.removeClass(SELECTED);
                                            return;
                                        }
                                    }
                                } else {
                                    that.selectable.clear();
                                }
                                that.selectable.value(current);
                            }
                        });
                    }
                }
            },
            current: function (candidate) {
                var that = this, element = that.element, current = that._current, id = that._itemId;
                if (candidate === undefined) {
                    return current;
                }
                if (current && current[0]) {
                    if (current[0].id === id) {
                        current.removeAttr('id');
                    }
                    current.removeClass(FOCUSED);
                    element.removeAttr('aria-activedescendant');
                }
                if (candidate && candidate[0]) {
                    id = candidate[0].id || id;
                    that._scrollTo(candidate[0]);
                    element.attr('aria-activedescendant', id);
                    candidate.addClass(FOCUSED).attr('id', id);
                }
                that._current = candidate;
            },
            _scrollTo: function (element) {
                var that = this, container, UseJQueryoffset = false, SCROLL = 'scroll';
                if (that.wrapper.css('overflow') == 'auto' || that.wrapper.css('overflow') == SCROLL) {
                    container = that.wrapper[0];
                } else {
                    container = window;
                    UseJQueryoffset = true;
                }
                var scrollDirectionFunc = function (direction, dimension) {
                    var elementOffset = UseJQueryoffset ? $(element).offset()[direction.toLowerCase()] : element['offset' + direction], elementDimension = element['client' + dimension], containerScrollAmount = $(container)[SCROLL + direction](), containerDimension = $(container)[dimension.toLowerCase()]();
                    if (elementOffset + elementDimension > containerScrollAmount + containerDimension) {
                        $(container)[SCROLL + direction](elementOffset + elementDimension - containerDimension);
                    } else if (elementOffset < containerScrollAmount) {
                        $(container)[SCROLL + direction](elementOffset);
                    }
                };
                scrollDirectionFunc('Top', 'Height');
                scrollDirectionFunc('Left', 'Width');
            },
            _navigatable: function () {
                var that = this, navigatable = that.options.navigatable, element = that.element, clickCallback = function (e) {
                        that.current($(e.currentTarget));
                        if (!$(e.target).is(':button,a,:input,a>.k-icon,textarea')) {
                            element.focus();
                        }
                    };
                if (navigatable) {
                    that._tabindex();
                    element.on('focus' + NS, function () {
                        var current = that._current;
                        if (!current || !current.is(':visible')) {
                            current = that._item('first');
                        }
                        that.current(current);
                    }).on('focusout' + NS, function () {
                        if (that._current) {
                            that._current.removeClass(FOCUSED);
                        }
                    }).on('keydown' + NS, function (e) {
                        var key = e.keyCode, current = that.current(), target = $(e.target), canHandle = !target.is(':button,textarea,a,a>.t-icon,input'), isTextBox = target.is(':text,:password'), preventDefault = kendo.preventDefault, editItem = element.find('.' + KEDITITEM), active = activeElement(), idx;
                        if (!canHandle && !isTextBox && keys.ESC != key || isTextBox && keys.ESC != key && keys.ENTER != key) {
                            return;
                        }
                        if (keys.UP === key || keys.LEFT === key) {
                            if (current) {
                                current = current.prev();
                            }
                            that.current(!current || !current[0] ? that._item('last') : current);
                            preventDefault(e);
                        } else if (keys.DOWN === key || keys.RIGHT === key) {
                            if (current) {
                                current = current.next();
                            }
                            that.current(!current || !current[0] ? that._item('first') : current);
                            preventDefault(e);
                        } else if (keys.PAGEUP === key) {
                            that.current(null);
                            that.dataSource.page(that.dataSource.page() - 1);
                            preventDefault(e);
                        } else if (keys.PAGEDOWN === key) {
                            that.current(null);
                            that.dataSource.page(that.dataSource.page() + 1);
                            preventDefault(e);
                        } else if (keys.HOME === key) {
                            that.current(that._item('first'));
                            preventDefault(e);
                        } else if (keys.END === key) {
                            that.current(that._item('last'));
                            preventDefault(e);
                        } else if (keys.ENTER === key) {
                            if (editItem.length !== 0 && (canHandle || isTextBox)) {
                                idx = that.items().index(editItem);
                                if (active) {
                                    active.blur();
                                }
                                that.save();
                                var focusAgain = function () {
                                    that.element.trigger('focus');
                                    that.current(that.items().eq(idx));
                                };
                                that.one('dataBound', focusAgain);
                            } else if (that.options.editTemplate !== '') {
                                that.edit(current);
                            }
                        } else if (keys.ESC === key) {
                            editItem = element.find('.' + KEDITITEM);
                            if (editItem.length === 0) {
                                return;
                            }
                            idx = that.items().index(editItem);
                            that.cancel();
                            that.element.trigger('focus');
                            that.current(that.items().eq(idx));
                        }
                    });
                    element.on('mousedown' + NS + ' touchstart' + NS, FOCUSSELECTOR, proxy(clickCallback, that));
                }
            },
            clearSelection: function () {
                var that = this;
                that.selectable.clear();
                that.trigger(CHANGE);
            },
            select: function (items) {
                var that = this, selectable = that.selectable;
                items = $(items);
                if (items.length) {
                    if (!selectable.options.multiple) {
                        selectable.clear();
                        items = items.first();
                    }
                    selectable.value(items);
                    return;
                }
                return selectable.value();
            },
            _destroyEditable: function () {
                var that = this;
                if (that.editable) {
                    that.editable.destroy();
                    delete that.editable;
                }
            },
            _modelFromElement: function (element) {
                var uid = element.attr(kendo.attr('uid'));
                return this.dataSource.getByUid(uid);
            },
            _closeEditable: function () {
                var that = this, editable = that.editable, data, item, index, template = that.template;
                if (editable) {
                    if (editable.element.index() % 2) {
                        template = that.altTemplate;
                    }
                    that.angular('cleanup', function () {
                        return { elements: [editable.element] };
                    });
                    data = that._modelFromElement(editable.element);
                    that._destroyEditable();
                    index = editable.element.index();
                    editable.element.replaceWith(template(data));
                    item = that.items().eq(index);
                    item.attr(kendo.attr('uid'), data.uid);
                    if (that._hasBindingTarget()) {
                        kendo.bind(item, data);
                    }
                    that.angular('compile', function () {
                        return {
                            elements: [item],
                            data: [{ dataItem: data }]
                        };
                    });
                }
                return true;
            },
            edit: function (item) {
                var that = this, data = that._modelFromElement(item), container, uid = data.uid, index;
                that.cancel();
                item = that.items().filter('[' + kendo.attr('uid') + '=' + uid + ']');
                index = item.index();
                item.replaceWith(that.editTemplate(data));
                container = that.items().eq(index).addClass(KEDITITEM).attr(kendo.attr('uid'), data.uid);
                that.editable = container.kendoEditable({
                    model: data,
                    clearContainer: false,
                    errorTemplate: false,
                    target: that
                }).data('kendoEditable');
                that.trigger(EDIT, {
                    model: data,
                    item: container
                });
            },
            save: function () {
                var that = this, editable = that.editable, model;
                if (!editable) {
                    return;
                }
                var container = editable.element;
                model = that._modelFromElement(container);
                if (editable.end() && !that.trigger(SAVE, {
                        model: model,
                        item: container
                    })) {
                    that._closeEditable();
                    that.dataSource.sync();
                }
            },
            remove: function (item) {
                var that = this, dataSource = that.dataSource, data = that._modelFromElement(item);
                if (that.editable) {
                    dataSource.cancelChanges(that._modelFromElement(that.editable.element));
                    that._closeEditable();
                }
                if (!that.trigger(REMOVE, {
                        model: data,
                        item: item
                    })) {
                    item.hide();
                    dataSource.remove(data);
                    dataSource.sync();
                }
            },
            add: function () {
                var that = this, dataItem, dataSource = that.dataSource, index = dataSource.indexOf((dataSource.view() || [])[0]);
                if (index < 0) {
                    index = 0;
                }
                that.cancel();
                dataItem = dataSource.insert(index, {});
                that.edit(that.element.find('[data-uid=\'' + dataItem.uid + '\']'));
            },
            cancel: function () {
                var that = this, dataSource = that.dataSource;
                if (that.editable) {
                    var container = that.editable.element;
                    var model = that._modelFromElement(container);
                    if (!that.trigger(CANCEL, {
                            model: model,
                            container: container
                        })) {
                        dataSource.cancelChanges(model);
                        that._closeEditable();
                    }
                }
            },
            _crudHandlers: function () {
                var that = this, clickNS = CLICK + NS;
                that.element.on(clickNS, '.k-edit-button', function (e) {
                    var item = $(this).closest('[' + kendo.attr('uid') + ']');
                    that.edit(item);
                    e.preventDefault();
                });
                that.element.on(clickNS, '.k-delete-button', function (e) {
                    var item = $(this).closest('[' + kendo.attr('uid') + ']');
                    that.remove(item);
                    e.preventDefault();
                });
                that.element.on(clickNS, '.k-update-button', function (e) {
                    that.save();
                    e.preventDefault();
                });
                that.element.on(clickNS, '.k-cancel-button', function (e) {
                    that.cancel();
                    e.preventDefault();
                });
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that._unbindDataSource();
                that._destroyEditable();
                that.element.off(NS);
                if (that.pager) {
                    that.pager.destroy();
                }
                kendo.destroy(that.element);
            }
        });
        kendo.ui.plugin(ListView);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.listbox', [
        'kendo.draganddrop',
        'kendo.data',
        'kendo.selectable'
    ], f);
}(function () {
    var __meta__ = {
        id: 'listbox',
        name: 'ListBox',
        category: 'web',
        depends: [
            'draganddrop',
            'data',
            'selectable'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var kendoAttr = kendo.attr;
        var data = kendo.data;
        var keys = kendo.keys;
        var kendoTemplate = kendo.template;
        var Widget = kendo.ui.Widget;
        var DataSource = data.DataSource;
        var Selectable = kendo.ui.Selectable;
        var DataBoundWidget = kendo.ui.DataBoundWidget;
        var Class = kendo.Class;
        var extend = $.extend;
        var noop = $.noop;
        var proxy = $.proxy;
        var DASH = '-';
        var DOT = '.';
        var SPACE = ' ';
        var HASH = '#';
        var KENDO_LISTBOX = 'kendoListBox';
        var NS = DOT + KENDO_LISTBOX;
        var DISABLED_STATE_CLASS = 'k-state-disabled';
        var SELECTED_STATE_CLASS = 'k-state-selected';
        var ENABLED_ITEM_SELECTOR = '.k-item:not(.k-state-disabled)';
        var ENABLED_ITEMS_SELECTOR = '.k-list:not(.k-state-disabled) >' + ENABLED_ITEM_SELECTOR;
        var TOOLBAR_CLASS = 'k-listbox-toolbar';
        var TOOL_SELECTOR = 'li > a.k-button:not(.k-state-disabled)';
        var FOCUSED_CLASS = 'k-state-focused';
        var DRAG_CLUE_CLASS = 'k-drag-clue';
        var DROP_HINT_CLASS = 'k-drop-hint';
        var LIST_CLASS = 'k-reset k-list';
        var LIST_SELECTOR = '.k-reset.k-list';
        var RESET = 'k-reset';
        var CLICK = 'click' + NS;
        var KEYDOWN = 'keydown' + NS;
        var BLUR = 'blur' + NS;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var CHANGE = 'change';
        var DATABOUND = 'dataBound';
        var ADD = 'add';
        var REMOVE = 'remove';
        var REORDER = 'reorder';
        var MOVE_UP = 'moveUp';
        var MOVE_DOWN = 'moveDown';
        var TRANSFER_TO = 'transferTo';
        var TRANSFER_FROM = 'transferFrom';
        var TRANSFER_ALL_TO = 'transferAllTo';
        var TRANSFER_ALL_FROM = 'transferAllFrom';
        var DRAGGEDCLASS = 'k-ghost';
        var UNIQUE_ID = 'uid';
        var TABINDEX = 'tabindex';
        var COMMAND = 'command';
        var MOVE_UP_OFFSET = -1;
        var MOVE_DOWN_OFFSET = 1;
        var DRAGSTART = 'dragstart';
        var DRAG = 'drag';
        var DROP = 'drop';
        var DRAGEND = 'dragend';
        var DEFAULT_FILTER = 'ul.k-reset.k-list>li.k-item';
        var RIGHT = 'right';
        var BOTTOM = 'bottom';
        var TOOLBAR_POSITION_CLASS_NAMES = [
            TOOLBAR_CLASS + DASH + 'left',
            TOOLBAR_CLASS + DASH + RIGHT,
            TOOLBAR_CLASS + DASH + 'top',
            TOOLBAR_CLASS + DASH + BOTTOM
        ];
        function getSortedDomIndices(items) {
            var indices = $.map(items, function (item) {
                return $(item).index();
            });
            return indices;
        }
        function isUndefined(value) {
            return typeof value === 'undefined';
        }
        function defaultHint(element) {
            return element.clone().removeClass(DRAGGEDCLASS).addClass(kendo.format('{0} {1} {2}', SELECTED_STATE_CLASS, RESET, DRAG_CLUE_CLASS)).width(element.width());
        }
        function defaultPlaceholder() {
            return $('<li>').addClass(DROP_HINT_CLASS);
        }
        var ListBox = DataBoundWidget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._wrapper();
                that._list();
                element = that.element.attr('multiple', 'multiple').hide();
                if (element[0] && !that.options.dataSource) {
                    that.options.dataTextField = that.options.dataTextField || 'text';
                    that.options.dataValueField = that.options.dataValueField || 'value';
                }
                that._templates();
                that._selectable();
                that._dataSource();
                that._createToolbar();
                that._createDraggable();
                that._createNavigatable();
            },
            destroy: function () {
                var that = this;
                DataBoundWidget.fn.destroy.call(that);
                if (!isNaN(that._listTabIndex)) {
                    that._getList().off();
                    that._listTabIndex = null;
                }
                that._unbindDataSource();
                that._destroySelectable();
                that._destroyToolbar();
                that.wrapper.off(NS);
                if (that._target) {
                    that._target = null;
                }
                if (that._draggable) {
                    that._draggable.destroy();
                    that.placeholder = null;
                }
                kendo.destroy(that.element);
            },
            events: [
                CHANGE,
                DATABOUND,
                ADD,
                REMOVE,
                REORDER,
                DRAGSTART,
                DRAG,
                DROP,
                DRAGEND
            ],
            options: {
                name: 'ListBox',
                autoBind: true,
                template: '',
                dataTextField: '',
                dataValueField: '',
                selectable: 'single',
                draggable: null,
                dropSources: [],
                connectWith: '',
                navigatable: true,
                toolbar: {
                    position: RIGHT,
                    tools: []
                },
                messages: {
                    tools: {
                        remove: 'Delete',
                        moveUp: 'Move Up',
                        moveDown: 'Move Down',
                        transferTo: 'Transfer To',
                        transferFrom: 'Transfer From',
                        transferAllTo: 'Transfer All To',
                        transferAllFrom: 'Transfer All From'
                    }
                }
            },
            add: function (dataItems) {
                var that = this;
                var items = dataItems && dataItems.length ? dataItems : [dataItems];
                var itemsLength = items.length;
                var i;
                that._unbindDataSource();
                for (i = 0; i < itemsLength; i++) {
                    that._addItem(items[i]);
                }
                that._bindDataSource();
                that._syncElement();
            },
            _addItem: function (dataItem) {
                var that = this;
                var item = that.templates.itemTemplate({
                    item: dataItem,
                    r: that.templates.itemContent
                });
                $(item).attr(kendoAttr(UNIQUE_ID), dataItem.uid).appendTo(that._getList());
                if (typeof dataItem === typeof '') {
                    that.dataSource._data.push(dataItem);
                } else {
                    that.dataSource.add(dataItem);
                }
            },
            _addItemAt: function (dataItem, index) {
                var that = this;
                var item = that.templates.itemTemplate({
                    item: dataItem,
                    r: that.templates.itemContent
                });
                that._unbindDataSource();
                if (typeof dataItem === typeof '') {
                    that._insertElementAt(item, index);
                    that.dataSource._data.push(dataItem);
                } else {
                    that._insertElementAt($(item).attr(kendoAttr(UNIQUE_ID), dataItem.uid), index);
                    that.dataSource.add(dataItem);
                }
                that._bindDataSource();
                that._syncElement();
            },
            _insertElementAt: function (item, index) {
                var that = this;
                var list = that._getList();
                if (index > 0) {
                    $(item).insertAfter(list.children().eq(index - 1));
                } else {
                    $(list).prepend(item);
                }
            },
            _createNavigatable: function () {
                var that = this;
                var options = that.options;
                if (options.navigatable) {
                    that._getList().on(CLICK, ENABLED_ITEM_SELECTOR, proxy(that._click, that)).on(KEYDOWN, proxy(that._keyDown, that)).on(BLUR, proxy(that._blur, that));
                }
            },
            _getTabIndex: function () {
                var that = this;
                var tabindex;
                if (!isNaN(that._listTabIndex)) {
                    return that._listTabIndex;
                }
                tabindex = that.element.attr(TABINDEX);
                that._listTabIndex = !isNaN(tabindex) ? tabindex : 0;
                that.element.removeAttr(TABINDEX);
                return that._listTabIndex;
            },
            _blur: function () {
                if (this._target) {
                    this._target.removeClass(FOCUSED_CLASS);
                    this._getList().removeAttr('aria-activedescendant');
                }
                this._target = null;
            },
            _click: function (e) {
                var that = this;
                var target = $(e.currentTarget);
                var oldTarget = that._target;
                if (oldTarget) {
                    oldTarget.removeClass(FOCUSED_CLASS);
                }
                that._target = target;
                target.addClass(FOCUSED_CLASS);
                that._getList().attr('aria-activedescendant', target.attr('id'));
                if (that._getList()[0] !== kendo._activeElement()) {
                    that.focus();
                }
            },
            _getNavigatableItem: function (key) {
                var that = this;
                var current;
                if (!that._target) {
                    current = that.items().filter(ENABLED_ITEM_SELECTOR).first();
                } else {
                    current = that._target;
                }
                if (key === keys.UP && that._target) {
                    current = that._target.prevAll(ENABLED_ITEM_SELECTOR).first();
                }
                if (key === keys.DOWN && that._target) {
                    current = that._target.nextAll(ENABLED_ITEM_SELECTOR).first();
                }
                return current.length ? current : null;
            },
            _scrollIntoView: function (item) {
                if (!item) {
                    return;
                }
                if (item[0]) {
                    item = item[0];
                }
                var list = this._getList().parent()[0];
                var itemOffsetTop = item.offsetTop;
                var contentScrollTop = list.scrollTop;
                var contentOffsetHeight = list.clientHeight;
                var bottomDistance = itemOffsetTop + item.offsetHeight;
                if (contentScrollTop > itemOffsetTop) {
                    contentScrollTop = itemOffsetTop;
                } else if (bottomDistance > contentScrollTop + contentOffsetHeight) {
                    contentScrollTop = bottomDistance - contentOffsetHeight;
                }
                list.scrollTop = contentScrollTop;
            },
            _keyDown: function (e) {
                var that = this;
                var key = e.keyCode;
                var current = that._getNavigatableItem(key);
                var shouldPreventDefault;
                if (that._target) {
                    that._target.removeClass(FOCUSED_CLASS);
                }
                if (!(e.shiftKey && !e.ctrlKey && (key === keys.DOWN || key === keys.UP))) {
                    that._shiftSelecting = false;
                }
                if (key == keys.DELETE) {
                    that._executeCommand(REMOVE);
                    if (that._target) {
                        that._target.removeClass(FOCUSED_CLASS);
                        that._getList().removeAttr('aria-activedescendant');
                        that._target = null;
                    }
                    shouldPreventDefault = true;
                } else if (key === keys.DOWN || key === keys.UP) {
                    if (!current) {
                        e.preventDefault();
                        return;
                    }
                    if (e.shiftKey && !e.ctrlKey) {
                        if (!that._shiftSelecting) {
                            that.clearSelection();
                            that._shiftSelecting = true;
                        }
                        if (that._target && current.hasClass('k-state-selected')) {
                            that._target.removeClass(SELECTED_STATE_CLASS);
                            that.trigger(CHANGE);
                        } else if (that.options.selectable == 'single') {
                            that.select(current);
                        } else {
                            that.select(current.add(that._target));
                        }
                    } else if (e.shiftKey && e.ctrlKey) {
                        that._executeCommand(key === keys.DOWN ? MOVE_DOWN : MOVE_UP);
                        that._scrollIntoView(that._target);
                        e.preventDefault();
                        return;
                    } else if (!e.shiftKey && !e.ctrlKey) {
                        if (that.options.selectable === 'multiple') {
                            that.clearSelection();
                        }
                        that.select(current);
                    }
                    that._target = current;
                    if (that._target) {
                        that._target.addClass(FOCUSED_CLASS);
                        that._scrollIntoView(that._target);
                        that._getList().attr('aria-activedescendant', that._target.attr('id'));
                    } else {
                        that._getList().removeAttr('aria-activedescendant');
                    }
                    shouldPreventDefault = true;
                } else if (key == keys.SPACEBAR) {
                    if (e.ctrlKey && that._target) {
                        if (that._target.hasClass(SELECTED_STATE_CLASS)) {
                            that._target.removeClass(SELECTED_STATE_CLASS);
                            that.trigger(CHANGE);
                        } else {
                            that.select(that._target);
                        }
                    } else {
                        that.clearSelection();
                        that.select(that._target);
                    }
                    shouldPreventDefault = true;
                } else if (e.ctrlKey && key == keys.RIGHT) {
                    if (e.shiftKey) {
                        that._executeCommand(TRANSFER_ALL_TO);
                    } else {
                        that._executeCommand(TRANSFER_TO);
                    }
                    that._target = that.select().length ? that.select() : null;
                    shouldPreventDefault = true;
                } else if (e.ctrlKey && key == keys.LEFT) {
                    if (e.shiftKey) {
                        that._executeCommand(TRANSFER_ALL_FROM);
                    } else {
                        that._executeCommand(TRANSFER_FROM);
                    }
                    shouldPreventDefault = true;
                }
                if (shouldPreventDefault) {
                    e.preventDefault();
                }
            },
            focus: function () {
                this._getList().focus();
            },
            _createDraggable: function () {
                var that = this;
                var draggable = that.options.draggable;
                var hint;
                if (draggable) {
                    hint = draggable.hint;
                    if (!that.options.selectable) {
                        throw new Error('Dragging requires selection to be enabled');
                    }
                    if (!hint) {
                        hint = defaultHint;
                    }
                    that._draggable = new kendo.ui.Draggable(that.wrapper, {
                        filter: draggable.filter ? draggable.filter : DEFAULT_FILTER,
                        hint: kendo.isFunction(hint) ? hint : $(hint),
                        dragstart: proxy(that._dragstart, that),
                        dragcancel: proxy(that._clear, that),
                        drag: proxy(that._drag, that),
                        dragend: proxy(that._dragend, that)
                    });
                }
            },
            _dragstart: function (e) {
                var that = this;
                var draggedElement = that.draggedElement = e.currentTarget;
                var placeholder = that.options.draggable.placeholder;
                var dataItem = that.dataItem(draggedElement);
                var eventData = {
                    dataItems: dataItem,
                    items: $(draggedElement),
                    draggableEvent: e
                };
                if (that.options.draggable.enabled === false) {
                    e.preventDefault();
                    return;
                }
                if (!placeholder) {
                    placeholder = defaultPlaceholder;
                }
                that.placeholder = kendo.isFunction(placeholder) ? $(placeholder.call(that, draggedElement)) : $(placeholder);
                if (draggedElement.is(DOT + DISABLED_STATE_CLASS)) {
                    e.preventDefault();
                } else {
                    if (that.trigger(DRAGSTART, eventData)) {
                        e.preventDefault();
                    } else {
                        that.clearSelection();
                        that.select(draggedElement);
                        draggedElement.addClass(DRAGGEDCLASS);
                    }
                }
            },
            _clear: function () {
                this.draggedElement.removeClass(DRAGGEDCLASS);
                this.placeholder.remove();
            },
            _findElementUnderCursor: function (e) {
                var elementUnderCursor = kendo.elementUnderCursor(e);
                var draggable = e.sender;
                if ($.contains(draggable.hint[0], elementUnderCursor) || draggable.hint[0] === elementUnderCursor) {
                    draggable.hint.hide();
                    elementUnderCursor = kendo.elementUnderCursor(e);
                    draggable.hint.show();
                }
                return elementUnderCursor;
            },
            _findTarget: function (e) {
                var that = this;
                var element = that._findElementUnderCursor(e);
                var elementNode = $(element);
                var list = that._getList();
                var items;
                var node;
                if ($.contains(list[0], element)) {
                    items = that.items();
                    element = elementNode.is('li') ? element : elementNode.closest('li')[0];
                    node = items.filter(element)[0] || items.has(element)[0];
                    if (node) {
                        node = $(node);
                        return !node.hasClass(DISABLED_STATE_CLASS) ? {
                            element: node,
                            listBox: that
                        } : null;
                    } else {
                        return null;
                    }
                } else if (list[0] == element || list.parent()[0] == element) {
                    return {
                        element: $(list),
                        appendToBottom: true,
                        listBox: that
                    };
                } else {
                    return that._searchConnectedListBox(elementNode);
                }
            },
            _getElementCenter: function (element) {
                var center = element.length ? kendo.getOffset(element) : null;
                if (center) {
                    center.top += outerHeight(element) / 2;
                    center.left += outerWidth(element) / 2;
                }
                return center;
            },
            _searchConnectedListBox: function (element) {
                var connectedListBox;
                var items;
                var node;
                var originalElement = element;
                var closestContainer;
                if (element.hasClass('k-list-scroller k-selectable')) {
                    closestContainer = element;
                } else {
                    closestContainer = element.closest('.k-list-scroller.k-selectable');
                }
                if (closestContainer.length) {
                    connectedListBox = closestContainer.parent().find('[data-role=\'listbox\']').getKendoListBox();
                } else {
                    return null;
                }
                if (connectedListBox && $.inArray(this.element[0].id, connectedListBox.options.dropSources) !== -1) {
                    items = connectedListBox.items();
                    element = element.is('li') ? element[0] : element.closest('li')[0];
                    node = items.filter(element)[0] || items.has(element)[0];
                    if (node) {
                        node = $(node);
                        return !node.hasClass(DISABLED_STATE_CLASS) ? {
                            element: node,
                            listBox: connectedListBox
                        } : null;
                    } else if (!items.length || originalElement.hasClass('k-list-scroller k-selectable') || originalElement.hasClass('k-reset k-list')) {
                        return {
                            element: connectedListBox._getList(),
                            listBox: connectedListBox,
                            appendToBottom: true
                        };
                    } else {
                        return null;
                    }
                }
                return null;
            },
            _drag: function (e) {
                var that = this;
                var draggedElement = that.draggedElement;
                var target = that._findTarget(e);
                var cursorOffset = {
                    left: e.x.location,
                    top: e.y.location
                };
                var dataItem = that.dataItem(draggedElement);
                var eventData = {
                    dataItems: [dataItem],
                    items: $(draggedElement),
                    draggableEvent: e
                };
                var targetCenter;
                var offsetDelta;
                var direction;
                if (that.trigger(DRAG, eventData)) {
                    e.preventDefault();
                    return;
                }
                if (target) {
                    targetCenter = this._getElementCenter(target.element);
                    offsetDelta = {
                        left: Math.round(cursorOffset.left - targetCenter.left),
                        top: Math.round(cursorOffset.top - targetCenter.top)
                    };
                    if (target.appendToBottom) {
                        that._movePlaceholder(target, null, draggedElement);
                        return;
                    }
                    if (offsetDelta.top < 0) {
                        direction = 'prev';
                    } else if (offsetDelta.top > 0) {
                        direction = 'next';
                    }
                    if (direction) {
                        if (target.element[0] != that.placeholder[0]) {
                            that._movePlaceholder(target, direction, draggedElement);
                        }
                    }
                } else if (that.placeholder.parent().length) {
                    that.placeholder.remove();
                }
            },
            _movePlaceholder: function (target, direction, draggedElement) {
                var that = this;
                var placeholder = that.placeholder;
                var draggableOptions = target.listBox.options.draggable;
                if (placeholder.parent().length) {
                    that.placeholder.remove();
                    if (draggableOptions && draggableOptions.placeholder) {
                        that.placeholder = kendo.isFunction(draggableOptions.placeholder) ? $(draggableOptions.placeholder.call(that, draggedElement)) : $(draggableOptions.placeholder);
                    } else {
                        that.placeholder = $(defaultPlaceholder.call(that, draggedElement));
                    }
                }
                if (!direction) {
                    target.element.append(that.placeholder);
                } else if (direction === 'prev') {
                    target.element.before(that.placeholder);
                } else if (direction === 'next') {
                    target.element.after(that.placeholder);
                }
            },
            _dragend: function (e) {
                var that = this;
                var draggedItem = that.draggedElement;
                var items = that.items();
                var placeholderIndex = items.not(that.draggedElement).index(that.placeholder);
                var draggedIndex = items.not(that.placeholder).index(that.draggedElement);
                var dataItem = that.dataItem(draggedItem);
                var eventData = {
                    dataItems: [dataItem],
                    items: $(draggedItem)
                };
                var connectedListBox = that.placeholder.closest('.k-widget.k-listbox').find('[data-role=\'listbox\']').getKendoListBox();
                if (that.trigger(DROP, extend({}, eventData, { draggableEvent: e }))) {
                    e.preventDefault();
                    this._clear();
                    return;
                }
                if (placeholderIndex >= 0) {
                    if (placeholderIndex !== draggedIndex && !that.trigger(REORDER, extend({}, eventData, { offset: placeholderIndex - draggedIndex }))) {
                        draggedItem.removeClass(DRAGGEDCLASS);
                        that.reorder(draggedItem, placeholderIndex);
                    }
                } else if (connectedListBox) {
                    if (!that.trigger(REMOVE, eventData)) {
                        that.remove($(draggedItem));
                    }
                    if (!connectedListBox.trigger(ADD, eventData)) {
                        connectedListBox._addItemAt(dataItem, connectedListBox.items().index(that.placeholder));
                    }
                }
                that._clear();
                that._draggable.dropped = true;
                that.trigger(DRAGEND, extend({}, eventData, { draggableEvent: e }));
            },
            reorder: function (item, index) {
                var that = this;
                var dataSource = that.dataSource;
                var dataItem = that.dataItem(item);
                var dataItemAtIndex = dataSource.at(index);
                var itemAtIndex = that.items()[index];
                var listItem = $(item);
                if (dataItem && itemAtIndex && dataItemAtIndex) {
                    that._removeElement(listItem);
                    that._insertElementAt(listItem, index);
                    that._updateToolbar();
                }
            },
            remove: function (items) {
                var that = this;
                var listItems = that._getItems(items);
                var itemsLength = listItems.length;
                var i;
                that._unbindDataSource();
                for (i = 0; i < itemsLength; i++) {
                    that._removeItem($(listItems[i]));
                }
                that._bindDataSource();
                that._syncElement();
                that._updateToolbar();
                that._updateAllToolbars();
            },
            _removeItem: function (item) {
                var that = this;
                var dataSource = that.dataSource;
                var dataItem = that.dataItem(item);
                if (!dataItem || !dataSource) {
                    return;
                }
                if (typeof dataItem === typeof '') {
                    var data = dataSource._data;
                    for (var i = 0; i < data.length; i++) {
                        if (dataItem === data[i]) {
                            data[i] = data[data.length - 1];
                            data.pop();
                            break;
                        }
                    }
                } else {
                    dataSource.remove(dataItem);
                }
                that._removeElement(item);
            },
            _removeElement: function (item) {
                kendo.destroy(item);
                $(item).off().remove();
            },
            dataItem: function (element) {
                var uniqueIdAttr = kendoAttr(UNIQUE_ID);
                var uid = $(element).attr(uniqueIdAttr) || $(element).closest('[' + uniqueIdAttr + ']').attr(uniqueIdAttr);
                if (uid) {
                    return this.dataSource.getByUid(uid);
                } else {
                    return $(element).html();
                }
            },
            _dataItems: function (items) {
                var dataItems = [];
                var listItems = $(items);
                var itemsLength = listItems.length;
                var i;
                for (i = 0; i < itemsLength; i++) {
                    dataItems.push(this.dataItem(listItems.eq(i)));
                }
                return dataItems;
            },
            items: function () {
                var list = this._getList();
                return list.children();
            },
            select: function (items) {
                var that = this;
                var selectable = that.selectable;
                var enabledItems;
                if (isUndefined(items)) {
                    return selectable.value();
                }
                enabledItems = that.items().filter(items).filter(ENABLED_ITEMS_SELECTOR);
                if (!selectable.options.multiple) {
                    selectable.clear();
                    enabledItems = enabledItems.first();
                }
                return selectable.value(enabledItems);
            },
            clearSelection: function () {
                var that = this;
                var selectable = that.selectable;
                if (selectable) {
                    selectable.clear();
                }
            },
            enable: function (items, enable) {
                var that = this;
                var enabled = isUndefined(enable) ? true : !!enable;
                var listItems = that._getItems(items);
                var itemsLength = listItems.length;
                var i;
                for (i = 0; i < itemsLength; i++) {
                    that._enableItem($(listItems[i]), enabled);
                }
                that._updateAllToolbars();
            },
            _enableItem: function (item, enable) {
                var that = this;
                var dataItem = that.dataItem(item);
                if (dataItem) {
                    if (enable) {
                        $(item).removeClass(DISABLED_STATE_CLASS);
                    } else {
                        $(item).addClass(DISABLED_STATE_CLASS).removeClass(SELECTED_STATE_CLASS);
                    }
                }
            },
            setDataSource: function (dataSource) {
                var that = this;
                that.options.dataSource = dataSource;
                that._dataSource();
            },
            _dataSource: function () {
                var that = this;
                var options = that.options;
                var dataSource = options.dataSource || {};
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                dataSource.select = that.element;
                dataSource.fields = [
                    { field: options.dataTextField },
                    { field: options.dataValueField }
                ];
                that._unbindDataSource();
                that.dataSource = DataSource.create(dataSource);
                that._bindDataSource();
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
            },
            _bindDataSource: function () {
                var that = this;
                var dataSource = that.dataSource;
                that._dataChangeHandler = proxy(that.refresh, that);
                if (dataSource) {
                    dataSource.bind(CHANGE, that._dataChangeHandler);
                }
            },
            _unbindDataSource: function () {
                var that = this;
                var dataSource = that.dataSource;
                if (dataSource) {
                    dataSource.unbind(CHANGE, that._dataChangeHandler);
                }
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper = element.parent('div.k-listbox');
                if (!wrapper[0]) {
                    wrapper = element.wrap('<div class="k-widget k-listbox" deselectable="on" />').parent();
                    wrapper[0].style.cssText = element[0].style.cssText;
                    wrapper[0].title = element[0].title;
                    $('<div class="k-list-scroller" />').insertBefore(element);
                }
                that.wrapper = wrapper.addClass(element[0].className).css('display', '');
                that._innerWrapper = $(wrapper[0].firstChild);
            },
            _list: function () {
                var that = this;
                $('<ul class=\'' + LIST_CLASS + '\' role=\'listbox\'></ul>').appendTo(that._innerWrapper);
                if (that.options.navigatable) {
                    that._getList().attr(TABINDEX, that._getTabIndex());
                }
            },
            _templates: function () {
                var that = this;
                var options = this.options;
                var template;
                if (options.template && typeof options.template == 'string') {
                    template = kendo.template(options.template);
                } else if (!options.template) {
                    template = kendo.template('${' + kendo.expr(options.dataTextField, 'data') + '}', { useWithBlock: false });
                } else {
                    template = options.template;
                }
                that.templates = {
                    itemTemplate: kendo.template('# var item = data.item, r = data.r; # <li class=\'k-item\' role=\'option\' aria-selected=\'false\'>#=r(item)#</li>', { useWithBlock: false }),
                    itemContent: template,
                    toolbar: '<div class=\'' + TOOLBAR_CLASS + '\'></div>'
                };
            },
            refresh: function () {
                var that = this;
                var view = that.dataSource.view();
                var template = that.templates.itemTemplate;
                var html = '';
                for (var idx = 0; idx < view.length; idx++) {
                    html += template({
                        item: view[idx],
                        r: that.templates.itemContent
                    });
                }
                that._getList().html(html);
                that._setItemIds();
                that._createToolbar();
                that._syncElement();
                that._updateToolbar();
                that._updateAllToolbars();
                that.trigger(DATABOUND);
            },
            _syncElement: function () {
                var options = '';
                var view = this.dataSource.view();
                for (var idx = 0; idx < view.length; idx++) {
                    options += this._option(view[idx][this.options.dataValueField] || view[idx], view[idx][this.options.dataTextField] || view[idx], true);
                }
                this.element.html(options);
            },
            _option: function (dataValue, dataText) {
                var option = '<option';
                if (dataValue !== undefined) {
                    dataValue += '';
                    if (dataValue.indexOf('"') !== -1) {
                        dataValue = dataValue.replace(/"/g, '&quot;');
                    }
                    option += ' value="' + dataValue + '"';
                }
                option += ' selected>';
                if (dataText !== undefined) {
                    option += kendo.htmlEncode(dataText);
                }
                return option += '</option>';
            },
            _setItemIds: function () {
                var that = this;
                var items = that.items();
                var view = that.dataSource.view();
                var viewLength = view.length;
                var i;
                for (i = 0; i < viewLength; i++) {
                    items.eq(i).attr(kendoAttr(UNIQUE_ID), view[i].uid).attr('id', view[i].uid);
                }
            },
            _selectable: function () {
                var that = this;
                var selectable = that.options.selectable;
                var selectableOptions = Selectable.parseOptions(selectable);
                if (selectableOptions.multiple) {
                    that.element.attr('aria-multiselectable', 'true');
                }
                that.selectable = new Selectable(that._innerWrapper, {
                    aria: true,
                    multiple: selectableOptions.multiple,
                    filter: ENABLED_ITEM_SELECTOR,
                    change: proxy(that._onSelect, that)
                });
            },
            _onSelect: function () {
                var that = this;
                that._updateToolbar();
                that._updateAllToolbars();
                that.trigger(CHANGE);
            },
            _destroySelectable: function () {
                var that = this;
                if (that.selectable) {
                    that.selectable.destroy();
                    that.selectable = null;
                }
            },
            _getList: function () {
                return this.wrapper.find(LIST_SELECTOR);
            },
            _getItems: function (items) {
                return this.items().filter(items);
            },
            _createToolbar: function () {
                var that = this;
                var toolbarOptions = that.options.toolbar;
                var position = toolbarOptions.position || RIGHT;
                var toolbarInsertion = position === BOTTOM ? 'insertAfter' : 'insertBefore';
                var tools = toolbarOptions.tools || [];
                var messages = that.options.messages;
                that._destroyToolbar();
                that.wrapper.removeClass(TOOLBAR_POSITION_CLASS_NAMES.join(SPACE));
                if (tools.length && tools.length > 0) {
                    var toolbarElement = $(that.templates.toolbar)[toolbarInsertion](that._innerWrapper);
                    that.toolbar = new ToolBar(toolbarElement, extend({}, toolbarOptions, {
                        listBox: that,
                        messages: messages
                    }));
                    that.wrapper.addClass(TOOLBAR_CLASS + DASH + position);
                }
            },
            _destroyToolbar: function () {
                var that = this;
                if (that.toolbar) {
                    that.toolbar.destroy();
                    that.toolbar = null;
                }
            },
            _executeCommand: function (commandName) {
                var that = this;
                var command = CommandFactory.current.create(commandName, { listBox: that });
                if (command) {
                    command.execute();
                    that._updateToolbar();
                    that._updateAllToolbars();
                }
            },
            _updateToolbar: function () {
                var toolbar = this.toolbar;
                if (toolbar) {
                    toolbar._updateToolStates();
                }
            },
            _updateAllToolbars: function () {
                var listBoxElements = $('select[data-role=\'listbox\']');
                var elementsLength = listBoxElements.length;
                var listBox;
                var i;
                for (i = 0; i < elementsLength; i++) {
                    listBox = $(listBoxElements[i]).data(KENDO_LISTBOX);
                    if (listBox) {
                        listBox._updateToolbar();
                    }
                }
            }
        });
        kendo.ui.plugin(ListBox);
        var CommandFactory = Class.extend({
            init: function () {
                this._commands = [];
            },
            register: function (commandName, commandType) {
                this._commands.push({
                    commandName: commandName,
                    commandType: commandType
                });
            },
            create: function (commandName, options) {
                var commands = this._commands;
                var itemsLength = commands.length;
                var name = commandName ? commandName.toLowerCase() : '';
                var match;
                var command;
                var i;
                for (i = 0; i < itemsLength; i++) {
                    command = commands[i];
                    if (command.commandName.toLowerCase() === name) {
                        match = command;
                        break;
                    }
                }
                if (match) {
                    return new match.commandType(options);
                }
            }
        });
        CommandFactory.current = new CommandFactory();
        var ListBoxCommand = Class.extend({
            init: function (options) {
                var that = this;
                that.options = extend({}, that.options, options);
                that.listBox = that.options.listBox;
            },
            options: { listBox: null },
            getItems: function () {
                return $(this.listBox.select());
            },
            execute: noop,
            canExecute: noop
        });
        var RemoveItemsCommand = ListBoxCommand.extend({
            execute: function () {
                var that = this;
                var listBox = that.listBox;
                var items = that.getItems();
                if (!listBox.trigger(REMOVE, {
                        dataItems: listBox._dataItems(items),
                        items: items
                    })) {
                    listBox.remove(items);
                }
            },
            canExecute: function () {
                return this.listBox.select().length > 0;
            }
        });
        CommandFactory.current.register(REMOVE, RemoveItemsCommand);
        var MoveItemsCommand = ListBoxCommand.extend({
            execute: function () {
                var that = this;
                if (that.canExecute()) {
                    that.moveItems();
                }
            },
            canExecute: noop,
            moveItems: function () {
                var that = this;
                var listBox = that.listBox;
                var options = that.options;
                var items = that.getItems();
                var offset = options.offset;
                var indecesInDom = getSortedDomIndices(items);
                var movedItems = $.makeArray(items.sort(that.itemComparer));
                var moveAction = options.moveAction;
                var movedItem;
                if (!listBox.trigger(REORDER, {
                        dataItems: listBox._dataItems(movedItems),
                        items: $(movedItems),
                        offset: offset
                    })) {
                    while (movedItems.length > 0 && indecesInDom.length > 0) {
                        movedItem = movedItems[moveAction]();
                        listBox.reorder(movedItem, indecesInDom[moveAction]() + offset);
                    }
                }
            },
            options: {
                offset: 0,
                moveAction: 'pop'
            },
            itemComparer: function (item1, item2) {
                var indexItem1 = $(item1).index();
                var indexItem2 = $(item2).index();
                if (indexItem1 === indexItem2) {
                    return 0;
                } else {
                    return indexItem1 > indexItem2 ? 1 : -1;
                }
            }
        });
        var MoveUpItemsCommand = MoveItemsCommand.extend({
            options: {
                offset: MOVE_UP_OFFSET,
                moveAction: 'shift'
            },
            canExecute: function () {
                var items = this.getItems();
                var domIndices = getSortedDomIndices(items);
                return domIndices.length > 0 && domIndices[0] > 0;
            }
        });
        CommandFactory.current.register(MOVE_UP, MoveUpItemsCommand);
        var MoveDownItemsCommand = MoveItemsCommand.extend({
            options: {
                offset: MOVE_DOWN_OFFSET,
                moveAction: 'pop'
            },
            canExecute: function () {
                var that = this;
                var items = that.getItems();
                var domIndices = getSortedDomIndices(items);
                return domIndices.length > 0 && $(domIndices).last()[0] < that.listBox.items().length - 1;
            }
        });
        CommandFactory.current.register(MOVE_DOWN, MoveDownItemsCommand);
        var TransferItemsCommand = ListBoxCommand.extend({
            options: { filter: ENABLED_ITEM_SELECTOR },
            execute: function () {
                var that = this;
                var sourceListBox = that.getSourceListBox();
                var items = that.getItems().filter(that.options.filter);
                var dataItems = sourceListBox ? sourceListBox._dataItems(items) : [];
                var destinationListBox = that.getDestinationListBox();
                var updatedSelection = that.getUpdatedSelection(items);
                if (destinationListBox && items.length > 0) {
                    if (!destinationListBox.trigger(ADD, {
                            dataItems: dataItems,
                            items: items
                        })) {
                        destinationListBox.add(dataItems);
                    }
                    if (!sourceListBox.trigger(REMOVE, {
                            dataItems: dataItems,
                            items: items
                        })) {
                        sourceListBox.remove(items);
                        that.updateSelection(updatedSelection);
                    }
                }
            },
            getUpdatedSelection: function (items) {
                var that = this;
                var itemFilter = that.options.filter;
                var sourceListBox = that.getSourceListBox();
                var lastEnabledItem = sourceListBox ? sourceListBox.items().filter(itemFilter).last() : null;
                var containsLastItem = $(items).filter(lastEnabledItem).length > 0;
                var itemToSelect = containsLastItem ? $(items).prevAll(itemFilter)[0] : $(items).nextAll(itemFilter)[0];
                if ($(items).length === 1 && itemToSelect) {
                    return itemToSelect;
                } else {
                    return null;
                }
            },
            updateSelection: function (item) {
                var sourceListBox = this.getSourceListBox();
                if (sourceListBox && item) {
                    $(sourceListBox.select($(item)));
                    sourceListBox._scrollIntoView(item);
                }
            },
            getSourceListBox: noop,
            getDestinationListBox: noop
        });
        var TransferItemsToCommand = TransferItemsCommand.extend({
            canExecute: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.select().length > 0 : false;
            },
            getSourceListBox: function () {
                return this.listBox;
            },
            getDestinationListBox: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox && sourceListBox.options.connectWith ? $(HASH + sourceListBox.options.connectWith).data(KENDO_LISTBOX) : null;
            },
            getItems: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? $(sourceListBox.select()) : $();
            }
        });
        CommandFactory.current.register(TRANSFER_TO, TransferItemsToCommand);
        var TransferItemsFromCommand = TransferItemsCommand.extend({
            canExecute: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.select().length > 0 : false;
            },
            getSourceListBox: function () {
                var destinationListBox = this.getDestinationListBox();
                return destinationListBox && destinationListBox.options.connectWith ? $(HASH + destinationListBox.options.connectWith).data(KENDO_LISTBOX) : null;
            },
            getDestinationListBox: function () {
                return this.listBox;
            },
            getItems: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? $(sourceListBox.select()) : $();
            }
        });
        CommandFactory.current.register(TRANSFER_FROM, TransferItemsFromCommand);
        var TransferAllItemsToCommand = TransferItemsToCommand.extend({
            canExecute: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.items().filter(ENABLED_ITEM_SELECTOR).length > 0 : false;
            },
            getItems: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.items() : $();
            },
            getUpdatedSelection: noop,
            updateSelection: noop
        });
        CommandFactory.current.register(TRANSFER_ALL_TO, TransferAllItemsToCommand);
        var TransferAllItemsFromCommand = TransferItemsFromCommand.extend({
            canExecute: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.items().filter(ENABLED_ITEM_SELECTOR).length > 0 : false;
            },
            getItems: function () {
                var sourceListBox = this.getSourceListBox();
                return sourceListBox ? sourceListBox.items() : $();
            },
            getUpdatedSelection: noop,
            updateSelection: noop
        });
        CommandFactory.current.register(TRANSFER_ALL_FROM, TransferAllItemsFromCommand);
        var ToolBar = Class.extend({
            init: function (element, options) {
                var that = this;
                that.element = $(element).addClass(TOOLBAR_CLASS);
                that.options = extend({}, that.options, options);
                that.listBox = that.options.listBox;
                that._initTemplates();
                that._createTools();
                that._updateToolStates();
                that._attachEventHandlers();
            },
            destroy: function () {
                var that = this;
                that._detachEventHandlers();
                kendo.destroy(that.element);
                that.element.remove();
                that.element = null;
            },
            options: {
                position: RIGHT,
                tools: []
            },
            _initTemplates: function () {
                this.templates = { tool: kendoTemplate('<li>' + '<a href=\'\\\\#\' class=\'k-button k-button-icon k-tool\' data-command=\'#= command #\' title=\'#= text #\' aria-label=\'#= text #\' role=\'button\'>' + '<span class=\'k-icon #= iconClass #\'></span>' + '</a>' + '</li>') };
            },
            _createTools: function () {
                var that = this;
                var tools = that.options.tools;
                var toolsLength = tools.length;
                var toolsMessages = that.options.messages.tools;
                var toolList = that._createToolList();
                var tool;
                var i;
                for (i = 0; i < toolsLength; i++) {
                    tool = extend({}, ToolBar.defaultTools[tools[i]], { text: toolsMessages[tools[i]] });
                    if (tool) {
                        toolList.append($(that.templates.tool(tool)));
                    }
                }
                that.element.append(toolList);
            },
            _createToolList: function () {
                return $('<ul class=\'k-reset\' />');
            },
            _attachEventHandlers: function () {
                var that = this;
                that.element.on(CLICK, TOOL_SELECTOR, proxy(that._onToolClick, that));
            },
            _detachEventHandlers: function () {
                this.element.off(NS).find('*').off(NS);
            },
            _onToolClick: function (e) {
                e.preventDefault();
                this._executeToolCommand($(e.currentTarget).data(COMMAND));
            },
            _executeToolCommand: function (command) {
                var that = this;
                var listBox = that.listBox;
                if (listBox) {
                    listBox._executeCommand(command);
                }
            },
            _updateToolStates: function () {
                var that = this;
                var tools = that.options.tools;
                var toolsLength = tools.length;
                var i;
                for (i = 0; i < toolsLength; i++) {
                    that._updateToolState(tools[i]);
                }
            },
            _updateToolState: function (toolName) {
                var that = this;
                var command = CommandFactory.current.create(toolName, { listBox: that.listBox });
                var toolElement = that.element.find('[data-command=\'' + toolName + '\']')[0];
                if (toolElement && command && command.canExecute) {
                    if (command.canExecute()) {
                        $(toolElement).removeClass(DISABLED_STATE_CLASS);
                    } else {
                        $(toolElement).addClass(DISABLED_STATE_CLASS);
                    }
                }
            }
        });
        ToolBar.defaultTools = {
            remove: {
                command: REMOVE,
                iconClass: 'k-i-x'
            },
            moveUp: {
                command: MOVE_UP,
                iconClass: 'k-i-arrow-60-up'
            },
            moveDown: {
                command: MOVE_DOWN,
                iconClass: 'k-i-arrow-60-down'
            },
            transferTo: {
                command: TRANSFER_TO,
                iconClass: 'k-i-arrow-60-right'
            },
            transferFrom: {
                command: TRANSFER_FROM,
                iconClass: 'k-i-arrow-60-left'
            },
            transferAllTo: {
                command: TRANSFER_ALL_TO,
                iconClass: 'k-i-arrow-double-60-right'
            },
            transferAllFrom: {
                command: TRANSFER_ALL_FROM,
                iconClass: 'k-i-arrow-double-60-left'
            }
        };
        extend(ListBox, { ToolBar: ToolBar });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.upload', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'upload',
        name: 'Upload',
        category: 'web',
        description: 'The Upload widget uses progressive enhancement to deliver the best possible uploading experience to users.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, antiForgeryTokens = kendo.antiForgeryTokens, logToConsole = kendo.logToConsole, rFileExtension = /\.([^\.]+)$/, NS = '.kendoUpload', SELECT = 'select', UPLOAD = 'upload', SUCCESS = 'success', ERROR = 'error', COMPLETE = 'complete', CANCEL = 'cancel', CLEAR = 'clear', PAUSE = 'pause', RESUME = 'resume', PROGRESS = 'progress', REMOVE = 'remove', VALIDATIONERRORS = 'validationErrors', INVALIDMAXFILESIZE = 'invalidMaxFileSize', INVALIDMINFILESIZE = 'invalidMinFileSize', INVALIDFILEEXTENSION = 'invalidFileExtension', PROGRESSHIDEDELAY = 1000, PROGRESSHIDEDURATION = 2000;
        var headerStatusIcon = {
            loading: 'k-i-loading',
            warning: 'k-i-warning',
            success: 'k-i-check'
        };
        var Upload = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.name = element.name;
                that.multiple = that.options.multiple;
                that.directory = that.options.directory;
                that.localization = that.options.localization;
                var activeInput = that.element;
                that.wrapper = activeInput.closest('.k-upload');
                if (that.wrapper.length === 0) {
                    that.wrapper = that._wrapInput(activeInput);
                }
                that._activeInput(activeInput);
                that.toggle(that.options.enabled);
                var ns = that._ns = NS + '-' + kendo.guid();
                activeInput.closest('form').on('submit' + ns, $.proxy(that._onParentFormSubmit, that)).on('reset' + ns, $.proxy(that._onParentFormReset, that));
                if (that.options.async.saveUrl) {
                    that._module = that._supportsFormData() ? new formDataUploadModule(that) : new iframeUploadModule(that);
                    that._async = true;
                    var initialFiles = that.options.files;
                    if (initialFiles.length > 0) {
                        that._renderInitialFiles(initialFiles);
                    }
                } else {
                    that._module = new syncUploadModule(that);
                }
                if (that._supportsDrop()) {
                    if (that.options.dropZone !== '') {
                        that._setupCustomDropZone();
                    } else {
                        that._setupDropZone();
                    }
                }
                that.wrapper.on('click', '.k-upload-action', $.proxy(that._onFileAction, that)).on('click', '.k-clear-selected', $.proxy(that._onClearSelected, that)).on('click', '.k-upload-selected', $.proxy(that._onUploadSelected, that));
                if (that.element.val()) {
                    that._onInputChange({ target: that.element });
                }
            },
            events: [
                SELECT,
                UPLOAD,
                SUCCESS,
                ERROR,
                COMPLETE,
                CANCEL,
                CLEAR,
                PROGRESS,
                REMOVE,
                PAUSE,
                RESUME
            ],
            options: {
                name: 'Upload',
                enabled: true,
                multiple: true,
                directory: false,
                showFileList: true,
                template: '',
                files: [],
                async: {
                    autoRetryAfter: 0,
                    bufferChunkSize: 10000000,
                    maxAutoRetries: 1,
                    removeVerb: 'POST',
                    autoUpload: true,
                    withCredentials: true,
                    accept: '*/*; q=0.5, application/json',
                    useArrayBuffer: false
                },
                localization: {
                    'select': 'Select files...',
                    'cancel': 'Cancel',
                    'retry': 'Retry',
                    'remove': 'Remove',
                    'pause': 'Pause',
                    'resume': 'Resume',
                    'clearSelectedFiles': 'Clear',
                    'uploadSelectedFiles': 'Upload',
                    'dropFilesHere': 'Drop files here to upload',
                    'invalidFiles': 'Invalid file(s). Please check file upload requirements.',
                    'statusUploading': 'uploading',
                    'statusUploaded': 'uploaded',
                    'statusWarning': 'warning',
                    'statusFailed': 'failed',
                    'headerStatusUploading': 'Uploading...',
                    'headerStatusPaused': 'Paused',
                    'headerStatusUploaded': 'Done',
                    'invalidMaxFileSize': 'File size too large.',
                    'invalidMinFileSize': 'File size too small.',
                    'invalidFileExtension': 'File type not allowed.'
                },
                validation: {
                    allowedExtensions: [],
                    maxFileSize: 0,
                    minFileSize: 0
                },
                dropZone: ''
            },
            setOptions: function (options) {
                var that = this, activeInput = that.element;
                Widget.fn.setOptions.call(that, options);
                that.multiple = that.options.multiple;
                that.directory = that.options.directory;
                activeInput.attr('multiple', that._supportsMultiple() ? that.multiple : false);
                if (that.directory) {
                    activeInput.attr('webkitdirectory', that.directory);
                    activeInput.attr('directory', that.directory);
                }
                that.toggle(that.options.enabled);
            },
            enable: function (enable) {
                enable = typeof enable === 'undefined' ? true : enable;
                this.toggle(enable);
            },
            disable: function () {
                this.toggle(false);
            },
            toggle: function (enable) {
                enable = typeof enable === 'undefined' ? enable : !enable;
                this.wrapper.toggleClass('k-state-disabled', enable);
                this.element.prop('disabled', enable);
            },
            focus: function () {
                this.element.focus();
            },
            destroy: function () {
                var that = this;
                var customDropZone = $(that.options.dropZone);
                $(document).add($('.k-dropzone', that.wrapper)).add(that.wrapper.closest('form')).off(that._ns);
                if (customDropZone.length > 0) {
                    customDropZone.off(that._ns);
                }
                $(that.element).off(NS);
                Widget.fn.destroy.call(that);
            },
            pause: function (fileEntry) {
                this._module.onPause({ target: $(fileEntry, this.wrapper) });
                var pauseIcon = fileEntry.find('.k-i-pause-sm');
                pauseIcon.removeClass('k-i-pause-sm').addClass('k-i-play-sm').attr('title', this.localization.resume);
                $(pauseIcon).parent().attr('aria-label', this.localization.resume);
            },
            resume: function (fileEntry) {
                this._module.onResume({ target: $(fileEntry, this.wrapper) });
                var playIcon = fileEntry.find('.k-i-play-sm');
                playIcon.removeClass('k-i-play-sm').addClass('k-i-pause-sm').attr('title', this.localization.pause);
                $(playIcon).parent().attr('aria-label', this.localization.pause);
            },
            upload: function () {
                var that = this;
                that._module.onSaveSelected();
            },
            getFiles: function () {
                var that = this;
                var filesData;
                var allFiles = [];
                var listItems = that.wrapper.find('.k-file');
                for (var i = 0; i < listItems.length; i++) {
                    filesData = $(listItems[i]).data('fileNames');
                    if (filesData) {
                        for (var j = 0; j < filesData.length; j++) {
                            allFiles.push(filesData[j]);
                        }
                    }
                }
                return allFiles;
            },
            clearAllFiles: function () {
                var that = this;
                var files = that.wrapper.find('.k-file');
                files.each(function (index, file) {
                    that._removeFileByDomElement(file, false);
                });
            },
            removeAllFiles: function () {
                var that = this;
                var files = that.wrapper.find('.k-file');
                files.each(function (index, file) {
                    that._removeFileByDomElement(file, true);
                });
            },
            removeFileByUid: function (uid) {
                this._removeFileByUid(uid, true);
            },
            clearFileByUid: function (uid) {
                this._removeFileByUid(uid, false);
            },
            _removeFileByUid: function (uid, shouldSendRemoveRequest) {
                var that = this;
                var fileEntry;
                if (typeof uid !== 'string') {
                    return;
                }
                fileEntry = $('.k-file[' + kendo.attr('uid') + '="' + uid + '"]', that.wrapper);
                if (fileEntry.length > 0) {
                    that._removeFileByDomElement(fileEntry, shouldSendRemoveRequest);
                }
            },
            clearFile: function (callback) {
                this._removeFile(callback, false);
            },
            removeFile: function (callback) {
                this._removeFile(callback, true);
            },
            _removeFile: function (callback, shouldSendRemoveRequest) {
                var that = this;
                var files = that.wrapper.find('.k-file');
                var fileData;
                if (typeof callback === 'function') {
                    files.each(function (index, file) {
                        fileData = $(file).data('fileNames');
                        if (callback(fileData)) {
                            that._removeFileByDomElement(file, shouldSendRemoveRequest);
                        }
                    });
                }
            },
            _removeFileByDomElement: function (fileEntry, shouldSendRemoveRequest) {
                var that = this;
                var fileData = { target: $(fileEntry, that.wrapper) };
                var allFiles;
                if (that.options.async.saveUrl) {
                    if ($(fileEntry).hasClass('k-file-progress')) {
                        that._module.onCancel(fileData);
                    } else {
                        that._module.onRemove(fileData, {}, shouldSendRemoveRequest);
                    }
                    allFiles = $('.k-file', that.wrapper);
                    if (allFiles.length === 0) {
                        that._hideHeaderUploadstatus();
                    } else {
                        that._updateHeaderUploadStatus();
                    }
                } else {
                    that._module.onRemove(fileData, {}, shouldSendRemoveRequest);
                }
            },
            _addInput: function (sourceInput) {
                if (!sourceInput[0].nodeType) {
                    return;
                }
                var that = this, input = sourceInput.clone().val('');
                input.insertAfter(that.element).data('kendoUpload', that);
                $(that.element).hide().attr('tabindex', '-1').removeAttr('id').off(NS);
                that._activeInput(input);
                that.element.focus();
            },
            _activeInput: function (input) {
                var that = this, wrapper = that.wrapper;
                that.element = input;
                if (that.directory) {
                    input.attr('webkitdirectory', that.directory);
                    input.attr('directory', that.directory);
                }
                input.attr('multiple', that._supportsMultiple() ? that.multiple : false).attr('autocomplete', 'off').on('click' + NS, function (e) {
                    if (wrapper.hasClass('k-state-disabled')) {
                        e.preventDefault();
                    }
                }).on('focus' + NS, function () {
                    $(this).parent().addClass('k-state-focused');
                }).on('blur' + NS, function () {
                    $(this).parent().removeClass('k-state-focused');
                }).on('change' + NS, $.proxy(that._onInputChange, that)).on('keydown' + NS, $.proxy(that._onInputKeyDown, that));
            },
            _onInputKeyDown: function (e) {
                var that = this;
                var firstButton = that.wrapper.find('.k-upload-action:visible:first');
                if (e.keyCode === kendo.keys.TAB && firstButton.length > 0) {
                    e.preventDefault();
                    firstButton.focus();
                }
            },
            _onInputChange: function (e) {
                var that = this;
                var input = $(e.target);
                var files = assignGuidToFiles(that._inputFiles(input), that._isAsyncNonBatch());
                validateFiles(files, that.options.validation);
                var prevented = that.trigger(SELECT, { files: files });
                if (prevented) {
                    that._addInput(input);
                    input.remove();
                } else {
                    that._module.onSelect({ target: input }, files);
                }
            },
            _readDirectory: function (item) {
                var deferred = new $.Deferred();
                var dirReader = item.createReader();
                dirReader.readEntries(function (entries) {
                    deferred.resolve(entries);
                }, deferred.reject);
                return deferred.promise();
            },
            _readFile: function (item) {
                var that = this;
                var fullpath = item.fullPath;
                item.file(function (file) {
                    file.relativePath = fullpath.slice(1);
                    that.droppedFolderFiles.push(file);
                    that.droppedFolderCounter--;
                    if (that.droppedFolderCounter === 0) {
                        setTimeout(function () {
                            if (that.droppedFolderCounter === 0) {
                                if (that.droppedFolderFiles.length) {
                                    that._proceedDroppedItems(that.droppedFolderFiles);
                                    that.droppedFolderFiles = [];
                                }
                            }
                        }, 0);
                    }
                }, function () {
                    logToConsole('File error.');
                });
            },
            _traverseFileTree: function (item, skipCounter) {
                var that = this;
                if (!skipCounter) {
                    that.droppedFolderCounter--;
                }
                this._readDirectory(item).then(function (items) {
                    that.droppedFolderCounter += items.length;
                    for (var i = 0; i < items.length; i++) {
                        if (items[i].isFile) {
                            that._readFile(items[i]);
                        } else if (items[i].isDirectory) {
                            that._traverseFileTree(items[i]);
                        }
                    }
                });
            },
            _onDrop: function (e) {
                var dt = e.originalEvent.dataTransfer;
                var that = this;
                var droppedFiles = dt.files;
                var length;
                stopEvent(e);
                if (that.options.directoryDrop && dt.items) {
                    length = dt.items.length;
                    that.droppedFolderCounter = 0;
                    that.droppedFolderFiles = [];
                    for (var i = 0; i < length; i++) {
                        if (dt.items[i].webkitGetAsEntry) {
                            var entry = dt.items[i].webkitGetAsEntry();
                            if (entry.isDirectory) {
                                that._traverseFileTree(entry, true);
                            } else if (entry.isFile) {
                                that.droppedFolderFiles.push(dt.files[i]);
                            }
                        } else {
                            that._proceedDroppedItems(droppedFiles);
                        }
                    }
                } else {
                    that._proceedDroppedItems(droppedFiles);
                }
            },
            _proceedDroppedItems: function (droppedFiles) {
                var that = this;
                var files = assignGuidToFiles(getAllFileInfo(droppedFiles), that._isAsyncNonBatch());
                if (droppedFiles.length > 0 && !that.wrapper.hasClass('k-state-disabled')) {
                    if (!that.multiple && files.length > 1) {
                        files.splice(1, files.length - 1);
                    }
                    validateFiles(files, that.options.validation);
                    var prevented = that.trigger(SELECT, { files: files });
                    if (!prevented) {
                        that._module.onSelect({ target: $('.k-dropzone', that.wrapper) }, files);
                    }
                }
            },
            _filesContainValidationErrors: function (files) {
                var hasErrors = false;
                $(files).each(function (index, file) {
                    if (file[VALIDATIONERRORS] && file[VALIDATIONERRORS].length > 0) {
                        hasErrors = true;
                        return false;
                    }
                });
                return hasErrors;
            },
            _isAsyncNonBatch: function () {
                return this._async && !this.options.async.batch || false;
            },
            _renderInitialFiles: function (files) {
                var that = this;
                var idx = 0;
                files = assignGuidToFiles(files, true);
                for (idx = 0; idx < files.length; idx++) {
                    var currentFile = files[idx];
                    var fileEntry = that._enqueueFile(currentFile.name, { fileNames: [currentFile] });
                    fileEntry.addClass('k-file-success').data('files', [files[idx]]);
                    if (that._supportsRemove()) {
                        that._fileAction(fileEntry, REMOVE);
                    }
                }
            },
            _prepareTemplateData: function (name, data) {
                var filesData = data.fileNames, templateData = {}, totalSize = 0, idx = 0;
                for (idx = 0; idx < filesData.length; idx++) {
                    totalSize += filesData[idx].size;
                }
                templateData.name = name;
                templateData.size = totalSize;
                templateData.files = data.fileNames;
                return templateData;
            },
            _prepareDefaultSingleFileEntryTemplate: function (data) {
                var that = this;
                var file = data.fileNames[0];
                var fileSize = getTotalFilesSizeMessage(data.fileNames);
                var errors = file[VALIDATIONERRORS];
                var template = '';
                if (errors && errors.length > 0) {
                    template += '<li class=\'k-file k-file-invalid\'><span class=\'k-progress\'></span>' + '<span class=\'k-file-invalid-extension-wrapper\'>' + '<span class=\'k-file-invalid-icon\'>!</span>' + '<span class=\'k-file-state\'></span>' + '</span>' + '<span class=\'k-file-name-size-wrapper\'>' + '<span class=\'k-file-name k-file-name-invalid\' title=\'' + file.name + '\'>' + file.name + '</span>' + '<span class=\'k-file-validation-message\'>' + that.localization[errors[0]] + '</span>' + '</span>';
                } else {
                    template += '<li class=\'k-file\'><span class=\'k-progress\'></span>' + '<span class=\'k-file-extension-wrapper\'>' + '<span class=\'k-file-extension\'>' + file.extension.substring(1) + '</span>' + '<span class=\'k-file-state\'></span>' + '</span>' + '<span class=\'k-file-name-size-wrapper\'><span class=\'k-file-name\' title=\'' + file.name + '\'>' + file.name + '</span>' + '<span class=\'k-file-size\'>' + fileSize + '</span></span>';
                }
                template += '<strong class=\'k-upload-status\'></strong>';
                return $(template);
            },
            _prepareDefaultMultipleFileEntriesTemplate: function (data) {
                var that = this;
                var files = data.fileNames;
                var filesHaveValidationErrors = that._filesContainValidationErrors(files);
                var totalFileSize = getTotalFilesSizeMessage(files);
                var template = '';
                var i, currentFile;
                if (filesHaveValidationErrors) {
                    template += '<li class=\'k-file k-file-invalid\'><span class=\'k-progress\'></span>' + '<span class=\'k-multiple-files-invalid-extension-wrapper\'>' + '<span class=\'k-file-invalid-icon\'>!</span>';
                } else {
                    template += '<li class=\'k-file\'><span class=\'k-progress\'></span>' + '<span class=\'k-multiple-files-extension-wrapper\'>';
                }
                template += '<span class=\'k-file-state\'></span></span>';
                files.sort(function (a, b) {
                    if (a[VALIDATIONERRORS]) {
                        return -1;
                    }
                    if (b[VALIDATIONERRORS]) {
                        return 1;
                    }
                    return 0;
                });
                template += '<span class=\'k-file-name-size-wrapper\'>';
                for (i = 0; i < files.length; i++) {
                    currentFile = files[i];
                    if (currentFile[VALIDATIONERRORS] && currentFile[VALIDATIONERRORS].length > 0) {
                        template += '<span class=\'k-file-name k-file-name-invalid\' title=\'' + currentFile.name + '\'>' + currentFile.name + '</span>';
                    } else {
                        template += '<span class=\'k-file-name\' title=\'' + currentFile.name + '\'>' + currentFile.name + '</span>';
                    }
                }
                if (filesHaveValidationErrors) {
                    template += '<span class=\'k-file-validation-message\'>' + that.localization.invalidFiles + '</span>';
                } else {
                    template += '<span class=\'k-file-information\'>Total: ' + files.length + ' files, ' + totalFileSize + '</span>';
                }
                template += '</span><strong class=\'k-upload-status\'></strong>';
                return $(template);
            },
            _enqueueFile: function (name, data) {
                var that = this;
                var existingFileEntries;
                var fileEntry;
                var fileUid = data.fileNames[0].uid;
                var fileList = $('.k-upload-files', that.wrapper);
                var options = that.options;
                var template = options.template;
                var templateData;
                var removeEventArgs;
                if (fileList.length === 0) {
                    fileList = $('<ul class=\'k-upload-files k-reset\'></ul>').appendTo(that.wrapper);
                    if (!that.options.showFileList) {
                        fileList.hide();
                    }
                    that.wrapper.removeClass('k-upload-empty');
                }
                existingFileEntries = $('.k-file', fileList);
                if (!template) {
                    if (data.fileNames.length === 1) {
                        fileEntry = that._prepareDefaultSingleFileEntryTemplate(data);
                    } else {
                        fileEntry = that._prepareDefaultMultipleFileEntriesTemplate(data);
                    }
                } else {
                    templateData = that._prepareTemplateData(name, data);
                    template = kendo.template(template);
                    fileEntry = $('<li class=\'k-file\'>' + template(templateData) + '</li>');
                    fileEntry.find('.k-upload-action').addClass('k-button');
                    that.angular('compile', function () {
                        return {
                            elements: fileEntry,
                            data: [templateData]
                        };
                    });
                }
                fileEntry.attr(kendo.attr('uid'), fileUid).appendTo(fileList).data(data);
                if (!that._async) {
                    $('.k-progress', fileEntry).width('100%');
                }
                if (!that.multiple && existingFileEntries.length > 0) {
                    removeEventArgs = {
                        files: existingFileEntries.data('fileNames'),
                        headers: {}
                    };
                    if (!that.trigger(REMOVE, removeEventArgs)) {
                        that._module.onRemove({ target: $(existingFileEntries, that.wrapper) }, removeEventArgs);
                    }
                }
                return fileEntry;
            },
            _removeFileEntry: function (fileEntry) {
                var that = this;
                var fileList = fileEntry.closest('.k-upload-files');
                var allFiles, allCompletedFiles, allInvalidFiles;
                fileEntry.remove();
                allFiles = $('.k-file', fileList);
                allCompletedFiles = $('.k-file-success, .k-file-error', fileList);
                allInvalidFiles = $('.k-file-invalid', fileList);
                if (allCompletedFiles.length === allFiles.length || allInvalidFiles.length === allFiles.length) {
                    this._hideUploadButton();
                }
                if (allFiles.length === 0) {
                    fileList.remove();
                    that.wrapper.addClass('k-upload-empty');
                    that._hideHeaderUploadstatus();
                } else {
                    that._updateHeaderUploadStatus();
                }
            },
            _fileAction: function (fileElement, actionKey, skipClear) {
                var classDictionary = {
                    remove: 'k-i-x',
                    cancel: 'k-i-cancel',
                    retry: 'k-i-retry',
                    pause: 'k-i-pause-sm'
                };
                var iconsClassDictionary = {
                    remove: 'k-i-close',
                    cancel: 'k-i-close',
                    retry: 'k-i-reload-sm',
                    pause: 'k-i-pause-sm'
                };
                if (!classDictionary.hasOwnProperty(actionKey)) {
                    return;
                }
                if (!skipClear) {
                    this._clearFileAction(fileElement);
                }
                if (!this.options.template) {
                    if (!skipClear) {
                        fileElement.find('.k-upload-status .k-upload-action').remove();
                    }
                    fileElement.find('.k-upload-status').append(this._renderAction(classDictionary[actionKey], this.localization[actionKey], iconsClassDictionary[actionKey]));
                } else {
                    fileElement.find('.k-upload-action').addClass('k-button').append('<span class=\'k-icon ' + iconsClassDictionary[actionKey] + ' ' + classDictionary[actionKey] + '\' title=\'' + this.localization[actionKey] + '\'' + 'aria-label=\'' + this.localization[actionKey] + '\'></span>').show();
                }
            },
            _fileState: function (fileEntry, stateKey) {
                var localization = this.localization, states = {
                        uploading: { text: localization.statusUploading },
                        uploaded: { text: localization.statusUploaded },
                        failed: { text: localization.statusFailed }
                    }, currentState = states[stateKey];
                if (currentState) {
                    $('span.k-file-state', fileEntry).text(currentState.text);
                }
            },
            _renderAction: function (actionClass, actionText, iconClass) {
                if (actionClass !== '') {
                    return $('<button type=\'button\' class=\'k-button k-upload-action\' aria-label=\'' + actionText + '\'>' + '<span class=\'k-icon ' + iconClass + ' ' + actionClass + '\' title=\'' + actionText + '\'></span>' + '</button>').on('focus', function () {
                        $(this).addClass('k-state-focused');
                    }).on('blur', function () {
                        $(this).removeClass('k-state-focused');
                    });
                } else {
                    return $('<button type=\'button\' class=\'k-button\'>' + actionText + '</button>');
                }
            },
            _clearFileAction: function (fileElement) {
                $('.k-upload-action', fileElement).empty().hide();
            },
            _onFileAction: function (e) {
                var that = this;
                if (!that.wrapper.hasClass('k-state-disabled')) {
                    var button = $(e.target).closest('.k-upload-action');
                    var icon = button.find('.k-icon');
                    var fileEntry = button.closest('.k-file');
                    var files = fileEntry.data('fileNames');
                    var hasValidationErrors = that._filesContainValidationErrors(files);
                    var eventArgs = {
                        files: files,
                        headers: {}
                    };
                    if (icon.hasClass('k-i-x')) {
                        if (!that.trigger(REMOVE, eventArgs)) {
                            that._module.onRemove({ target: $(fileEntry, that.wrapper) }, eventArgs, !hasValidationErrors);
                        }
                    } else if (icon.hasClass('k-i-cancel')) {
                        that.trigger(CANCEL, eventArgs);
                        that._module.onCancel({ target: $(fileEntry, that.wrapper) });
                        that._checkAllComplete();
                        that._updateHeaderUploadStatus();
                    } else if (icon.hasClass('k-i-pause-sm')) {
                        that.trigger(PAUSE, eventArgs);
                        that.pause(fileEntry);
                        that._updateHeaderUploadStatus();
                    } else if (icon.hasClass('k-i-play-sm')) {
                        that.trigger(RESUME, eventArgs);
                        that.resume(fileEntry);
                    } else if (icon.hasClass('k-i-retry')) {
                        $('.k-i-warning', fileEntry).remove();
                        $('.k-progress', fileEntry).finish().show();
                        that._module.onRetry({ target: $(fileEntry, that.wrapper) });
                    }
                }
                return false;
            },
            _onUploadSelected: function () {
                var that = this;
                var wrapper = that.wrapper;
                if (!wrapper.hasClass('k-state-disabled')) {
                    this._module.onSaveSelected();
                }
                return false;
            },
            _onClearSelected: function () {
                var that = this;
                var wrapper = that.wrapper;
                var clearEventArgs = {};
                if (!wrapper.hasClass('k-state-disabled') && !that.trigger(CLEAR, clearEventArgs)) {
                    that.clearAllFiles();
                }
                return false;
            },
            _onFileProgress: function (e, percentComplete) {
                var progressPct;
                var warningPct;
                if (percentComplete > 100) {
                    percentComplete = 100;
                }
                if (!this.options.template) {
                    progressPct = $('.k-upload-pct', e.target);
                    warningPct = $('.k-i-warning', e.target);
                    if (warningPct.length) {
                        warningPct.removeClass('k-i-warning').removeClass('k-icon').addClass('k-upload-pct');
                    } else if (progressPct.length === 0) {
                        $('.k-upload-status', e.target).prepend('<span class=\'k-upload-pct\'></span>');
                    }
                    if (percentComplete !== 100) {
                        $('.k-upload-pct', e.target).text(percentComplete + '%');
                    } else {
                        $('.k-upload-pct', e.target).remove();
                    }
                    $('.k-progress', e.target).width(percentComplete + '%');
                } else {
                    $('.k-progress', e.target).width(percentComplete + '%');
                }
                this.trigger(PROGRESS, {
                    files: getFileEntry(e).data('fileNames'),
                    percentComplete: percentComplete
                });
            },
            _onUploadSuccess: function (e, response, xhr) {
                var that = this;
                var fileEntry = getFileEntry(e);
                var prevented = that.trigger(SUCCESS, {
                    files: fileEntry.data('fileNames'),
                    response: response,
                    operation: 'upload',
                    XMLHttpRequest: xhr
                });
                if (prevented) {
                    that._setUploadErrorState(fileEntry);
                } else {
                    that._fileState(fileEntry, 'uploaded');
                    fileEntry.removeClass('k-file-progress').addClass('k-file-success');
                    that._updateHeaderUploadStatus();
                    if (that._supportsRemove()) {
                        that._fileAction(fileEntry, REMOVE);
                    } else {
                        that._clearFileAction(fileEntry);
                    }
                }
                that._hideUploadProgress(fileEntry);
                that._checkAllComplete();
            },
            _onUploadError: function (e, xhr) {
                var that = this;
                var module = that._module;
                var fileEntry = getFileEntry(e);
                var fileUid = fileEntry.data('uid');
                that._setUploadErrorState(fileEntry);
                that.trigger(ERROR, {
                    operation: 'upload',
                    files: fileEntry.data('fileNames'),
                    XMLHttpRequest: xhr
                });
                logToConsole('Server response: ' + xhr.responseText);
                if (!that.options.async.chunkSize) {
                    that._hideUploadProgress(fileEntry);
                } else {
                    if (module._decreasePosition) {
                        module._decreasePosition(fileUid);
                    }
                }
                that._checkAllComplete();
                if (this.options.async.autoRetryAfter) {
                    this._autoRetryAfter(fileEntry);
                }
            },
            _autoRetryAfter: function (fileEntry) {
                var that = this;
                var retries = this._module.retries;
                if (!retries) {
                    return;
                }
                if (!retries[fileEntry.data('uid')]) {
                    retries[fileEntry.data('uid')] = 1;
                }
                if (retries[fileEntry.data('uid')] <= this.options.async.maxAutoRetries) {
                    retries[fileEntry.data('uid')]++;
                    setTimeout(function () {
                        that._module.performUpload(fileEntry);
                    }, this.options.async.autoRetryAfter);
                }
            },
            _setUploadErrorState: function (fileEntry) {
                var that = this;
                var uploadPercentage;
                that._fileState(fileEntry, 'failed');
                fileEntry.removeClass('k-file-progress').addClass('k-file-error');
                that._updateUploadProgress(fileEntry);
                uploadPercentage = $('.k-upload-pct', fileEntry);
                if (uploadPercentage.length > 0) {
                    if (!uploadPercentage.parent().find('.k-i-warning').length) {
                        uploadPercentage.removeClass('k-upload-pct').addClass('k-icon k-i-warning');
                    }
                    uploadPercentage.empty();
                } else {
                    $('.k-upload-status', fileEntry).prepend('<span class=\'k-icon k-i-warning\'></span>');
                }
                this._updateHeaderUploadStatus();
                this._fileAction(fileEntry, 'retry');
                this._fileAction(fileEntry, REMOVE, true);
            },
            _updateUploadProgress: function (fileEntry) {
                var that = this;
                if (!that.options.async.chunkSize) {
                    $('.k-progress', fileEntry).width('100%');
                } else {
                    var fileUid = fileEntry.data('uid');
                    if (that._module.metaData) {
                        var fileMetaData = that._module.metaData[fileUid];
                        if (fileMetaData) {
                            var percentComplete = fileMetaData.totalChunks ? Math.round(fileMetaData.chunkIndex / fileMetaData.totalChunks * 100) : 100;
                            that._onFileProgress({ target: $(fileEntry, that.wrapper) }, percentComplete);
                        }
                    }
                }
            },
            _hideUploadProgress: function (fileEntry) {
                $('.k-progress', fileEntry).delay(PROGRESSHIDEDELAY).fadeOut(PROGRESSHIDEDURATION, function () {
                    $(this).css('width', '0%');
                });
            },
            _showUploadButton: function () {
                var that = this;
                var uploadButton = $('.k-upload-selected', that.wrapper);
                var clearButton = $('.k-clear-selected', that.wrapper);
                if (uploadButton.length === 0) {
                    uploadButton = that._renderAction('', this.localization.uploadSelectedFiles).addClass('k-upload-selected');
                    clearButton = that._renderAction('', this.localization.clearSelectedFiles).addClass('k-clear-selected');
                }
                this.wrapper.append(clearButton, uploadButton);
            },
            _hideUploadButton: function () {
                $('.k-upload-selected, .k-clear-selected', this.wrapper).remove();
            },
            _showHeaderUploadStatus: function (isUploading) {
                var that = this;
                var localization = that.localization;
                var dropZone = $('.k-dropzone', that.wrapper);
                var headerUploadStatus = $('.k-upload-status-total', that.wrapper);
                if (headerUploadStatus.length !== 0) {
                    headerUploadStatus.remove();
                }
                headerUploadStatus = '<strong class="k-upload-status k-upload-status-total"><span class="k-icon"></span></strong>';
                if (isUploading) {
                    headerUploadStatus = $(headerUploadStatus).append(localization.headerStatusUploading);
                    headerUploadStatus.find('.k-icon').addClass(headerStatusIcon.loading);
                } else {
                    headerUploadStatus = $(headerUploadStatus).append(localization.headerStatusUploaded);
                    headerUploadStatus.find('.k-icon').addClass(headerStatusIcon.warning);
                }
                if (dropZone.length > 0) {
                    dropZone.append(headerUploadStatus);
                } else {
                    $('.k-upload-button', that.wrapper).after(headerUploadStatus);
                }
            },
            _updateHeaderUploadStatus: function () {
                var that = this;
                var headerUploadStatus = $('.k-upload-status-total', this.wrapper);
                var currentlyUploading = $('.k-file', that.wrapper).not('.k-file-success, .k-file-error, .k-file-invalid');
                var currentlyInvalid = $('.k-file-invalid', that.wrapper);
                var currentlyFailed = $('.k-file-error', that.wrapper);
                var currentlyPaused = $('.k-file', that.wrapper).find('.k-i-play-sm');
                var failedUploads, headerUploadStatusIcon;
                if (currentlyPaused.length && (currentlyPaused.length === currentlyUploading.length || !that.options.async.concurrent)) {
                    headerUploadStatusIcon = $('.k-icon', headerUploadStatus).removeClass().addClass('k-icon').addClass('k-i-pause-sm');
                    headerUploadStatus.html(headerUploadStatusIcon).append(that.localization.headerStatusPaused);
                } else if (currentlyUploading.length === 0 || currentlyInvalid.length > 0 || currentlyFailed.length > 0) {
                    failedUploads = $('.k-file.k-file-error, .k-file.k-file-invalid', that.wrapper);
                    headerUploadStatus = $('.k-upload-status-total', that.wrapper);
                    headerUploadStatusIcon = $('.k-icon', headerUploadStatus).removeClass().addClass('k-icon').addClass(failedUploads.length !== 0 ? headerStatusIcon.warning : headerStatusIcon.success);
                    headerUploadStatus.html(headerUploadStatusIcon).append(that.localization.headerStatusUploaded);
                }
            },
            _hideHeaderUploadstatus: function () {
                $('.k-upload-status-total', this.wrapper).remove();
            },
            _onParentFormSubmit: function () {
                var upload = this, element = upload.element;
                if (typeof this._module.onAbort !== 'undefined') {
                    this._module.onAbort();
                }
                if (!element.value) {
                    var input = $(element);
                    input.attr('disabled', 'disabled');
                    window.setTimeout(function () {
                        input.removeAttr('disabled');
                    }, 0);
                }
            },
            _onParentFormReset: function () {
                $('.k-upload-files', this.wrapper).remove();
            },
            _supportsFormData: function () {
                return typeof FormData != 'undefined';
            },
            _supportsMultiple: function () {
                var windows = this._userAgent().indexOf('Windows') > -1;
                return !kendo.support.browser.opera && !(kendo.support.browser.safari && windows);
            },
            _supportsDrop: function () {
                var userAgent = this._userAgent().toLowerCase();
                var isChrome = /chrome/.test(userAgent);
                var isSafari = !isChrome && /safari/.test(userAgent);
                var isWindowsSafari = isSafari && /windows/.test(userAgent);
                return !isWindowsSafari && this._supportsFormData() && this.options.async.saveUrl;
            },
            _userAgent: function () {
                return navigator.userAgent;
            },
            _setupDropZone: function () {
                var that = this;
                $('.k-upload-button', that.wrapper).wrap('<div class=\'k-dropzone\'></div>');
                var ns = that._ns;
                var dropZone = $('.k-dropzone', that.wrapper).append($('<em>' + that.localization.dropFilesHere + '</em>')).on('dragenter' + ns, stopEvent).on('dragover' + ns, function (e) {
                    e.preventDefault();
                }).on('drop' + ns, $.proxy(that._onDrop, that));
                bindDragEventWrappers(dropZone, ns, function () {
                    if (!dropZone.closest('.k-upload').hasClass('k-state-disabled')) {
                        dropZone.addClass('k-dropzone-hovered');
                    }
                }, function () {
                    dropZone.removeClass('k-dropzone-hovered');
                });
                that._bindDocumentDragEventWrappers(dropZone);
            },
            _setupCustomDropZone: function () {
                var that = this;
                var dropZone = $(that.options.dropZone);
                $('.k-upload-button', that.wrapper).wrap('<div class=\'k-dropzone\'></div>');
                var ns = that._ns;
                dropZone.on('dragenter' + ns, stopEvent).on('dragover' + ns, function (e) {
                    e.preventDefault();
                }).on('drop' + ns, $.proxy(that._onDrop, that));
                bindDragEventWrappers(dropZone, ns, function (e) {
                    if (!that.wrapper.hasClass('k-state-disabled')) {
                        dropZone.removeClass('k-dropzone-hovered');
                        $(e.target).addClass('k-dropzone-hovered');
                    }
                }, function () {
                    dropZone.removeClass('k-dropzone-hovered');
                });
                that._bindDocumentDragEventWrappers(dropZone);
            },
            _bindDocumentDragEventWrappers: function (dropZone) {
                var that = this;
                var ns = that._ns;
                bindDragEventWrappers($(document), ns, function () {
                    if (!that.wrapper.hasClass('k-state-disabled')) {
                        dropZone.addClass('k-dropzone-active');
                        dropZone.closest('.k-upload').removeClass('k-upload-empty');
                    }
                }, function () {
                    dropZone.removeClass('k-dropzone-active');
                    if ($('li.k-file', dropZone.closest('.k-upload')).length === 0) {
                        dropZone.closest('.k-upload').addClass('k-upload-empty');
                    }
                });
            },
            _supportsRemove: function () {
                return !!this.options.async.removeUrl;
            },
            _submitRemove: function (fileNames, eventArgs, onSuccess, onError) {
                var upload = this, removeField = upload.options.async.removeField || 'fileNames', params = $.extend(eventArgs.data, antiForgeryTokens());
                params[removeField] = fileNames;
                jQuery.ajax({
                    type: this.options.async.removeVerb,
                    dataType: 'json',
                    dataFilter: normalizeJSON,
                    url: this.options.async.removeUrl,
                    traditional: true,
                    data: params,
                    headers: eventArgs.headers,
                    success: onSuccess,
                    error: onError,
                    xhrFields: { withCredentials: this.options.async.withCredentials }
                });
            },
            _wrapInput: function (input) {
                var that = this;
                var options = that.options;
                input.wrap('<div class=\'k-widget k-upload k-header\'><div class=\'k-button k-upload-button\' aria-label=\'' + this.localization.select + '\'></div></div>');
                if (!options.async.saveUrl) {
                    input.closest('.k-upload').addClass('k-upload-sync');
                }
                input.closest('.k-upload').addClass('k-upload-empty');
                input.closest('.k-button').append('<span>' + this.localization.select + '</span>');
                return input.closest('.k-upload');
            },
            _checkAllComplete: function () {
                if ($('.k-file.k-file-progress', this.wrapper).length === 0) {
                    this.trigger(COMPLETE);
                }
            },
            _inputFiles: function (sourceInput) {
                return inputFiles(sourceInput);
            }
        });
        var syncUploadModule = function (upload) {
            this.name = 'syncUploadModule';
            this.element = upload.wrapper;
            this.upload = upload;
            this.element.closest('form').attr('enctype', 'multipart/form-data').attr('encoding', 'multipart/form-data');
        };
        syncUploadModule.prototype = {
            onSelect: function (e, files) {
                var upload = this.upload;
                var sourceInput = $(e.target);
                var filesContainErrors = upload._filesContainValidationErrors(files);
                upload._addInput(sourceInput);
                var fileData = { 'fileNames': files };
                if (filesContainErrors) {
                    sourceInput.remove();
                } else {
                    fileData.relatedInput = sourceInput;
                }
                var file = upload._enqueueFile(getFileName(sourceInput), fileData);
                if (filesContainErrors) {
                    upload._hideUploadProgress(file);
                }
                upload._fileAction(file, REMOVE);
            },
            onRemove: function (e) {
                var fileEntry = getFileEntry(e);
                var relatedInput = fileEntry.data('relatedInput');
                if (relatedInput) {
                    relatedInput.remove();
                }
                this.upload._removeFileEntry(fileEntry);
            }
        };
        var iframeUploadModule = function (upload) {
            this.name = 'iframeUploadModule';
            this.element = upload.wrapper;
            this.upload = upload;
            this.iframes = [];
        };
        Upload._frameId = 0;
        iframeUploadModule.prototype = {
            onSelect: function (e, files) {
                var upload = this.upload;
                var sourceInput = $(e.target);
                var hasValidationErrors = upload._filesContainValidationErrors(files);
                var fileEntry = this.prepareUpload(sourceInput, files, hasValidationErrors);
                if (upload.options.async.autoUpload) {
                    if (!hasValidationErrors) {
                        this.performUpload(fileEntry);
                    } else {
                        upload._fileAction(fileEntry, REMOVE);
                        upload._showHeaderUploadStatus(false);
                    }
                } else {
                    upload._fileAction(fileEntry, REMOVE);
                    if (!hasValidationErrors) {
                        upload._showUploadButton();
                    } else {
                        upload._updateHeaderUploadStatus();
                    }
                }
                if (hasValidationErrors) {
                    upload._hideUploadProgress(fileEntry);
                }
            },
            prepareUpload: function (sourceInput, files, hasValidationErrors) {
                var upload = this.upload;
                var activeInput = $(upload.element);
                var name = upload.options.async.saveField || sourceInput.attr('name');
                var fileEntry, fileData, iframe, form;
                upload._addInput(sourceInput);
                sourceInput.attr('name', name);
                if (!hasValidationErrors) {
                    iframe = this.createFrame(upload.name + '_' + Upload._frameId++);
                    this.registerFrame(iframe);
                    form = this.createForm(upload.options.async.saveUrl, iframe.attr('name')).append(activeInput);
                    fileData = {
                        'frame': iframe,
                        'relatedInput': activeInput,
                        'fileNames': files
                    };
                } else {
                    sourceInput.remove();
                    fileData = { 'fileNames': files };
                }
                fileEntry = upload._enqueueFile(getFileName(sourceInput), fileData);
                if (iframe) {
                    iframe.data({
                        'form': form,
                        'file': fileEntry
                    });
                }
                return fileEntry;
            },
            performUpload: function (fileEntry) {
                var e = { files: fileEntry.data('fileNames') };
                var iframe = fileEntry.data('frame');
                var upload = this.upload;
                if (!upload.trigger(UPLOAD, e)) {
                    upload._hideUploadButton();
                    upload._showHeaderUploadStatus(true);
                    iframe.appendTo(document.body);
                    var form = iframe.data('form').attr('action', upload.options.async.saveUrl).appendTo(document.body);
                    e.data = $.extend({}, e.data, antiForgeryTokens());
                    for (var key in e.data) {
                        var dataInput = form.find('input[name=\'' + key + '\']');
                        if (dataInput.length === 0) {
                            dataInput = $('<input>', {
                                type: 'hidden',
                                name: key
                            }).prependTo(form);
                        }
                        dataInput.val(e.data[key]);
                    }
                    upload._fileAction(fileEntry, CANCEL);
                    upload._fileState(fileEntry, 'uploading');
                    $(fileEntry).removeClass('k-file-error').addClass('k-file-progress');
                    iframe.one('load', $.proxy(this.onIframeLoad, this));
                    form[0].submit();
                } else {
                    upload._removeFileEntry(iframe.data('file'));
                    this.cleanupFrame(iframe);
                    this.unregisterFrame(iframe);
                }
            },
            onSaveSelected: function () {
                var module = this;
                var upload = module.upload;
                $('.k-file', this.element).each(function () {
                    var fileEntry = $(this);
                    var started = isFileUploadStarted(fileEntry);
                    var hasValidationErrors = upload._filesContainValidationErrors(fileEntry.data('fileNames'));
                    if (!started && !hasValidationErrors) {
                        module.performUpload(fileEntry);
                    }
                });
            },
            onIframeLoad: function (e) {
                var iframe = $(e.target), responseText;
                try {
                    responseText = iframe.contents().text();
                } catch (ex) {
                    responseText = 'Error trying to get server response: ' + ex;
                }
                this.processResponse(iframe, responseText);
            },
            processResponse: function (iframe, responseText) {
                var fileEntry = iframe.data('file'), module = this, fakeXHR = { responseText: responseText };
                tryParseJSON(responseText, function (jsonResult) {
                    $.extend(fakeXHR, {
                        statusText: 'OK',
                        status: '200'
                    });
                    module.upload._onFileProgress({ target: $(fileEntry, module.upload.wrapper) }, 100);
                    module.upload._onUploadSuccess({ target: $(fileEntry, module.upload.wrapper) }, jsonResult, fakeXHR);
                    module.cleanupFrame(iframe);
                    module.unregisterFrame(iframe);
                }, function () {
                    $.extend(fakeXHR, {
                        statusText: 'error',
                        status: '500'
                    });
                    module.upload._onUploadError({ target: $(fileEntry, module.upload.wrapper) }, fakeXHR);
                });
            },
            onCancel: function (e) {
                var iframe = $(e.target).data('frame');
                this.stopFrameSubmit(iframe);
                this.cleanupFrame(iframe);
                this.unregisterFrame(iframe);
                this.upload._removeFileEntry(iframe.data('file'));
            },
            onRetry: function (e) {
                var fileEntry = getFileEntry(e);
                this.performUpload(fileEntry);
            },
            onRemove: function (e, eventArgs, shouldSendRemoveRequest) {
                var module = this;
                var upload = module.upload;
                var fileEntry = getFileEntry(e);
                var iframe = fileEntry.data('frame');
                if (iframe) {
                    module.unregisterFrame(iframe);
                    upload._removeFileEntry(fileEntry);
                    module.cleanupFrame(iframe);
                } else {
                    if (fileEntry.hasClass('k-file-success')) {
                        removeUploadedFile(fileEntry, upload, eventArgs, shouldSendRemoveRequest);
                    } else {
                        upload._removeFileEntry(fileEntry);
                    }
                }
            },
            onAbort: function () {
                var element = this.element, module = this;
                $.each(this.iframes, function () {
                    $('input', this.data('form')).appendTo(element);
                    module.stopFrameSubmit(this[0]);
                    this.data('form').remove();
                    this.remove();
                });
                this.iframes = [];
            },
            createFrame: function (id) {
                return $('<iframe' + ' name=\'' + id + '\'' + ' id=\'' + id + '\'' + ' style=\'display:none;\' />');
            },
            createForm: function (action, target) {
                return $('<form enctype=\'multipart/form-data\' method=\'POST\'' + ' action=\'' + action + '\'' + ' target=\'' + target + '\'' + '/>');
            },
            stopFrameSubmit: function (frame) {
                if (typeof frame.stop != 'undefined') {
                    frame.stop();
                } else if (frame.document) {
                    frame.document.execCommand('Stop');
                }
            },
            registerFrame: function (frame) {
                this.iframes.push(frame);
            },
            unregisterFrame: function (frame) {
                this.iframes = $.grep(this.iframes, function (value) {
                    return value.attr('name') != frame.attr('name');
                });
            },
            cleanupFrame: function (frame) {
                var form = frame.data('form');
                frame.data('file').data('frame', null);
                setTimeout(function () {
                    form.remove();
                    frame.remove();
                }, 1);
            }
        };
        var formDataUploadModule = function (upload) {
            this.name = 'formDataUploadModule';
            this.element = upload.wrapper;
            this.upload = upload;
            this.position = {};
            this.metaData = {};
            this.cancelled = {};
            this.resume = {};
            this.paused = {};
            this.retries = {};
        };
        formDataUploadModule.prototype = {
            onSelect: function (e, files) {
                var upload = this.upload;
                var module = this;
                var sourceElement = $(e.target);
                var fileEntries = this.prepareUpload(sourceElement, files);
                var hasValidationErrors;
                var prev;
                $.each(fileEntries, function (index) {
                    hasValidationErrors = upload._filesContainValidationErrors($(this.data('fileNames')));
                    if (upload.options.async.autoUpload) {
                        if (!hasValidationErrors) {
                            if (upload.options.async.chunkSize) {
                                module.prepareChunk(this);
                                prev = this.prev();
                                if (upload.options.async.concurrent || index === 0 && !prev.length || index === 0 && prev.hasClass('k-file-success')) {
                                    module.performUpload(this);
                                }
                            } else {
                                module.performUpload(this);
                            }
                        } else {
                            upload._fileAction(this, REMOVE);
                            upload._showHeaderUploadStatus(false);
                        }
                    } else {
                        upload._fileAction(this, REMOVE);
                        if (!hasValidationErrors) {
                            upload._showUploadButton();
                            this.addClass('k-toupload');
                        } else {
                            upload._updateHeaderUploadStatus();
                        }
                    }
                    if (hasValidationErrors) {
                        upload._hideUploadProgress(this);
                    }
                });
            },
            prepareUpload: function (sourceElement, files) {
                var fileEntries = this.enqueueFiles(files);
                if (sourceElement.is('input')) {
                    $.each(fileEntries, function () {
                        $(this).data('relatedInput', sourceElement);
                    });
                    sourceElement.data('relatedFileEntries', fileEntries);
                    this.upload._addInput(sourceElement);
                }
                return fileEntries;
            },
            enqueueFiles: function (files) {
                var upload = this.upload;
                var name;
                var i;
                var filesLength = files.length;
                var currentFile;
                var fileEntry;
                var fileEntries = [];
                if (upload.options.async.batch === true) {
                    name = $.map(files, function (file) {
                        return file.name;
                    }).join(', ');
                    if (upload.directory || upload.options.directoryDrop) {
                        $(files).each(function () {
                            if (this.rawFile.webkitRelativePath || this.rawFile.relativePath) {
                                this.name = this.rawFile.webkitRelativePath || this.rawFile.relativePath;
                            }
                        });
                    }
                    fileEntry = upload._enqueueFile(name, { fileNames: files });
                    fileEntry.data('files', files);
                    fileEntries.push(fileEntry);
                } else {
                    for (i = 0; i < filesLength; i++) {
                        currentFile = files[i];
                        name = currentFile.name;
                        if (upload.directory || upload.options.directoryDrop) {
                            if (currentFile.rawFile.webkitRelativePath || currentFile.rawFile.relativePath) {
                                currentFile.name = currentFile.rawFile.webkitRelativePath || currentFile.rawFile.relativePath;
                            }
                        }
                        fileEntry = upload._enqueueFile(name, { fileNames: [currentFile] });
                        fileEntry.data('files', [currentFile]);
                        fileEntries.push(fileEntry);
                    }
                }
                return fileEntries;
            },
            performUpload: function (fileEntry) {
                var upload = this.upload, formData = this.createFormData(), xhr = this.createXHR(), e = {
                        files: fileEntry.data('fileNames'),
                        XMLHttpRequest: xhr
                    }, files;
                if (!upload.trigger(UPLOAD, e)) {
                    if (fileEntry.find('.k-i-cancel').length === 0) {
                        if (upload.options.async.chunkSize) {
                            upload._fileAction(fileEntry, PAUSE);
                        }
                        upload._fileAction(fileEntry, CANCEL, upload.options.async.chunkSize);
                    }
                    if (!upload.wrapper.find('.k-toupload').length) {
                        upload._hideUploadButton();
                    }
                    upload._showHeaderUploadStatus(true);
                    if (e.formData) {
                        formData = e.formData;
                    } else {
                        e.data = $.extend({}, e.data, antiForgeryTokens());
                        for (var key in e.data) {
                            formData.append(key, e.data[key]);
                        }
                        files = fileEntry.data('files');
                        if (files) {
                            this.populateFormData(formData, files);
                        }
                    }
                    upload._fileState(fileEntry, 'uploading');
                    $(fileEntry).removeClass('k-file-error').addClass('k-file-progress');
                    if (upload.options.async.useArrayBuffer && window.FileReader) {
                        this._readFile(upload.options.async.saveUrl, formData, fileEntry, xhr);
                    } else {
                        this.postFormData(upload.options.async.saveUrl, formData, fileEntry, xhr);
                    }
                } else {
                    this.removeFileEntry(fileEntry);
                }
            },
            _readFile: function (saveUrl, formData, fileEntry, xhr) {
                var that = this;
                var upload = that.upload;
                var file = fileEntry.data('files')[0];
                var reader = new FileReader();
                reader.onload = function (e) {
                    try {
                        if (!that.fileArrayBuffer) {
                            that.fileArrayBuffer = e.target.result;
                        } else {
                            that.fileArrayBuffer = that._appendBuffer(that.fileArrayBuffer, e.target.result);
                        }
                    } catch (err) {
                        upload._onUploadError({ target: $(fileEntry, upload.wrapper) }, xhr);
                        return;
                    }
                    if (that.position[file.uid] > file.size) {
                        that.postFormData(upload.options.async.saveUrl, that.fileArrayBuffer, fileEntry, xhr);
                        that.fileArrayBuffer = null;
                    } else {
                        that._readFile(saveUrl, formData, fileEntry, xhr);
                    }
                };
                reader.onerror = function () {
                    upload._onUploadError({ target: $(fileEntry, upload.wrapper) }, xhr);
                };
                reader.readAsArrayBuffer(that._getCurrentChunk(file.rawFile, file.uid));
            },
            _appendBuffer: function (buffer1, buffer2) {
                var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
                tmp.set(new Uint8Array(buffer1), 0);
                tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
                return tmp.buffer;
            },
            onSaveSelected: function () {
                var module = this;
                var upload = module.upload;
                $('.k-toupload', this.element).filter(function () {
                    var fileEntry = $(this);
                    var started = isFileUploadStarted(fileEntry);
                    var hasValidationErrors = upload._filesContainValidationErrors(fileEntry.data('fileNames'));
                    return !started && !hasValidationErrors;
                }).each(function (index) {
                    var fileEntry = $(this);
                    var prevEntry = fileEntry.prev();
                    fileEntry.removeClass('k-toupload');
                    if (upload.options.async.chunkSize) {
                        module.prepareChunk(fileEntry);
                        if (upload.options.async.concurrent || index === 0 && !prevEntry.length || (index === 0 && prevEntry.hasClass('k-file-success') || prevEntry.hasClass('k-file-error'))) {
                            module.performUpload(fileEntry);
                        }
                    } else {
                        module.performUpload(fileEntry);
                    }
                });
            },
            onCancel: function (e) {
                var fileEntry = getFileEntry(e);
                if (this.upload.options.async.chunkSize) {
                    this.cancelled[fileEntry.data('uid')] = true;
                }
                this.stopUploadRequest(fileEntry);
                this.removeFileEntry(fileEntry);
            },
            onPause: function (e) {
                var fileEntry = getFileEntry(e);
                var fileUid = fileEntry.data('uid');
                var async = this.upload.options.async;
                if (async.chunkSize) {
                    this.retries[fileUid] = async.maxAutoRetries + 1;
                    this.paused[fileUid] = true;
                    this.resume[fileUid] = false;
                }
            },
            onResume: function (e) {
                var fileEntry = getFileEntry(e);
                var fileUid = fileEntry.data('uid');
                if (this.upload.options.async.chunkSize) {
                    delete this.paused[fileUid];
                    this.resume[fileUid] = true;
                    this.retries[fileEntry.data('uid')] = 1;
                    this._increaseChunkIndex(fileUid);
                    this.performUpload(fileEntry);
                }
            },
            onRetry: function (e) {
                var fileEntry = getFileEntry(e);
                var async = this.upload.options.async;
                if (async.chunkSize) {
                    this.retries[fileEntry.data('uid')] = async.maxAutoRetries + 1;
                    delete this.paused[fileEntry.data('uid')];
                }
                this.performUpload(fileEntry);
            },
            onRemove: function (e, eventArgs, shouldSendRemoveRequest) {
                var module = this;
                var upload = module.upload;
                var fileEntry = getFileEntry(e);
                var async = this.upload.options.async;
                if (async.chunkSize) {
                    this.retries[fileEntry.data('uid')] = async.maxAutoRetries + 1;
                }
                if (fileEntry.hasClass('k-file-success')) {
                    removeUploadedFile(fileEntry, upload, eventArgs, shouldSendRemoveRequest);
                } else {
                    module.removeFileEntry(fileEntry);
                }
            },
            createXHR: function () {
                return new XMLHttpRequest();
            },
            postFormData: function (url, data, fileEntry, xhr) {
                var module = this;
                fileEntry.data('request', xhr);
                xhr.addEventListener('load', function (e) {
                    module.onRequestSuccess.call(module, e, fileEntry);
                }, false);
                xhr.addEventListener(ERROR, function (e) {
                    module.onRequestError.call(module, e, fileEntry);
                }, false);
                xhr.upload.addEventListener('progress', function (e) {
                    module.onRequestProgress.call(module, e, fileEntry);
                }, false);
                xhr.open('POST', url, true);
                xhr.withCredentials = this.upload.options.async.withCredentials;
                var accept = this.upload.options.async.accept;
                if (accept) {
                    xhr.setRequestHeader('Accept', accept);
                }
                xhr.send(data);
            },
            createFormData: function () {
                return new FormData();
            },
            populateFormData: function (data, files) {
                var chunk;
                var i;
                var length = files.length;
                var uid;
                var upload = this.upload;
                if (upload.options.async.chunkSize) {
                    uid = files[0].uid;
                    chunk = this._getCurrentChunk(files[0].rawFile, uid);
                    data.append(upload.options.async.saveField || upload.name, chunk);
                    var serializedMetaData = JSON.stringify(this.metaData[uid]);
                    data.append('metadata', serializedMetaData);
                } else {
                    for (i = 0; i < length; i++) {
                        data.append(upload.options.async.saveField || upload.name, files[i].rawFile);
                    }
                }
                return data;
            },
            onRequestSuccess: function (e, fileEntry) {
                var xhr = e.target, module = this;
                function raiseError() {
                    module.upload._onUploadError({ target: $(fileEntry, module.upload.wrapper) }, xhr);
                }
                function parseSuccess(jsonResult) {
                    var batch = module.upload.options.async.batch;
                    var chunkSize = module.upload.options.async.chunkSize;
                    var concurrent = module.upload.options.async.concurrent;
                    var fileUid = jsonResult.fileUid;
                    if (module.paused[fileUid] || module.cancelled[fileUid]) {
                        return;
                    }
                    delete module.retries[fileUid];
                    if (chunkSize && !batch && !jsonResult.uploaded) {
                        module._increaseChunkIndex(fileUid);
                        module.performUpload(fileEntry);
                    } else if (chunkSize && !batch && !concurrent && fileEntry.next().length && !fileEntry.next().hasClass('k-toupload')) {
                        module.upload._onFileProgress({ target: $(fileEntry, module.upload.wrapper) }, 100);
                        module._resetChunkIndex(fileUid);
                        module.upload._onUploadSuccess({ target: $(fileEntry, module.upload.wrapper) }, jsonResult, xhr);
                        module.performUpload(fileEntry.next());
                    } else {
                        module.upload._onFileProgress({ target: $(fileEntry, module.upload.wrapper) }, 100);
                        module.upload._onUploadSuccess({ target: $(fileEntry, module.upload.wrapper) }, jsonResult, xhr);
                        module.cleanupFileEntry(fileEntry);
                    }
                }
                if (xhr.status >= 200 && xhr.status <= 299) {
                    tryParseJSON(xhr.responseText, parseSuccess, raiseError);
                } else {
                    raiseError();
                }
            },
            onRequestError: function (e, fileEntry) {
                var xhr = e.target;
                this.upload._onUploadError({ target: $(fileEntry, this.upload.wrapper) }, xhr);
            },
            cleanupFileEntry: function (fileEntry) {
                var relatedInput = fileEntry.data('relatedInput'), uploadComplete = true;
                if (relatedInput) {
                    $.each(relatedInput.data('relatedFileEntries') || [], function () {
                        if (this.parent().length > 0 && this[0] != fileEntry[0]) {
                            uploadComplete = uploadComplete && this.hasClass('k-file-success');
                        }
                    });
                    if (uploadComplete) {
                        relatedInput.remove();
                    }
                }
            },
            removeFileEntry: function (fileEntry) {
                var chunkSize = this.upload.options.async.chunkSize;
                var concurrent = this.upload.options.async.concurrent;
                this.cleanupFileEntry(fileEntry);
                if (chunkSize && !concurrent) {
                    if (fileEntry.next().length) {
                        this.performUpload(fileEntry.next());
                    }
                }
                this.upload._removeFileEntry(fileEntry);
            },
            onRequestProgress: function (e, fileEntry) {
                var percentComplete = Math.round(e.loaded * 100 / e.total);
                var fileUid = fileEntry.data('uid');
                var fileMetaData;
                if (this.upload.options.async.chunkSize) {
                    fileMetaData = this.metaData[fileUid];
                    percentComplete = fileMetaData.totalChunks ? Math.round(fileMetaData.chunkIndex / fileMetaData.totalChunks * 100) : 100;
                }
                this.upload._onFileProgress({ target: $(fileEntry, this.upload.wrapper) }, percentComplete);
            },
            stopUploadRequest: function (fileEntry) {
                fileEntry.data('request').abort();
            },
            prepareChunk: function (fileEntry) {
                var file = fileEntry.data('files')[0].rawFile;
                var uid = fileEntry.data('files')[0].uid;
                var chunkSize = this.upload.options.async.chunkSize;
                this.position[uid] = 0;
                this.metaData[uid] = {
                    chunkIndex: 0,
                    contentType: file.type,
                    fileName: file.name,
                    totalFileSize: file.size,
                    totalChunks: Math.ceil(file.size / chunkSize),
                    uploadUid: uid
                };
            },
            _decreaseChunkIndex: function (uid) {
                this.metaData[uid].chunkIndex--;
            },
            _increaseChunkIndex: function (uid) {
                this.metaData[uid].chunkIndex++;
            },
            _resetChunkIndex: function (uid) {
                this.metaData[uid].chunkIndex = 0;
            },
            _decreasePosition: function (uid) {
                this.position[uid] -= this.upload.options.async.chunkSize;
            },
            _getCurrentChunk: function (file, uid) {
                var oldPosition = this.position[uid];
                var methodToInvoke;
                var async = this.upload.options.async;
                var chunkSize = async.chunkSize || async.bufferChunkSize;
                if (!this.position[uid]) {
                    this.position[uid] = 0;
                }
                this.position[uid] += chunkSize;
                if (!!(methodToInvoke = this._getChunker(file))) {
                    return file[methodToInvoke](oldPosition, this.position[uid]);
                } else {
                    return file;
                }
            },
            _getChunker: function (file) {
                if (file.slice) {
                    return 'slice';
                } else if (file.mozSlice) {
                    return 'mozSlice';
                } else if (file.webkitSlice) {
                    return 'webkitSlice';
                } else {
                    return null;
                }
            }
        };
        function getFileName(input) {
            return $.map(inputFiles(input), function (file) {
                return file.name;
            }).join(', ');
        }
        function inputFiles($input) {
            var input = $input[0];
            if (input.files) {
                return getAllFileInfo(input.files);
            } else {
                return [{
                        name: stripPath(input.value),
                        extension: getFileExtension(input.value),
                        size: null
                    }];
            }
        }
        function getAllFileInfo(rawFiles) {
            return $.map(rawFiles, function (file) {
                return getFileInfo(file);
            });
        }
        function getFileInfo(rawFile) {
            var fileName = rawFile.name || rawFile.fileName;
            return {
                name: kendo.htmlEncode(fileName),
                extension: getFileExtension(fileName),
                size: typeof rawFile.size == 'number' ? rawFile.size : rawFile.fileSize,
                rawFile: rawFile
            };
        }
        function getFileExtension(fileName) {
            var matches = fileName.match(rFileExtension);
            return matches ? matches[0] : '';
        }
        function stripPath(name) {
            var slashIndex = name.lastIndexOf('\\');
            return slashIndex != -1 ? name.substr(slashIndex + 1) : name;
        }
        function assignGuidToFiles(files, unique) {
            var uid = kendo.guid();
            return $.map(files, function (file) {
                file.uid = unique ? kendo.guid() : uid;
                return file;
            });
        }
        function validateFiles(files, validationInfo) {
            var allowedExtensions = parseAllowedExtensions(validationInfo.allowedExtensions);
            var maxFileSize = validationInfo.maxFileSize;
            var minFileSize = validationInfo.minFileSize;
            for (var i = 0; i < files.length; i++) {
                validateFileExtension(files[i], allowedExtensions);
                validateFileSize(files[i], minFileSize, maxFileSize);
            }
        }
        function parseAllowedExtensions(extensions) {
            var allowedExtensions = $.map(extensions, function (ext) {
                var parsedExt = ext.substring(0, 1) === '.' ? ext : '.' + ext;
                return parsedExt.toLowerCase();
            });
            return allowedExtensions;
        }
        function validateFileExtension(file, allowedExtensions) {
            if (allowedExtensions.length > 0) {
                if (allowedExtensions.indexOf(file.extension.toLowerCase()) < 0) {
                    file.validationErrors = file.validationErrors || [];
                    if ($.inArray(INVALIDFILEEXTENSION, file.validationErrors) === -1) {
                        file.validationErrors.push(INVALIDFILEEXTENSION);
                    }
                }
            }
        }
        function validateFileSize(file, minFileSize, maxFileSize) {
            if (minFileSize !== 0 && file.size < minFileSize) {
                file.validationErrors = file.validationErrors || [];
                if ($.inArray(INVALIDMINFILESIZE, file.validationErrors) === -1) {
                    file.validationErrors.push(INVALIDMINFILESIZE);
                }
            }
            if (maxFileSize !== 0 && file.size > maxFileSize) {
                file.validationErrors = file.validationErrors || [];
                if ($.inArray(INVALIDMAXFILESIZE, file.validationErrors) === -1) {
                    file.validationErrors.push(INVALIDMAXFILESIZE);
                }
            }
        }
        function getTotalFilesSizeMessage(files) {
            var totalSize = 0;
            if (typeof files[0].size == 'number') {
                for (var i = 0; i < files.length; i++) {
                    if (files[i].size) {
                        totalSize += files[i].size;
                    }
                }
            } else {
                return '';
            }
            totalSize /= 1024;
            if (totalSize < 1024) {
                return totalSize.toFixed(2) + ' KB';
            } else {
                return (totalSize / 1024).toFixed(2) + ' MB';
            }
        }
        function shouldRemoveFileEntry(upload) {
            return !upload.multiple && $('.k-file', upload.wrapper).length > 1;
        }
        function removeUploadedFile(fileEntry, upload, eventArgs, shouldSendRemoveRequest) {
            if (!upload._supportsRemove()) {
                if (shouldRemoveFileEntry(upload) || !shouldSendRemoveRequest) {
                    upload._removeFileEntry(fileEntry);
                }
                return;
            }
            var files = fileEntry.data('fileNames');
            var fileNames = $.map(files, function (file) {
                return file.name;
            });
            if (shouldSendRemoveRequest === false) {
                upload._removeFileEntry(fileEntry);
                return;
            }
            upload._submitRemove(fileNames, eventArgs, function onSuccess(data, textStatus, xhr) {
                var prevented = upload.trigger(SUCCESS, {
                    operation: 'remove',
                    files: files,
                    response: data,
                    XMLHttpRequest: xhr
                });
                if (!prevented) {
                    upload._removeFileEntry(fileEntry);
                }
            }, function onError(xhr) {
                if (shouldRemoveFileEntry(upload)) {
                    upload._removeFileEntry(fileEntry);
                }
                upload.trigger(ERROR, {
                    operation: 'remove',
                    files: files,
                    XMLHttpRequest: xhr
                });
                logToConsole('Server response: ' + xhr.responseText);
            });
        }
        function tryParseJSON(input, onSuccess, onError) {
            var success = false, json = '';
            try {
                json = $.parseJSON(normalizeJSON(input));
                success = true;
            } catch (e) {
                onError();
            }
            if (success) {
                onSuccess(json);
            }
        }
        function normalizeJSON(input) {
            if (typeof input === 'undefined' || input === '') {
                input = '{}';
            }
            return input;
        }
        function stopEvent(e) {
            e.stopPropagation();
            e.preventDefault();
        }
        function bindDragEventWrappers(element, namespace, onDragEnter, onDragLeave) {
            var hideInterval, lastDrag;
            element.on('dragenter' + namespace, function (e) {
                onDragEnter(e);
                lastDrag = new Date();
                if (!hideInterval) {
                    hideInterval = setInterval(function () {
                        var sinceLastDrag = new Date() - lastDrag;
                        if (sinceLastDrag > 100) {
                            onDragLeave();
                            clearInterval(hideInterval);
                            hideInterval = null;
                        }
                    }, 100);
                }
            }).on('dragover' + namespace, function () {
                lastDrag = new Date();
            });
        }
        function isFileUploadStarted(fileEntry) {
            return fileEntry.is('.k-file-progress, .k-file-success, .k-file-error');
        }
        function getFileEntry(e) {
            return $(e.target).closest('.k-file');
        }
        kendo.ui.plugin(Upload);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.filebrowser', [
        'kendo.listview',
        'kendo.dropdownlist',
        'kendo.upload'
    ], f);
}(function () {
    var __meta__ = {
        id: 'filebrowser',
        name: 'FileBrowser',
        category: 'web',
        description: '',
        hidden: true,
        depends: [
            'selectable',
            'listview',
            'dropdownlist',
            'upload'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, isPlainObject = $.isPlainObject, proxy = $.proxy, extend = $.extend, placeholderSupported = kendo.support.placeholder, browser = kendo.support.browser, isFunction = kendo.isFunction, trimSlashesRegExp = /(^\/|\/$)/g, CHANGE = 'change', APPLY = 'apply', ERROR = 'error', CLICK = 'click', NS = '.kendoFileBrowser', BREADCRUBMSNS = '.kendoBreadcrumbs', SEARCHBOXNS = '.kendoSearchBox', NAMEFIELD = 'name', SIZEFIELD = 'size', TYPEFIELD = 'type', DEFAULTSORTORDER = {
                field: TYPEFIELD,
                dir: 'asc'
            }, EMPTYTILE = kendo.template('<li class="k-tile-empty"><strong>${text}</strong></li>'), TOOLBARTMPL = '<div class="k-widget k-filebrowser-toolbar k-header k-floatwrap">' + '<div class="k-toolbar-wrap">' + '# if (showUpload) { # ' + '<div class="k-widget k-upload"><div class="k-button k-button-icontext k-upload-button">' + '<span class="k-icon k-i-plus"></span>#=messages.uploadFile#<input type="file" name="file" /></div></div>' + '# } #' + '# if (showCreate) { #' + '<button type="button" class="k-button k-button-icon"><span class="k-icon k-i-folder-add" /></button>' + '# } #' + '# if (showDelete) { #' + '<button type="button" class="k-button k-button-icon k-state-disabled"><span class="k-icon k-i-close" /></button>&nbsp;' + '# } #' + '</div>' + '<div class="k-tiles-arrange">' + '<label>#=messages.orderBy#: <select /></label>' + '</div>' + '</div>';
        extend(true, kendo.data, {
            schemas: {
                'filebrowser': {
                    data: function (data) {
                        return data.items || data || [];
                    },
                    model: {
                        id: 'name',
                        fields: {
                            name: 'name',
                            size: 'size',
                            type: 'type'
                        }
                    }
                }
            }
        });
        extend(true, kendo.data, {
            transports: {
                'filebrowser': kendo.data.RemoteTransport.extend({
                    init: function (options) {
                        kendo.data.RemoteTransport.fn.init.call(this, $.extend(true, {}, this.options, options));
                    },
                    _call: function (type, options) {
                        options.data = $.extend({}, options.data, { path: this.options.path() });
                        if (isFunction(this.options[type])) {
                            this.options[type].call(this, options);
                        } else {
                            kendo.data.RemoteTransport.fn[type].call(this, options);
                        }
                    },
                    read: function (options) {
                        this._call('read', options);
                    },
                    create: function (options) {
                        this._call('create', options);
                    },
                    destroy: function (options) {
                        this._call('destroy', options);
                    },
                    update: function () {
                    },
                    options: {
                        read: { type: 'POST' },
                        update: { type: 'POST' },
                        create: { type: 'POST' },
                        destroy: { type: 'POST' }
                    }
                })
            }
        });
        function bindDragEventWrappers(element, onDragEnter, onDragLeave) {
            var hideInterval, lastDrag;
            element.on('dragenter' + NS, function () {
                onDragEnter();
                lastDrag = new Date();
                if (!hideInterval) {
                    hideInterval = setInterval(function () {
                        var sinceLastDrag = new Date() - lastDrag;
                        if (sinceLastDrag > 100) {
                            onDragLeave();
                            clearInterval(hideInterval);
                            hideInterval = null;
                        }
                    }, 100);
                }
            }).on('dragover' + NS, function () {
                lastDrag = new Date();
            });
        }
        var offsetTop;
        if (browser.msie && browser.version < 8) {
            offsetTop = function (element) {
                return element.offsetTop;
            };
        } else {
            offsetTop = function (element) {
                return element.offsetTop - $(element).height();
            };
        }
        function concatPaths(path, name) {
            if (path === undefined || !path.match(/\/$/)) {
                path = (path || '') + '/';
            }
            return path + name;
        }
        function sizeFormatter(value) {
            if (!value) {
                return '';
            }
            var suffix = ' bytes';
            if (value >= 1073741824) {
                suffix = ' GB';
                value /= 1073741824;
            } else if (value >= 1048576) {
                suffix = ' MB';
                value /= 1048576;
            } else if (value >= 1024) {
                suffix = ' KB';
                value /= 1024;
            }
            return Math.round(value * 100) / 100 + suffix;
        }
        function fieldName(fields, name) {
            var descriptor = fields[name];
            if (isPlainObject(descriptor)) {
                return descriptor.from || descriptor.field || name;
            }
            return descriptor;
        }
        var FileBrowser = Widget.extend({
            init: function (element, options) {
                var that = this;
                options = options || {};
                Widget.fn.init.call(that, element, options);
                that.element.addClass('k-filebrowser');
                that.element.on(CLICK + NS, '.k-filebrowser-toolbar button:not(.k-state-disabled):has(.k-i-close)', proxy(that._deleteClick, that)).on(CLICK + NS, '.k-filebrowser-toolbar button:not(.k-state-disabled):has(.k-i-folder-add)', proxy(that._addClick, that)).on('keydown' + NS, 'li.k-state-selected input', proxy(that._directoryKeyDown, that)).on('blur' + NS, 'li.k-state-selected input', proxy(that._directoryBlur, that));
                that._dataSource();
                that.refresh();
                that.path(that.options.path);
            },
            options: {
                name: 'FileBrowser',
                messages: {
                    uploadFile: 'Upload',
                    orderBy: 'Arrange by',
                    orderByName: 'Name',
                    orderBySize: 'Size',
                    directoryNotFound: 'A directory with this name was not found.',
                    emptyFolder: 'Empty Folder',
                    deleteFile: 'Are you sure you want to delete "{0}"?',
                    invalidFileType: 'The selected file "{0}" is not valid. Supported file types are {1}.',
                    overwriteFile: 'A file with name "{0}" already exists in the current directory. Do you want to overwrite it?',
                    dropFilesHere: 'drop file here to upload',
                    search: 'Search'
                },
                transport: {},
                path: '/',
                fileTypes: '*.*'
            },
            events: [
                ERROR,
                CHANGE,
                APPLY
            ],
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.dataSource.unbind(ERROR, that._errorHandler);
                that.element.add(that.list).add(that.toolbar).off(NS);
                kendo.destroy(that.element);
            },
            value: function () {
                var that = this, selected = that._selectedItem(), path, fileUrl = that.options.transport.fileUrl;
                if (selected && selected.get(TYPEFIELD) === 'f') {
                    path = concatPaths(that.path(), selected.get(NAMEFIELD)).replace(trimSlashesRegExp, '');
                    if (fileUrl) {
                        path = isFunction(fileUrl) ? fileUrl(path) : kendo.format(fileUrl, encodeURIComponent(path));
                    }
                    return path;
                }
            },
            _selectedItem: function () {
                var listView = this.listView, selected = listView.select();
                if (selected.length) {
                    return this.dataSource.getByUid(selected.attr(kendo.attr('uid')));
                }
            },
            _toolbar: function () {
                var that = this, template = kendo.template(TOOLBARTMPL), messages = that.options.messages, arrangeBy = [
                        {
                            text: messages.orderByName,
                            value: 'name'
                        },
                        {
                            text: messages.orderBySize,
                            value: 'size'
                        }
                    ];
                that.toolbar = $(template({
                    messages: messages,
                    showUpload: that.options.transport.uploadUrl,
                    showCreate: that.options.transport.create,
                    showDelete: that.options.transport.destroy
                })).appendTo(that.element).find('.k-upload input').kendoUpload({
                    multiple: false,
                    localization: { dropFilesHere: messages.dropFilesHere },
                    async: {
                        saveUrl: that.options.transport.uploadUrl,
                        autoUpload: true
                    },
                    upload: proxy(that._fileUpload, that),
                    error: function (e) {
                        that._error({
                            xhr: e.XMLHttpRequest,
                            status: 'error'
                        });
                    }
                }).end();
                that.upload = that.toolbar.find('.k-upload input').data('kendoUpload');
                that.arrangeBy = that.toolbar.find('.k-tiles-arrange select').kendoDropDownList({
                    dataSource: arrangeBy,
                    dataTextField: 'text',
                    dataValueField: 'value',
                    change: function () {
                        that.orderBy(this.value());
                    }
                }).data('kendoDropDownList');
                that._attachDropzoneEvents();
            },
            _attachDropzoneEvents: function () {
                var that = this;
                if (that.options.transport.uploadUrl) {
                    bindDragEventWrappers($(document.documentElement), $.proxy(that._dropEnter, that), $.proxy(that._dropLeave, that));
                    that._scrollHandler = proxy(that._positionDropzone, that);
                }
            },
            _dropEnter: function () {
                this._positionDropzone();
                $(document).on('scroll' + NS, this._scrollHandler);
            },
            _dropLeave: function () {
                this._removeDropzone();
                $(document).off('scroll' + NS, this._scrollHandler);
            },
            _positionDropzone: function () {
                var that = this, element = that.element, offset = element.offset();
                that.toolbar.find('.k-dropzone').addClass('k-filebrowser-dropzone').offset(offset).css({
                    width: element[0].clientWidth,
                    height: element[0].clientHeight,
                    lineHeight: element[0].clientHeight + 'px'
                });
            },
            _removeDropzone: function () {
                this.toolbar.find('.k-dropzone').removeClass('k-filebrowser-dropzone').css({
                    width: '',
                    height: '',
                    lineHeight: '',
                    top: '',
                    left: ''
                });
            },
            _deleteClick: function () {
                var that = this, item = that.listView.select(), message = kendo.format(that.options.messages.deleteFile, item.find('strong').text());
                if (item.length && that._showMessage(message, 'confirm')) {
                    that.listView.remove(item);
                }
            },
            _addClick: function () {
                this.createDirectory();
            },
            _getFieldName: function (name) {
                return fieldName(this.dataSource.reader.model.fields, name);
            },
            _fileUpload: function (e) {
                var that = this, options = that.options, fileTypes = options.fileTypes, filterRegExp = new RegExp(('(' + fileTypes.split(',').join(')|(') + ')').replace(/\*\./g, '.*.'), 'i'), fileName = e.files[0].name, fileNameField = NAMEFIELD, sizeField = SIZEFIELD, file;
                if (filterRegExp.test(fileName)) {
                    e.data = { path: that.path() };
                    file = that._createFile(fileName);
                    if (!file) {
                        e.preventDefault();
                    } else {
                        that.upload.one('success', function (e) {
                            var model = that._insertFileToList(file);
                            model.set(fileNameField, e.response[that._getFieldName(fileNameField)]);
                            model.set(sizeField, e.response[that._getFieldName(sizeField)]);
                            that._tiles = that.listView.items().filter('[' + kendo.attr('type') + '=f]');
                        });
                    }
                } else {
                    e.preventDefault();
                    that._showMessage(kendo.format(options.messages.invalidFileType, fileName, fileTypes));
                }
            },
            _findFile: function (name) {
                var data = this.dataSource.data(), idx, result, typeField = TYPEFIELD, nameField = NAMEFIELD, length;
                name = name.toLowerCase();
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].get(typeField) === 'f' && data[idx].get(nameField).toLowerCase() === name) {
                        result = data[idx];
                        break;
                    }
                }
                return result;
            },
            _createFile: function (fileName) {
                var that = this, model = {}, typeField = TYPEFIELD, file = that._findFile(fileName);
                if (file) {
                    if (!that._showMessage(kendo.format(that.options.messages.overwriteFile, fileName), 'confirm')) {
                        return null;
                    } else {
                        file._override = true;
                        return file;
                    }
                }
                model[typeField] = 'f';
                model[NAMEFIELD] = fileName;
                model[SIZEFIELD] = 0;
                return model;
            },
            _insertFileToList: function (model) {
                var index;
                if (model._override) {
                    return model;
                }
                var dataSource = this.dataSource;
                var view = dataSource.view();
                for (var i = 0, length = view.length; i < length; i++) {
                    if (view[i].get(TYPEFIELD) === 'f') {
                        index = i;
                        break;
                    }
                }
                return dataSource.insert(++index, model);
            },
            createDirectory: function () {
                var that = this, idx, length, lastDirectoryIdx = 0, typeField = TYPEFIELD, nameField = NAMEFIELD, view = that.dataSource.data(), name = that._nameDirectory(), model = new that.dataSource.reader.model();
                for (idx = 0, length = view.length; idx < length; idx++) {
                    if (view[idx].get(typeField) === 'd') {
                        lastDirectoryIdx = idx;
                    }
                }
                model.set(typeField, 'd');
                model.set(nameField, name);
                that.listView.one('dataBound', function () {
                    var selected = that.listView.items().filter('[' + kendo.attr('uid') + '=' + model.uid + ']'), input = selected.find('input');
                    if (selected.length) {
                        this.edit(selected);
                    }
                    this.element.scrollTop(selected.attr('offsetTop') - this.element[0].offsetHeight);
                    setTimeout(function () {
                        input.select();
                    });
                }).one('save', function (e) {
                    var value = e.model.get(nameField);
                    if (!value) {
                        e.model.set(nameField, name);
                    } else {
                        e.model.set(nameField, that._nameExists(value, model.uid) ? that._nameDirectory() : value);
                    }
                });
                that.dataSource.insert(++lastDirectoryIdx, model);
            },
            _directoryKeyDown: function (e) {
                if (e.keyCode == 13) {
                    e.currentTarget.blur();
                }
            },
            _directoryBlur: function () {
                this.listView.save();
            },
            _nameExists: function (name, uid) {
                var data = this.dataSource.data(), typeField = TYPEFIELD, nameField = NAMEFIELD, idx, length;
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].get(typeField) === 'd' && data[idx].get(nameField).toLowerCase() === name.toLowerCase() && data[idx].uid !== uid) {
                        return true;
                    }
                }
                return false;
            },
            _nameDirectory: function () {
                var name = 'New folder', data = this.dataSource.data(), directoryNames = [], typeField = TYPEFIELD, nameField = NAMEFIELD, candidate, idx, length;
                for (idx = 0, length = data.length; idx < length; idx++) {
                    if (data[idx].get(typeField) === 'd' && data[idx].get(nameField).toLowerCase().indexOf(name.toLowerCase()) > -1) {
                        directoryNames.push(data[idx].get(nameField));
                    }
                }
                if ($.inArray(name, directoryNames) > -1) {
                    idx = 2;
                    do {
                        candidate = name + ' (' + idx + ')';
                        idx++;
                    } while ($.inArray(candidate, directoryNames) > -1);
                    name = candidate;
                }
                return name;
            },
            orderBy: function (field) {
                this.dataSource.sort([
                    {
                        field: TYPEFIELD,
                        dir: 'asc'
                    },
                    {
                        field: field,
                        dir: 'asc'
                    }
                ]);
            },
            search: function (name) {
                this.dataSource.filter({
                    field: NAMEFIELD,
                    operator: 'contains',
                    value: name
                });
            },
            _content: function () {
                var that = this;
                that.list = $('<ul class="k-reset k-floats k-tiles" />').appendTo(that.element).on('dblclick' + NS, 'li', proxy(that._dblClick, that));
                that.listView = new kendo.ui.ListView(that.list, {
                    dataSource: that.dataSource,
                    template: that._itemTmpl(),
                    editTemplate: that._editTmpl(),
                    selectable: true,
                    autoBind: false,
                    dataBinding: function (e) {
                        that.toolbar.find('.k-i-close').parent().addClass('k-state-disabled');
                        if (e.action === 'remove' || e.action === 'sync') {
                            e.preventDefault();
                        }
                    },
                    dataBound: function () {
                        if (that.dataSource.view().length) {
                            that._tiles = this.items().filter('[' + kendo.attr('type') + '=f]');
                        } else {
                            this.wrapper.append(EMPTYTILE({ text: that.options.messages.emptyFolder }));
                        }
                    },
                    change: proxy(that._listViewChange, that)
                });
            },
            _dblClick: function (e) {
                var that = this, li = $(e.currentTarget);
                if (li.hasClass('k-edit-item')) {
                    that._directoryBlur();
                }
                if (li.filter('[' + kendo.attr('type') + '=d]').length) {
                    var folder = that.dataSource.getByUid(li.attr(kendo.attr('uid')));
                    if (folder) {
                        that.path(concatPaths(that.path(), folder.get(NAMEFIELD)));
                        that.breadcrumbs.value(that.path());
                    }
                } else if (li.filter('[' + kendo.attr('type') + '=f]').length) {
                    that.trigger(APPLY);
                }
            },
            _listViewChange: function () {
                var selected = this._selectedItem();
                if (selected) {
                    this.toolbar.find('.k-i-close').parent().removeClass('k-state-disabled');
                    this.trigger(CHANGE, { selected: selected });
                }
            },
            _dataSource: function () {
                var that = this, options = that.options, transport = options.transport, typeSortOrder = extend({}, DEFAULTSORTORDER), nameSortOrder = {
                        field: NAMEFIELD,
                        dir: 'asc'
                    }, schema, dataSource = {
                        type: transport.type || 'filebrowser',
                        sort: [
                            typeSortOrder,
                            nameSortOrder
                        ]
                    };
                if (isPlainObject(transport)) {
                    transport.path = proxy(that.path, that);
                    dataSource.transport = transport;
                }
                if (isPlainObject(options.schema)) {
                    dataSource.schema = options.schema;
                } else if (transport.type && isPlainObject(kendo.data.schemas[transport.type])) {
                    schema = kendo.data.schemas[transport.type];
                }
                if (that.dataSource && that._errorHandler) {
                    that.dataSource.unbind(ERROR, that._errorHandler);
                } else {
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = kendo.data.DataSource.create(dataSource).bind(ERROR, that._errorHandler);
            },
            _navigation: function () {
                var that = this, navigation = $('<div class="k-floatwrap"><input/><input/></div>').appendTo(this.element);
                that.breadcrumbs = navigation.find('input:first').kendoBreadcrumbs({
                    value: that.options.path,
                    change: function () {
                        that.path(this.value());
                    }
                }).data('kendoBreadcrumbs');
                that.searchBox = navigation.parent().find('input:last').kendoSearchBox({
                    label: that.options.messages.search,
                    change: function () {
                        that.search(this.value());
                    }
                }).data('kendoSearchBox');
            },
            _error: function (e) {
                var that = this, status;
                if (!that.trigger(ERROR, e)) {
                    status = e.xhr.status;
                    if (e.status == 'error') {
                        if (status == '404') {
                            that._showMessage(that.options.messages.directoryNotFound);
                        } else if (status != '0') {
                            that._showMessage('Error! The requested URL returned ' + status + ' - ' + e.xhr.statusText);
                        }
                    } else if (status == 'timeout') {
                        that._showMessage('Error! Server timeout.');
                    }
                    var dataSource = that.dataSource;
                    if (dataSource.hasChanges()) {
                        dataSource.cancelChanges();
                    }
                }
            },
            _showMessage: function (message, type) {
                return window[type || 'alert'](message);
            },
            refresh: function () {
                var that = this;
                that._navigation();
                that._toolbar();
                that._content();
            },
            _editTmpl: function () {
                var html = '<li class="k-tile k-state-selected" ' + kendo.attr('uid') + '="#=uid#" ';
                html += kendo.attr('type') + '="${' + TYPEFIELD + '}">';
                html += '#if(' + TYPEFIELD + ' == "d") { #';
                html += '<div class="k-thumb"><span class="k-icon k-i-folder"></span></div>';
                html += '#}else{#';
                html += '<div class="k-thumb"><span class="k-icon k-i-loading"></span></div>';
                html += '#}#';
                html += '#if(' + TYPEFIELD + ' == "d") { #';
                html += '<input class="k-input" ' + kendo.attr('bind') + '="value:' + NAMEFIELD + '"/>';
                html += '#}#';
                html += '</li>';
                return proxy(kendo.template(html), { sizeFormatter: sizeFormatter });
            },
            _itemTmpl: function () {
                var html = '<li class="k-tile" ' + kendo.attr('uid') + '="#=uid#" ';
                html += kendo.attr('type') + '="${' + TYPEFIELD + '}">';
                html += '#if(' + TYPEFIELD + ' == "d") { #';
                html += '<div class="k-thumb"><span class="k-icon k-i-folder"></span></div>';
                html += '#}else{#';
                html += '<div class="k-thumb"><span class="k-icon k-i-file"></span></div>';
                html += '#}#';
                html += '<strong>${' + NAMEFIELD + '}</strong>';
                html += '#if(' + TYPEFIELD + ' == "f") { # <span class="k-filesize">${this.sizeFormatter(' + SIZEFIELD + ')}</span> #}#';
                html += '</li>';
                return proxy(kendo.template(html), { sizeFormatter: sizeFormatter });
            },
            path: function (value) {
                var that = this, path = that._path || '';
                if (value !== undefined) {
                    that._path = value.replace(trimSlashesRegExp, '') + '/';
                    that.dataSource.read({ path: that._path });
                    return;
                }
                if (path) {
                    path = path.replace(trimSlashesRegExp, '');
                }
                return path === '/' || path === '' ? '' : path + '/';
            }
        });
        var SearchBox = Widget.extend({
            init: function (element, options) {
                var that = this;
                options = options || {};
                Widget.fn.init.call(that, element, options);
                if (placeholderSupported) {
                    that.element.attr('placeholder', that.options.label);
                }
                that._wrapper();
                that.element.on('keydown' + SEARCHBOXNS, proxy(that._keydown, that)).on('change' + SEARCHBOXNS, proxy(that._updateValue, that));
                that.wrapper.on(CLICK + SEARCHBOXNS, 'a', proxy(that._click, that));
                if (!placeholderSupported) {
                    that.element.on('focus' + SEARCHBOXNS, proxy(that._focus, that)).on('blur' + SEARCHBOXNS, proxy(that._blur, that));
                }
            },
            options: {
                name: 'SearchBox',
                label: 'Search',
                value: ''
            },
            events: [CHANGE],
            destroy: function () {
                var that = this;
                that.wrapper.add(that.element).add(that.label).off(SEARCHBOXNS);
                Widget.fn.destroy.call(that);
            },
            _keydown: function (e) {
                if (e.keyCode === 13) {
                    this._updateValue();
                }
            },
            _click: function (e) {
                e.preventDefault();
                this._updateValue();
            },
            _updateValue: function () {
                var that = this, value = that.element.val();
                if (value !== that.value()) {
                    that.value(value);
                    that.trigger(CHANGE);
                }
            },
            _blur: function () {
                this._updateValue();
                this._toggleLabel();
            },
            _toggleLabel: function () {
                if (!placeholderSupported) {
                    this.label.toggle(!this.element.val());
                }
            },
            _focus: function () {
                this.label.hide();
            },
            _wrapper: function () {
                var element = this.element, wrapper = element.parents('.k-search-wrap');
                element[0].style.width = '';
                element.addClass('k-input');
                if (!wrapper.length) {
                    wrapper = element.wrap($('<div class="k-widget k-search-wrap k-textbox"/>')).parent();
                    if (!placeholderSupported) {
                        $('<label style="display:block">' + this.options.label + '</label>').insertBefore(element);
                    }
                    $('<a href="#" class="k-icon k-i-zoom k-search"/>').appendTo(wrapper);
                }
                this.wrapper = wrapper;
                this.label = wrapper.find('>label');
            },
            value: function (value) {
                var that = this;
                if (value !== undefined) {
                    that.options.value = value;
                    that.element.val(value);
                    that._toggleLabel();
                    return;
                }
                return that.options.value;
            }
        });
        var Breadcrumbs = Widget.extend({
            init: function (element, options) {
                var that = this;
                options = options || {};
                Widget.fn.init.call(that, element, options);
                that._wrapper();
                that.wrapper.on('focus' + BREADCRUBMSNS, 'input', proxy(that._focus, that)).on('blur' + BREADCRUBMSNS, 'input', proxy(that._blur, that)).on('keydown' + BREADCRUBMSNS, 'input', proxy(that._keydown, that)).on(CLICK + BREADCRUBMSNS, 'a.k-i-arrow-60-up:first', proxy(that._rootClick, that)).on(CLICK + BREADCRUBMSNS, 'a:not(.k-i-arrow-60-up)', proxy(that._click, that));
                that.value(that.options.value);
            },
            options: {
                name: 'Breadcrumbs',
                gap: 50
            },
            events: [CHANGE],
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.wrapper.add(that.wrapper.find('input')).add(that.wrapper.find('a')).off(BREADCRUBMSNS);
            },
            _update: function (val) {
                val = (val || '').charAt(0) === '/' ? val : '/' + (val || '');
                if (val !== this.value()) {
                    this.value(val);
                    this.trigger(CHANGE);
                }
            },
            _click: function (e) {
                e.preventDefault();
                this._update(this._path($(e.target).prevAll('a:not(.k-i-arrow-60-up)').addBack()));
            },
            _rootClick: function (e) {
                e.preventDefault();
                this._update('');
            },
            _focus: function () {
                var that = this, element = that.element;
                that.overlay.hide();
                that.element.val(that.value());
                setTimeout(function () {
                    element.select();
                });
            },
            _blur: function () {
                if (this.overlay.is(':visible')) {
                    return;
                }
                var that = this, element = that.element, val = element.val().replace(/\/{2,}/g, '/');
                that.overlay.show();
                element.val('');
                that._update(val);
            },
            _keydown: function (e) {
                var that = this;
                if (e.keyCode === 13) {
                    that._blur();
                    setTimeout(function () {
                        that.overlay.find('a:first').focus();
                    });
                }
            },
            _wrapper: function () {
                var element = this.element, wrapper = element.parents('.k-breadcrumbs'), overlay;
                element[0].style.width = '';
                element.addClass('k-input');
                if (!wrapper.length) {
                    wrapper = element.wrap($('<div class="k-widget k-breadcrumbs k-textbox"/>')).parent();
                }
                overlay = wrapper.find('.k-breadcrumbs-wrap');
                if (!overlay.length) {
                    overlay = $('<div class="k-breadcrumbs-wrap"/>').appendTo(wrapper);
                }
                this.wrapper = wrapper;
                this.overlay = overlay;
            },
            refresh: function () {
                var html = '', value = this.value(), segments, segment, idx, length;
                if (value === undefined || !value.match(/^\//)) {
                    value = '/' + (value || '');
                }
                segments = value.split('/');
                for (idx = 0, length = segments.length; idx < length; idx++) {
                    segment = segments[idx];
                    if (segment) {
                        if (!html) {
                            html += '<a href="#" class="k-icon k-i-arrow-60-up" title="Go to parent folder"></a>';
                        }
                        html += '<a class="k-link" href="#">' + segments[idx] + '</a>';
                        html += '<span class="k-icon k-i-arrow-60-right" title="Go to child folder"></span>';
                    }
                }
                this.overlay.empty().append($(html));
                this._adjustSectionWidth();
            },
            _adjustSectionWidth: function () {
                var that = this, wrapper = that.wrapper, width = wrapper.width() - that.options.gap, links = that.overlay.find('a'), a;
                links.each(function (index) {
                    a = $(this);
                    if (a.parent().width() > width) {
                        if (index == links.length - 1) {
                            a.width(width);
                        } else {
                            a.prev().addBack().hide();
                        }
                    }
                });
            },
            value: function (val) {
                if (val !== undefined) {
                    this._value = val.replace(/\/{2,}/g, '/');
                    this.refresh();
                    return;
                }
                return this._value;
            },
            _path: function (trail) {
                return '/' + $.map(trail, function (b) {
                    return $(b).text();
                }).join('/');
            }
        });
        kendo.ui.plugin(FileBrowser);
        kendo.ui.plugin(Breadcrumbs);
        kendo.ui.plugin(SearchBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.imagebrowser', ['kendo.filebrowser'], f);
}(function () {
    var __meta__ = {
        id: 'imagebrowser',
        name: 'ImageBrowser',
        category: 'web',
        description: '',
        hidden: true,
        depends: ['filebrowser']
    };
    (function ($, undefined) {
        var kendo = window.kendo, FileBrowser = kendo.ui.FileBrowser, isPlainObject = $.isPlainObject, proxy = $.proxy, extend = $.extend, browser = kendo.support.browser, isFunction = kendo.isFunction, trimSlashesRegExp = /(^\/|\/$)/g, ERROR = 'error', NS = '.kendoImageBrowser', NAMEFIELD = 'name', SIZEFIELD = 'size', TYPEFIELD = 'type', DEFAULTSORTORDER = {
                field: TYPEFIELD,
                dir: 'asc'
            }, EMPTYTILE = kendo.template('<li class="k-tile-empty"><strong>${text}</strong></li>');
        extend(true, kendo.data, {
            schemas: {
                'imagebrowser': {
                    data: function (data) {
                        return data.items || data || [];
                    },
                    model: {
                        id: 'name',
                        fields: {
                            name: 'name',
                            size: 'size',
                            type: 'type'
                        }
                    }
                }
            }
        });
        extend(true, kendo.data, {
            transports: {
                'imagebrowser': kendo.data.RemoteTransport.extend({
                    init: function (options) {
                        kendo.data.RemoteTransport.fn.init.call(this, $.extend(true, {}, this.options, options));
                    },
                    _call: function (type, options) {
                        options.data = $.extend({}, options.data, { path: this.options.path() });
                        if (isFunction(this.options[type])) {
                            this.options[type].call(this, options);
                        } else {
                            kendo.data.RemoteTransport.fn[type].call(this, options);
                        }
                    },
                    read: function (options) {
                        this._call('read', options);
                    },
                    create: function (options) {
                        this._call('create', options);
                    },
                    destroy: function (options) {
                        this._call('destroy', options);
                    },
                    update: function () {
                    },
                    options: {
                        read: { type: 'POST' },
                        update: { type: 'POST' },
                        create: { type: 'POST' },
                        destroy: { type: 'POST' }
                    }
                })
            }
        });
        var offsetTop;
        if (browser.msie && browser.version < 8) {
            offsetTop = function (element) {
                return element.offsetTop;
            };
        } else {
            offsetTop = function (element) {
                return element.offsetTop - $(element).height();
            };
        }
        function concatPaths(path, name) {
            if (path === undefined || !path.match(/\/$/)) {
                path = (path || '') + '/';
            }
            return path + name;
        }
        function sizeFormatter(value) {
            if (!value) {
                return '';
            }
            var suffix = ' bytes';
            if (value >= 1073741824) {
                suffix = ' GB';
                value /= 1073741824;
            } else if (value >= 1048576) {
                suffix = ' MB';
                value /= 1048576;
            } else if (value >= 1024) {
                suffix = ' KB';
                value /= 1024;
            }
            return Math.round(value * 100) / 100 + suffix;
        }
        var ImageBrowser = FileBrowser.extend({
            init: function (element, options) {
                var that = this;
                options = options || {};
                FileBrowser.fn.init.call(that, element, options);
                that.element.addClass('k-imagebrowser');
            },
            options: {
                name: 'ImageBrowser',
                fileTypes: '*.png,*.gif,*.jpg,*.jpeg'
            },
            value: function () {
                var that = this, selected = that._selectedItem(), path, imageUrl = that.options.transport.imageUrl;
                if (selected && selected.get(TYPEFIELD) === 'f') {
                    path = concatPaths(that.path(), selected.get(NAMEFIELD)).replace(trimSlashesRegExp, '');
                    if (imageUrl) {
                        path = isFunction(imageUrl) ? imageUrl(path) : kendo.format(imageUrl, encodeURIComponent(path));
                    }
                    return path;
                }
            },
            _fileUpload: function (e) {
                var that = this, options = that.options, fileTypes = options.fileTypes, filterRegExp = new RegExp(('(' + fileTypes.split(',').join(')|(') + ')').replace(/\*\./g, '.*.'), 'i'), fileName = e.files[0].name, fileNameField = NAMEFIELD, sizeField = SIZEFIELD, file;
                if (filterRegExp.test(fileName)) {
                    e.data = { path: that.path() };
                    file = that._createFile(fileName);
                    if (!file) {
                        e.preventDefault();
                    } else {
                        file._uploading = true;
                        that.upload.one('success', function (e) {
                            delete file._uploading;
                            var model = that._insertFileToList(file);
                            model.set(fileNameField, e.response[that._getFieldName(fileNameField)]);
                            model.set(sizeField, e.response[that._getFieldName(sizeField)]);
                            that._tiles = that.listView.items().filter('[' + kendo.attr('type') + '=f]');
                            that._scroll();
                        });
                    }
                } else {
                    e.preventDefault();
                    that._showMessage(kendo.format(options.messages.invalidFileType, fileName, fileTypes));
                }
            },
            _content: function () {
                var that = this;
                that.list = $('<ul class="k-reset k-floats k-tiles" />').appendTo(that.element).on('scroll' + NS, proxy(that._scroll, that)).on('dblclick' + NS, 'li', proxy(that._dblClick, that));
                that.listView = new kendo.ui.ListView(that.list, {
                    dataSource: that.dataSource,
                    template: that._itemTmpl(),
                    editTemplate: that._editTmpl(),
                    selectable: true,
                    autoBind: false,
                    dataBinding: function (e) {
                        that.toolbar.find('.k-i-close').parent().addClass('k-state-disabled');
                        if (e.action === 'remove' || e.action === 'sync') {
                            e.preventDefault();
                        }
                    },
                    dataBound: function () {
                        if (that.dataSource.view().length) {
                            that._tiles = this.items().filter('[' + kendo.attr('type') + '=f]');
                            that._scroll();
                        } else {
                            this.wrapper.append(EMPTYTILE({ text: that.options.messages.emptyFolder }));
                        }
                    },
                    change: proxy(that._listViewChange, that)
                });
            },
            _dataSource: function () {
                var that = this, options = that.options, transport = options.transport, typeSortOrder = extend({}, DEFAULTSORTORDER), nameSortOrder = {
                        field: NAMEFIELD,
                        dir: 'asc'
                    }, schema, dataSource = {
                        type: transport.type || 'imagebrowser',
                        sort: [
                            typeSortOrder,
                            nameSortOrder
                        ]
                    };
                if (isPlainObject(transport)) {
                    transport.path = proxy(that.path, that);
                    dataSource.transport = transport;
                }
                if (isPlainObject(options.schema)) {
                    dataSource.schema = options.schema;
                } else if (transport.type && isPlainObject(kendo.data.schemas[transport.type])) {
                    schema = kendo.data.schemas[transport.type];
                }
                if (that.dataSource && that._errorHandler) {
                    that.dataSource.unbind(ERROR, that._errorHandler);
                } else {
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = kendo.data.DataSource.create(dataSource).bind(ERROR, that._errorHandler);
            },
            _loadImage: function (li) {
                var that = this, element = $(li), dataItem = that.dataSource.getByUid(element.attr(kendo.attr('uid'))), name = dataItem.get(NAMEFIELD), thumbnailUrl = that.options.transport.thumbnailUrl, img = $('<img />', { alt: name }), urlJoin = '?';
                if (dataItem._uploading) {
                    return;
                }
                img.hide().on('load' + NS, function () {
                    $(this).prev().remove().end().addClass('k-image').fadeIn();
                });
                element.find('.k-i-loading').after(img);
                if (isFunction(thumbnailUrl)) {
                    thumbnailUrl = thumbnailUrl(that.path(), encodeURIComponent(name));
                } else {
                    if (thumbnailUrl.indexOf('?') >= 0) {
                        urlJoin = '&';
                    }
                    thumbnailUrl = thumbnailUrl + urlJoin + 'path=' + encodeURIComponent(that.path() + name);
                    if (dataItem._override) {
                        thumbnailUrl += '&_=' + new Date().getTime();
                        delete dataItem._override;
                    }
                }
                img.attr('src', thumbnailUrl);
                li.loaded = true;
            },
            _scroll: function () {
                var that = this;
                if (that.options.transport && that.options.transport.thumbnailUrl) {
                    clearTimeout(that._timeout);
                    that._timeout = setTimeout(function () {
                        var height = kendo._outerHeight(that.list), viewTop = that.list.scrollTop(), viewBottom = viewTop + height;
                        that._tiles.each(function () {
                            var top = offsetTop(this), bottom = top + this.offsetHeight;
                            if (top >= viewTop && top < viewBottom || bottom >= viewTop && bottom < viewBottom) {
                                that._loadImage(this);
                            }
                            if (top > viewBottom) {
                                return false;
                            }
                        });
                        that._tiles = that._tiles.filter(function () {
                            return !this.loaded;
                        });
                    }, 250);
                }
            },
            _itemTmpl: function () {
                var that = this, html = '<li class="k-tile" ' + kendo.attr('uid') + '="#=uid#" ';
                html += kendo.attr('type') + '="${' + TYPEFIELD + '}">';
                html += '#if(' + TYPEFIELD + ' == "d") { #';
                html += '<div class="k-thumb"><span class="k-icon k-i-folder"></span></div>';
                html += '#}else{#';
                if (that.options.transport && that.options.transport.thumbnailUrl) {
                    html += '<div class="k-thumb"><span class="k-icon k-i-loading"></span></div>';
                } else {
                    html += '<div class="k-thumb"><span class="k-icon k-i-file"></span></div>';
                }
                html += '#}#';
                html += '<strong>${' + NAMEFIELD + '}</strong>';
                html += '#if(' + TYPEFIELD + ' == "f") { # <span class="k-filesize">${this.sizeFormatter(' + SIZEFIELD + ')}</span> #}#';
                html += '</li>';
                return proxy(kendo.template(html), { sizeFormatter: sizeFormatter });
            }
        });
        kendo.ui.plugin(ImageBrowser);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.tabstrip', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'tabstrip',
        name: 'TabStrip',
        category: 'web',
        description: 'The TabStrip widget displays a collection of tabs with associated tab content.',
        depends: ['data']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, keys = kendo.keys, map = $.map, each = $.each, trim = $.trim, extend = $.extend, isFunction = kendo.isFunction, template = kendo.template, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, Widget = ui.Widget, excludedNodesRegExp = /^(a|div)$/i, NS = '.kendoTabStrip', IMG = 'img', HREF = 'href', PREV = 'prev', SHOW = 'show', LINK = 'k-link', LAST = 'k-last', CLICK = 'click', ERROR = 'error', EMPTY = ':empty', IMAGE = 'k-image', FIRST = 'k-first', SELECT = 'select', ACTIVATE = 'activate', CONTENT = 'k-content', CONTENTURL = 'contentUrl', MOUSEENTER = 'mouseenter', MOUSELEAVE = 'mouseleave', CONTENTLOAD = 'contentLoad', DISABLEDSTATE = 'k-state-disabled', DEFAULTSTATE = 'k-state-default', ACTIVESTATE = 'k-state-active', FOCUSEDSTATE = 'k-state-focused', HOVERSTATE = 'k-state-hover', TABONTOP = 'k-tab-on-top', NAVIGATABLEITEMS = '.k-item:not(.' + DISABLEDSTATE + ')', HOVERABLEITEMS = '.k-tabstrip-items > ' + NAVIGATABLEITEMS + ':not(.' + ACTIVESTATE + ')', templates = {
                content: template('<div class=\'k-content\'#= contentAttributes(data) # role=\'tabpanel\'>#= content(item) #</div>'),
                itemWrapper: template('<#= tag(item) # class=\'k-link\'#= contentUrl(item) ##= textAttributes(item) #>' + '#= image(item) ##= sprite(item) ##= text(item) #' + '</#= tag(item) #>'),
                item: template('<li class=\'#= wrapperCssClass(group, item) #\' role=\'tab\' #=item.active ? "aria-selected=\'true\'" : \'\'#>' + '#= itemWrapper(data) #' + '</li>'),
                image: template('<img class=\'k-image\' alt=\'\' src=\'#= imageUrl #\' />'),
                sprite: template('<span class=\'k-sprite #= spriteCssClass #\'></span>'),
                empty: template('')
            }, rendering = {
                wrapperCssClass: function (group, item) {
                    var result = 'k-item', index = item.index;
                    if (item.enabled === false) {
                        result += ' k-state-disabled';
                    } else {
                        result += ' k-state-default';
                    }
                    if (index === 0) {
                        result += ' k-first';
                    }
                    if (index == group.length - 1) {
                        result += ' k-last';
                    }
                    return result;
                },
                textAttributes: function (item) {
                    return item.url ? ' href=\'' + item.url + '\'' : '';
                },
                text: function (item) {
                    return item.encoded === false ? item.text : kendo.htmlEncode(item.text);
                },
                tag: function (item) {
                    return item.url ? 'a' : 'span';
                },
                contentAttributes: function (content) {
                    return content.active !== true ? ' style=\'display:none\' aria-hidden=\'true\' aria-expanded=\'false\'' : '';
                },
                content: function (item) {
                    return item.content ? item.content : item.contentUrl ? '' : '&nbsp;';
                },
                contentUrl: function (item) {
                    return item.contentUrl ? kendo.attr('content-url') + '="' + item.contentUrl + '"' : '';
                }
            };
        function updateTabClasses(tabs) {
            tabs.children(IMG).addClass(IMAGE);
            tabs.children('a').addClass(LINK).children(IMG).addClass(IMAGE);
            tabs.filter(':not([disabled]):not([class*=k-state-disabled])').addClass(DEFAULTSTATE);
            tabs.filter('li[disabled]').addClass(DISABLEDSTATE).removeAttr('disabled');
            tabs.filter(':not([class*=k-state])').children('a').filter(':focus').parent().addClass(ACTIVESTATE + ' ' + TABONTOP);
            tabs.attr('role', 'tab');
            tabs.filter('.' + ACTIVESTATE).attr('aria-selected', true);
            tabs.each(function () {
                var item = $(this);
                if (!item.children('.' + LINK).length) {
                    item.contents().filter(function () {
                        return !this.nodeName.match(excludedNodesRegExp) && !(this.nodeType == 3 && !trim(this.nodeValue));
                    }).wrapAll('<span UNSELECTABLE=\'on\' class=\'' + LINK + '\'/>');
                }
            });
        }
        function updateFirstLast(tabGroup) {
            var tabs = tabGroup.children('.k-item');
            tabs.filter('.k-first:not(:first-child)').removeClass(FIRST);
            tabs.filter('.k-last:not(:last-child)').removeClass(LAST);
            tabs.filter(':first-child').addClass(FIRST);
            tabs.filter(':last-child').addClass(LAST);
        }
        function scrollButtonHtml(buttonClass, iconClass) {
            return '<span class=\'k-button k-button-icon k-bare k-tabstrip-' + buttonClass + '\' unselectable=\'on\'><span class=\'k-icon ' + iconClass + '\'></span></span>';
        }
        var TabStrip = Widget.extend({
            init: function (element, options) {
                var that = this, value;
                Widget.fn.init.call(that, element, options);
                that._animations(that.options);
                options = that.options;
                that._contentUrls = options.contentUrls || [];
                that._wrapper();
                that._isRtl = kendo.support.isRtl(that.wrapper);
                that._tabindex();
                that._updateClasses();
                that._dataSource();
                if (options.dataSource) {
                    that.dataSource.fetch();
                }
                that._tabPosition();
                that._scrollable();
                if (that._contentUrls.length) {
                    that.wrapper.find('.k-tabstrip-items > .k-item').each(function (index, item) {
                        var url = that._contentUrls[index];
                        if (typeof url === 'string') {
                            $(item).find('>.' + LINK).data(CONTENTURL, url);
                        }
                    });
                } else {
                    that._contentUrls.length = that.tabGroup.find('li.k-item').length;
                }
                that.wrapper.on(MOUSEENTER + NS + ' ' + MOUSELEAVE + NS, HOVERABLEITEMS, that._toggleHover).on('focus' + NS, $.proxy(that._active, that)).on('blur' + NS, function () {
                    that._current(null);
                });
                that._keyDownProxy = $.proxy(that._keydown, that);
                if (options.navigatable) {
                    that.wrapper.on('keydown' + NS, that._keyDownProxy);
                }
                if (that.options.value) {
                    value = that.options.value;
                }
                that.wrapper.children('.k-tabstrip-items').on(CLICK + NS, '.k-state-disabled .k-link', false).on(CLICK + NS, ' > ' + NAVIGATABLEITEMS, function (e) {
                    var wr = that.wrapper[0];
                    if (wr !== document.activeElement) {
                        var msie = kendo.support.browser.msie;
                        if (msie) {
                            try {
                                wr.setActive();
                            } catch (j) {
                                wr.focus();
                            }
                        } else {
                            wr.focus();
                        }
                    }
                    if (that._click($(e.currentTarget))) {
                        e.preventDefault();
                    }
                });
                var selectedItems = that.tabGroup.children('li.' + ACTIVESTATE), content = that.contentHolder(selectedItems.index());
                if (selectedItems[0] && content.length > 0 && content[0].childNodes.length === 0) {
                    that.activateTab(selectedItems.eq(0));
                }
                that.element.attr('role', 'tablist');
                if (that.element[0].id) {
                    that._ariaId = that.element[0].id + '_ts_active';
                }
                that.value(value);
                kendo.notify(that);
            },
            _active: function () {
                var item = this.tabGroup.children().filter('.' + ACTIVESTATE);
                item = item[0] ? item : this._endItem('first');
                if (item[0]) {
                    this._current(item);
                }
            },
            _endItem: function (action) {
                return this.tabGroup.children(NAVIGATABLEITEMS)[action]();
            },
            _item: function (item, action) {
                var endItem;
                if (action === PREV) {
                    endItem = 'last';
                } else {
                    endItem = 'first';
                }
                if (!item) {
                    return this._endItem(endItem);
                }
                item = item[action]();
                if (!item[0]) {
                    item = this._endItem(endItem);
                }
                if (item.hasClass(DISABLEDSTATE)) {
                    item = this._item(item, action);
                }
                return item;
            },
            _current: function (candidate) {
                var that = this, focused = that._focused, id = that._ariaId;
                if (candidate === undefined) {
                    return focused;
                }
                if (focused) {
                    if (focused[0].id === id) {
                        focused.removeAttr('id');
                    }
                    focused.removeClass(FOCUSEDSTATE);
                }
                if (candidate) {
                    if (!candidate.hasClass(ACTIVESTATE)) {
                        candidate.addClass(FOCUSEDSTATE);
                    }
                    that.element.removeAttr('aria-activedescendant');
                    id = candidate[0].id || id;
                    if (id) {
                        candidate.attr('id', id);
                        that.element.attr('aria-activedescendant', id);
                    }
                }
                that._focused = candidate;
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, current = that._current(), rtl = that._isRtl, action;
                if (e.target != e.currentTarget) {
                    return;
                }
                if (key == keys.DOWN || key == keys.RIGHT) {
                    action = rtl ? PREV : 'next';
                } else if (key == keys.UP || key == keys.LEFT) {
                    action = rtl ? 'next' : PREV;
                } else if (key == keys.ENTER || key == keys.SPACEBAR) {
                    that._click(current);
                    e.preventDefault();
                } else if (key == keys.HOME) {
                    that._click(that._endItem('first'));
                    e.preventDefault();
                    return;
                } else if (key == keys.END) {
                    that._click(that._endItem('last'));
                    e.preventDefault();
                    return;
                }
                if (action) {
                    that._click(that._item(current, action));
                    e.preventDefault();
                }
            },
            _dataSource: function () {
                var that = this;
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind('change', that._refreshHandler);
                } else {
                    that._refreshHandler = $.proxy(that.refresh, that);
                }
                that.dataSource = kendo.data.DataSource.create(that.options.dataSource).bind('change', that._refreshHandler);
            },
            setDataSource: function (dataSource) {
                var that = this;
                that.options.dataSource = dataSource;
                that._dataSource();
                that.dataSource.fetch();
            },
            _animations: function (options) {
                if (options && 'animation' in options && !options.animation) {
                    options.animation = {
                        open: { effects: {} },
                        close: { effects: {} }
                    };
                }
            },
            refresh: function (e) {
                var that = this, options = that.options, text = kendo.getter(options.dataTextField), content = kendo.getter(options.dataContentField), contentUrl = kendo.getter(options.dataContentUrlField), image = kendo.getter(options.dataImageUrlField), url = kendo.getter(options.dataUrlField), sprite = kendo.getter(options.dataSpriteCssClass), idx, tabs = [], tab, action, view = that.dataSource.view(), length;
                e = e || {};
                action = e.action;
                if (action) {
                    view = e.items;
                }
                for (idx = 0, length = view.length; idx < length; idx++) {
                    tab = { text: text(view[idx]) };
                    if (options.dataContentField) {
                        tab.content = content(view[idx]);
                    }
                    if (options.dataContentUrlField) {
                        tab.contentUrl = contentUrl(view[idx]);
                    }
                    if (options.dataUrlField) {
                        tab.url = url(view[idx]);
                    }
                    if (options.dataImageUrlField) {
                        tab.imageUrl = image(view[idx]);
                    }
                    if (options.dataSpriteCssClass) {
                        tab.spriteCssClass = sprite(view[idx]);
                    }
                    tabs[idx] = tab;
                }
                if (e.action == 'add') {
                    if (e.index < that.tabGroup.children().length) {
                        that.insertBefore(tabs, that.tabGroup.children().eq(e.index));
                    } else {
                        that.append(tabs);
                    }
                } else if (e.action == 'remove') {
                    for (idx = 0; idx < view.length; idx++) {
                        that.remove(e.index);
                    }
                } else if (e.action == 'itemchange') {
                    idx = that.dataSource.view().indexOf(view[0]);
                    if (e.field === options.dataTextField) {
                        that.tabGroup.children().eq(idx).find('.k-link').text(view[0].get(e.field));
                    }
                    if (e.field === options.dataUrlField) {
                        that._contentUrls[idx] = view[0].get(e.field);
                    }
                } else {
                    that.trigger('dataBinding');
                    that.remove('li');
                    that._contentUrls = [];
                    that.append(tabs);
                    that.trigger('dataBound');
                }
            },
            value: function (value) {
                var that = this;
                if (value !== undefined) {
                    if (value != that.value()) {
                        that.tabGroup.children().each(function () {
                            if ($.trim($(this).text()) == value) {
                                that.select(this);
                            }
                        });
                    }
                } else {
                    return that.select().text();
                }
            },
            items: function () {
                return this.tabGroup[0].children;
            },
            setOptions: function (options) {
                var that = this, animation = that.options.animation;
                that._animations(options);
                if (options.contentUrls) {
                    that._contentUrls = options.contentUrls;
                }
                options.animation = extend(true, animation, options.animation);
                if (options.navigatable) {
                    that.wrapper.on('keydown' + NS, that._keyDownProxy);
                } else {
                    that.wrapper.off('keydown' + NS, that._keyDownProxy);
                }
                Widget.fn.setOptions.call(that, options);
            },
            events: [
                SELECT,
                ACTIVATE,
                SHOW,
                ERROR,
                CONTENTLOAD,
                'change',
                'dataBinding',
                'dataBound'
            ],
            options: {
                name: 'TabStrip',
                dataTextField: '',
                dataContentField: '',
                dataImageUrlField: '',
                dataUrlField: '',
                dataSpriteCssClass: '',
                dataContentUrlField: '',
                tabPosition: 'top',
                animation: {
                    open: {
                        effects: 'expand:vertical fadeIn',
                        duration: 200
                    },
                    close: { duration: 200 }
                },
                collapsible: false,
                navigatable: true,
                contentUrls: false,
                scrollable: { distance: 200 }
            },
            destroy: function () {
                var that = this, scrollWrap = that.scrollWrap;
                Widget.fn.destroy.call(that);
                if (that._refreshHandler) {
                    that.dataSource.unbind('change', that._refreshHandler);
                }
                that.wrapper.off(NS);
                that.wrapper.children('.k-tabstrip-items').off(NS);
                if (that._scrollableModeActive) {
                    that._scrollPrevButton.off().remove();
                    that._scrollNextButton.off().remove();
                }
                kendo.destroy(that.wrapper);
                scrollWrap.children('.k-tabstrip').unwrap();
            },
            select: function (element) {
                var that = this;
                if (arguments.length === 0) {
                    return that.tabGroup.children('li.' + ACTIVESTATE);
                }
                if (!isNaN(element)) {
                    element = that.tabGroup.children().get(element);
                }
                element = that.tabGroup.find(element);
                $(element).each(function (index, item) {
                    item = $(item);
                    if (!item.hasClass(ACTIVESTATE) && !that.trigger(SELECT, {
                            item: item[0],
                            contentElement: that.contentHolder(item.index())[0]
                        })) {
                        that.activateTab(item);
                    }
                });
                return that;
            },
            enable: function (element, state) {
                this._toggleDisabled(element, state !== false);
                return this;
            },
            disable: function (element) {
                this._toggleDisabled(element, false);
                return this;
            },
            reload: function (element) {
                element = this.tabGroup.find(element);
                var that = this;
                var contentUrls = that._contentUrls;
                element.each(function () {
                    var item = $(this), contentUrl = item.find('.' + LINK).data(CONTENTURL) || contentUrls[item.index()], content = that.contentHolder(item.index());
                    if (contentUrl) {
                        that.ajaxRequest(item, content, null, contentUrl);
                    }
                });
                return that;
            },
            append: function (tab) {
                var that = this, inserted = that._create(tab);
                each(inserted.tabs, function (idx) {
                    var contents = inserted.contents[idx];
                    that.tabGroup.append(this);
                    if (that.options.tabPosition == 'bottom') {
                        that.tabGroup.before(contents);
                    } else if (that._scrollableModeActive) {
                        that._scrollPrevButton.before(contents);
                    } else {
                        that.wrapper.append(contents);
                    }
                    that.angular('compile', function () {
                        return { elements: [contents] };
                    });
                });
                updateFirstLast(that.tabGroup);
                that._updateContentElements();
                that.resize(true);
                return that;
            },
            _appendUrlItem: function (url) {
                this._contentUrls.push(url);
            },
            _moveUrlItem: function (from, to) {
                this._contentUrls.splice(to, 0, this._contentUrls.splice(from, 1)[0]);
            },
            _removeUrlItem: function (index) {
                this._contentUrls.splice(index, 1);
            },
            insertBefore: function (tab, referenceTab) {
                if ($(tab).is($(referenceTab))) {
                    referenceTab = this.tabGroup.find(referenceTab).next();
                } else {
                    referenceTab = this.tabGroup.find(referenceTab);
                }
                var that = this, inserted = that._create(tab), referenceContent = that.element.find('#' + referenceTab.attr('aria-controls'));
                each(inserted.tabs, function (idx) {
                    var contents = inserted.contents[idx];
                    var fromIndex = inserted.newTabsCreated ? that._contentUrls.length - (inserted.tabs.length - idx) : $(contents).index() - 1;
                    referenceTab.before(this);
                    referenceContent.before(contents);
                    that._moveUrlItem(fromIndex, $(this).index());
                    that.angular('compile', function () {
                        return { elements: [contents] };
                    });
                });
                updateFirstLast(that.tabGroup);
                that._updateContentElements(inserted.newTabsCreated);
                that.resize(true);
                return that;
            },
            insertAfter: function (tab, referenceTab) {
                if ($(tab).is($(referenceTab))) {
                    referenceTab = this.tabGroup.find(referenceTab).prev();
                } else {
                    referenceTab = this.tabGroup.find(referenceTab);
                }
                var that = this, inserted = that._create(tab), referenceContent = that.element.find('#' + referenceTab.attr('aria-controls'));
                each(inserted.tabs, function (idx) {
                    var contents = inserted.contents[idx];
                    var fromIndex = inserted.newTabsCreated ? that._contentUrls.length - (inserted.tabs.length - idx) : $(contents).index() - 1;
                    referenceTab.after(this);
                    referenceContent.after(contents);
                    that._moveUrlItem(fromIndex, $(this).index());
                    that.angular('compile', function () {
                        return { elements: [contents] };
                    });
                });
                updateFirstLast(that.tabGroup);
                that._updateContentElements(inserted.newTabsCreated);
                that.resize(true);
                return that;
            },
            remove: function (elements) {
                var that = this;
                var type = typeof elements;
                var contents;
                if (type === 'string') {
                    elements = that.tabGroup.find(elements);
                } else if (type === 'number') {
                    elements = that.tabGroup.children().eq(elements);
                }
                contents = elements.map(function () {
                    var idx = $(this).index();
                    var content = that.contentElement(idx);
                    kendo.destroy(content);
                    that._removeUrlItem(idx);
                    return content;
                });
                elements.remove();
                contents.empty();
                contents.remove();
                that._updateContentElements();
                that.resize(true);
                return that;
            },
            _create: function (tab) {
                var that = this, tabs, contents, content, newTabsCreated = false;
                tab = tab instanceof kendo.data.ObservableArray ? tab.toJSON() : tab;
                if ($.isPlainObject(tab) || $.isArray(tab)) {
                    tab = $.isArray(tab) ? tab : [tab];
                    newTabsCreated = true;
                    tabs = map(tab, function (value, idx) {
                        that._appendUrlItem(tab[idx].contentUrl || null);
                        return $(TabStrip.renderItem({
                            group: that.tabGroup,
                            item: extend(value, { index: idx })
                        }));
                    });
                    contents = map(tab, function (value, idx) {
                        if (typeof value.content == 'string' || value.contentUrl) {
                            return $(TabStrip.renderContent({ item: extend(value, { index: idx }) }));
                        }
                    });
                } else {
                    if (typeof tab == 'string' && tab[0] != '<') {
                        tabs = that.element.find(tab);
                    } else {
                        tabs = $(tab);
                    }
                    contents = $();
                    tabs.each(function () {
                        if (/k-tabstrip-items/.test(this.parentNode.className)) {
                            var element = that.element.find('#' + this.getAttribute('aria-controls'));
                            content = element;
                        } else {
                            content = $('<div class=\'' + CONTENT + '\'/>');
                        }
                        contents = contents.add(content);
                    });
                    updateTabClasses(tabs);
                }
                return {
                    tabs: tabs,
                    contents: contents,
                    newTabsCreated: newTabsCreated
                };
            },
            _toggleDisabled: function (element, enable) {
                element = this.tabGroup.find(element);
                element.each(function () {
                    $(this).toggleClass(DEFAULTSTATE, enable).toggleClass(DISABLEDSTATE, !enable);
                });
            },
            _updateClasses: function () {
                var that = this, tabs, activeItem, activeTab;
                that.wrapper.addClass('k-widget k-header k-tabstrip');
                that.tabGroup = that.wrapper.children('ul').addClass('k-tabstrip-items k-reset');
                if (!that.tabGroup[0]) {
                    that.tabGroup = $('<ul class=\'k-tabstrip-items k-reset\'/>').appendTo(that.wrapper);
                }
                tabs = that.tabGroup.find('li').addClass('k-item');
                if (tabs.length) {
                    activeItem = tabs.filter('.' + ACTIVESTATE).index();
                    activeTab = activeItem >= 0 ? activeItem : undefined;
                    that.tabGroup.contents().filter(function () {
                        return this.nodeType == 3 && !trim(this.nodeValue);
                    }).remove();
                }
                if (activeItem >= 0) {
                    tabs.eq(activeItem).addClass(TABONTOP);
                }
                that.contentElements = that.wrapper.children('div');
                that.contentElements.addClass(CONTENT).eq(activeTab).addClass(ACTIVESTATE).css({ display: 'block' });
                if (tabs.length) {
                    updateTabClasses(tabs);
                    updateFirstLast(that.tabGroup);
                    that._updateContentElements(true);
                }
            },
            _elementId: function (element, idx) {
                var elementId = element.attr('id');
                var wrapperId = this.element.attr('id');
                if (!elementId || elementId.indexOf(wrapperId + '-') > -1) {
                    var tabStripID = (wrapperId || kendo.guid()) + '-';
                    return tabStripID + (idx + 1);
                }
                return elementId;
            },
            _updateContentElements: function (isInitialUpdate) {
                var that = this, contentUrls = that._contentUrls, items = that.tabGroup.children('.k-item'), contentElements = that.wrapper.children('div'), _elementId = that._elementId.bind(that);
                if (contentElements.length && items.length > contentElements.length) {
                    contentElements.each(function (idx) {
                        var id = _elementId($(this), idx);
                        var item = items.filter('[aria-controls=' + (this.id || 0) + ']')[0];
                        if (!item && isInitialUpdate) {
                            item = items[idx];
                        }
                        if (item) {
                            item.setAttribute('aria-controls', id);
                        }
                        this.setAttribute('id', id);
                    });
                } else {
                    items.each(function (idx) {
                        var currentContent = contentElements.eq(idx);
                        var id = _elementId(currentContent, idx);
                        this.setAttribute('aria-controls', id);
                        if (!currentContent.length && contentUrls[idx]) {
                            $('<div class=\'' + CONTENT + '\'/>').appendTo(that.wrapper).attr('id', id);
                        } else {
                            currentContent.attr('id', id);
                            if (!$(this).children('.k-loading')[0] && !contentUrls[idx]) {
                                $('<span class=\'k-loading k-complete\'/>').prependTo(this);
                            }
                        }
                        currentContent.attr('role', 'tabpanel');
                        currentContent.filter(':not(.' + ACTIVESTATE + ')').attr('aria-hidden', true).attr('aria-expanded', false);
                        currentContent.filter('.' + ACTIVESTATE).attr('aria-expanded', true);
                    });
                }
                that.contentElements = that.contentAnimators = that.wrapper.children('div');
                that.tabsHeight = outerHeight(that.tabGroup) + parseInt(that.wrapper.css('border-top-width'), 10) + parseInt(that.wrapper.css('border-bottom-width'), 10);
                if (kendo.kineticScrollNeeded && kendo.mobile.ui.Scroller) {
                    kendo.touchScroller(that.contentElements);
                    that.contentElements = that.contentElements.children('.km-scroll-container');
                }
            },
            _wrapper: function () {
                var that = this;
                if (that.element.is('ul')) {
                    that.wrapper = that.element.wrapAll('<div />').parent();
                } else {
                    that.wrapper = that.element;
                }
                that.scrollWrap = that.wrapper.parent('.k-tabstrip-wrapper');
                if (!that.scrollWrap[0]) {
                    that.scrollWrap = that.wrapper.wrapAll('<div class=\'k-tabstrip-wrapper\' />').parent();
                }
            },
            _tabPosition: function () {
                var that = this, tabPosition = that.options.tabPosition;
                that.wrapper.addClass('k-floatwrap k-tabstrip-' + tabPosition);
                if (tabPosition == 'bottom') {
                    that.tabGroup.appendTo(that.wrapper);
                }
                that.resize(true);
            },
            _setContentElementsDimensions: function () {
                var that = this, tabPosition = that.options.tabPosition;
                if (tabPosition == 'left' || tabPosition == 'right') {
                    var contentDivs = that.wrapper.children('.k-content'), activeDiv = contentDivs.filter(':visible'), marginStyleProperty = 'margin-' + tabPosition, tabGroup = that.tabGroup, margin = outerWidth(tabGroup);
                    var minHeight = Math.ceil(tabGroup.height()) - parseInt(activeDiv.css('padding-top'), 10) - parseInt(activeDiv.css('padding-bottom'), 10) - parseInt(activeDiv.css('border-top-width'), 10) - parseInt(activeDiv.css('border-bottom-width'), 10);
                    setTimeout(function () {
                        contentDivs.css(marginStyleProperty, margin).css('min-height', minHeight);
                    });
                }
            },
            _resize: function () {
                this._setContentElementsDimensions();
                this._scrollable();
            },
            _sizeScrollWrap: function (element) {
                if (element.is(':visible')) {
                    var tabPosition = this.options.tabPosition;
                    var h = Math.floor(outerHeight(element, true)) + (tabPosition === 'left' || tabPosition === 'right' ? 2 : this.tabsHeight);
                    this.scrollWrap.css('height', h).css('height');
                }
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVERSTATE, e.type == MOUSEENTER);
            },
            _click: function (item) {
                var that = this, link = item.find('.' + LINK), href = link.attr(HREF), collapse = that.options.collapsible, index = item.index(), contentHolder = that.contentHolder(index), prevent, isAnchor;
                if (item.closest('.k-widget')[0] != that.wrapper[0]) {
                    return;
                }
                if (item.is('.' + DISABLEDSTATE + (!collapse ? ',.' + ACTIVESTATE : ''))) {
                    return true;
                }
                isAnchor = link.data(CONTENTURL) || that._contentUrls[index] || href && (href.charAt(href.length - 1) == '#' || href.indexOf('#' + that.element[0].id + '-') != -1);
                prevent = !href || isAnchor;
                if (that.tabGroup.children('[data-animating]').length) {
                    return prevent;
                }
                if (that.trigger(SELECT, {
                        item: item[0],
                        contentElement: contentHolder[0]
                    })) {
                    return true;
                }
                if (prevent === false) {
                    return;
                }
                if (collapse && item.is('.' + ACTIVESTATE)) {
                    that.deactivateTab(item);
                    return true;
                }
                if (that.activateTab(item)) {
                    prevent = true;
                }
                return prevent;
            },
            _scrollable: function () {
                var that = this, options = that.options, wrapperOffsetWidth, tabGroupScrollWidth, scrollPrevButton, scrollNextButton;
                if (that._scrollableAllowed()) {
                    that.wrapper.addClass('k-tabstrip-scrollable');
                    wrapperOffsetWidth = that.wrapper[0].offsetWidth;
                    tabGroupScrollWidth = that.tabGroup[0].scrollWidth;
                    if (tabGroupScrollWidth > wrapperOffsetWidth && !that._scrollableModeActive) {
                        that._nowScrollingTabs = false;
                        that._isRtl = kendo.support.isRtl(that.element);
                        var mouseDown = kendo.support.mobileOS ? 'touchstart' : 'mousedown';
                        var mouseUp = kendo.support.mobileOS ? 'touchend' : 'mouseup';
                        that.wrapper.append(scrollButtonHtml('prev', 'k-i-arrow-60-left') + scrollButtonHtml('next', 'k-i-arrow-60-right'));
                        scrollPrevButton = that._scrollPrevButton = that.wrapper.children('.k-tabstrip-prev');
                        scrollNextButton = that._scrollNextButton = that.wrapper.children('.k-tabstrip-next');
                        that.tabGroup.css({
                            marginLeft: outerWidth(scrollPrevButton) + 9,
                            marginRight: outerWidth(scrollNextButton) + 12
                        });
                        scrollPrevButton.on(mouseDown + NS, function () {
                            that._nowScrollingTabs = true;
                            that._scrollTabsByDelta(options.scrollable.distance * (that._isRtl ? 1 : -1));
                        });
                        scrollNextButton.on(mouseDown + NS, function () {
                            that._nowScrollingTabs = true;
                            that._scrollTabsByDelta(options.scrollable.distance * (that._isRtl ? -1 : 1));
                        });
                        scrollPrevButton.add(scrollNextButton).on(mouseUp + NS, function () {
                            that._nowScrollingTabs = false;
                        });
                        that._scrollableModeActive = true;
                        that._toggleScrollButtons();
                    } else if (that._scrollableModeActive && tabGroupScrollWidth <= wrapperOffsetWidth) {
                        that._scrollableModeActive = false;
                        that.wrapper.removeClass('k-tabstrip-scrollable');
                        that._scrollPrevButton.off().remove();
                        that._scrollNextButton.off().remove();
                        that.tabGroup.css({
                            marginLeft: '',
                            marginRight: ''
                        });
                    } else if (!that._scrollableModeActive) {
                        that.wrapper.removeClass('k-tabstrip-scrollable');
                    } else {
                        that._toggleScrollButtons();
                    }
                }
            },
            _scrollableAllowed: function () {
                var options = this.options;
                return options.scrollable && !isNaN(options.scrollable.distance) && (options.tabPosition == 'top' || options.tabPosition == 'bottom');
            },
            _scrollTabsToItem: function (item) {
                var that = this, tabGroup = that.tabGroup, currentScrollOffset = tabGroup.scrollLeft(), itemWidth = outerWidth(item), itemOffset = that._isRtl ? item.position().left : item.position().left - tabGroup.children().first().position().left, tabGroupWidth = tabGroup[0].offsetWidth, tabGroupPadding = Math.ceil(parseFloat(tabGroup.css('padding-left'))), itemPosition;
                if (that._isRtl) {
                    if (itemOffset < 0) {
                        itemPosition = currentScrollOffset + itemOffset - (tabGroupWidth - currentScrollOffset) - tabGroupPadding;
                    } else if (itemOffset + itemWidth > tabGroupWidth) {
                        itemPosition = currentScrollOffset + itemOffset - itemWidth + tabGroupPadding * 2;
                    }
                } else {
                    if (currentScrollOffset + tabGroupWidth < itemOffset + itemWidth) {
                        itemPosition = itemOffset + itemWidth - tabGroupWidth + tabGroupPadding * 2;
                    } else if (currentScrollOffset > itemOffset) {
                        itemPosition = itemOffset - tabGroupPadding;
                    }
                }
                tabGroup.finish().animate({ 'scrollLeft': itemPosition }, 'fast', 'linear', function () {
                    that._toggleScrollButtons();
                });
            },
            _scrollTabsByDelta: function (delta) {
                var that = this;
                var tabGroup = that.tabGroup;
                var scrLeft = tabGroup.scrollLeft();
                tabGroup.finish().animate({ 'scrollLeft': scrLeft + delta }, 'fast', 'linear', function () {
                    if (that._nowScrollingTabs) {
                        that._scrollTabsByDelta(delta);
                    } else {
                        that._toggleScrollButtons();
                    }
                });
            },
            _toggleScrollButtons: function () {
                var that = this, ul = that.tabGroup, scrollLeft = ul.scrollLeft();
                that._scrollPrevButton.toggle(that._isRtl ? scrollLeft < ul[0].scrollWidth - ul[0].offsetWidth - 1 : scrollLeft !== 0);
                that._scrollNextButton.toggle(that._isRtl ? scrollLeft !== 0 : scrollLeft < ul[0].scrollWidth - ul[0].offsetWidth - 1);
            },
            deactivateTab: function (item) {
                var that = this, animationSettings = that.options.animation, animation = animationSettings.open, close = extend({}, animationSettings.close), hasCloseAnimation = close && 'effects' in close;
                item = that.tabGroup.find(item);
                close = extend(hasCloseAnimation ? close : extend({ reverse: true }, animation), { hide: true });
                if (kendo.size(animation.effects)) {
                    item.kendoAddClass(DEFAULTSTATE, { duration: animation.duration });
                    item.kendoRemoveClass(ACTIVESTATE, { duration: animation.duration });
                } else {
                    item.addClass(DEFAULTSTATE);
                    item.removeClass(ACTIVESTATE);
                }
                item.removeAttr('aria-selected');
                that.contentAnimators.filter('.' + ACTIVESTATE).kendoStop(true, true).kendoAnimate(close).removeClass(ACTIVESTATE).attr('aria-hidden', true);
            },
            activateTab: function (item) {
                if (this.tabGroup.children('[data-animating]').length) {
                    return;
                }
                item = this.tabGroup.find(item);
                var that = this, animationSettings = that.options.animation, animation = animationSettings.open, close = extend({}, animationSettings.close), hasCloseAnimation = close && 'effects' in close, neighbours = item.parent().children(), oldTab = neighbours.filter('.' + ACTIVESTATE), itemIndex = neighbours.index(item);
                close = extend(hasCloseAnimation ? close : extend({ reverse: true }, animation), { hide: true });
                if (kendo.size(animation.effects)) {
                    oldTab.kendoRemoveClass(ACTIVESTATE, { duration: close.duration });
                    item.kendoRemoveClass(HOVERSTATE, { duration: close.duration });
                } else {
                    oldTab.removeClass(ACTIVESTATE);
                    item.removeClass(HOVERSTATE);
                }
                var contentAnimators = that.contentAnimators;
                if (that.inRequest) {
                    that.xhr.abort();
                    that.inRequest = false;
                }
                if (contentAnimators.length === 0) {
                    that.tabGroup.find('.' + TABONTOP).removeClass(TABONTOP);
                    item.addClass(TABONTOP).css('z-index');
                    item.addClass(ACTIVESTATE);
                    that._current(item);
                    that.trigger('change');
                    if (that._scrollableModeActive) {
                        that._scrollTabsToItem(item);
                    }
                    return false;
                }
                var visibleContents = contentAnimators.filter('.' + ACTIVESTATE), contentHolder = that.contentHolder(itemIndex), contentElement = contentHolder.closest('.k-content');
                that.tabsHeight = outerHeight(that.tabGroup) + parseInt(that.wrapper.css('border-top-width'), 10) + parseInt(that.wrapper.css('border-bottom-width'), 10);
                that._sizeScrollWrap(visibleContents);
                if (contentHolder.length === 0) {
                    visibleContents.removeClass(ACTIVESTATE).attr('aria-hidden', true).kendoStop(true, true).kendoAnimate(close);
                    return false;
                }
                item.attr('data-animating', true);
                var isAjaxContent = (item.children('.' + LINK).data(CONTENTURL) || that._contentUrls[itemIndex] || false) && contentHolder.is(EMPTY), showContentElement = function () {
                        that.tabGroup.find('.' + TABONTOP).removeClass(TABONTOP);
                        item.addClass(TABONTOP).css('z-index');
                        if (kendo.size(animation.effects)) {
                            oldTab.kendoAddClass(DEFAULTSTATE, { duration: animation.duration });
                            item.kendoAddClass(ACTIVESTATE, { duration: animation.duration });
                        } else {
                            oldTab.addClass(DEFAULTSTATE);
                            item.addClass(ACTIVESTATE);
                        }
                        oldTab.removeAttr('aria-selected');
                        item.attr('aria-selected', true);
                        that._current(item);
                        that._sizeScrollWrap(contentElement);
                        contentElement.addClass(ACTIVESTATE).removeAttr('aria-hidden').kendoStop(true, true).attr('aria-expanded', true).kendoAnimate(extend({
                            init: function () {
                                that.trigger(SHOW, {
                                    item: item[0],
                                    contentElement: contentHolder[0]
                                });
                                kendo.resize(contentHolder);
                            }
                        }, animation, {
                            complete: function () {
                                item.removeAttr('data-animating');
                                that.trigger(ACTIVATE, {
                                    item: item[0],
                                    contentElement: contentHolder[0]
                                });
                                kendo.resize(contentHolder);
                                that.scrollWrap.css('height', '').css('height');
                            }
                        }));
                    }, showContent = function () {
                        if (!isAjaxContent) {
                            showContentElement();
                            that.trigger('change');
                        } else {
                            item.removeAttr('data-animating');
                            that.ajaxRequest(item, contentHolder, function () {
                                item.attr('data-animating', true);
                                showContentElement();
                                that.trigger('change');
                            });
                        }
                        if (that._scrollableModeActive) {
                            that._scrollTabsToItem(item);
                        }
                    };
                visibleContents.removeClass(ACTIVESTATE);
                visibleContents.attr('aria-hidden', true);
                visibleContents.attr('aria-expanded', false);
                if (visibleContents.length) {
                    visibleContents.kendoStop(true, true).kendoAnimate(extend({ complete: showContent }, close));
                } else {
                    showContent();
                }
                return true;
            },
            contentElement: function (itemIndex) {
                if (isNaN(itemIndex - 0)) {
                    return undefined;
                }
                var contentElements = this.contentElements && this.contentElements[0] && !kendo.kineticScrollNeeded ? this.contentElements : this.contentAnimators;
                var id = $(this.tabGroup.children()[itemIndex]).attr('aria-controls');
                if (contentElements) {
                    for (var i = 0, len = contentElements.length; i < len; i++) {
                        if (contentElements.eq(i).closest('.k-content')[0].id == id) {
                            return contentElements[i];
                        }
                    }
                }
                return undefined;
            },
            contentHolder: function (itemIndex) {
                var contentElement = $(this.contentElement(itemIndex)), scrollContainer = contentElement.children('.km-scroll-container');
                return kendo.support.touch && scrollContainer[0] ? scrollContainer : contentElement;
            },
            ajaxRequest: function (element, content, complete, url) {
                element = this.tabGroup.find(element);
                var that = this, xhr = $.ajaxSettings.xhr, link = element.find('.' + LINK), data = {}, halfWidth = element.width() / 2, fakeProgress = false, statusIcon = element.find('.k-loading').removeClass('k-complete');
                if (!statusIcon[0]) {
                    statusIcon = $('<span class=\'k-loading\'/>').prependTo(element);
                }
                var endState = halfWidth * 2 - statusIcon.width();
                var oldProgressAnimation = function () {
                    statusIcon.animate({ marginLeft: (parseInt(statusIcon.css('marginLeft'), 10) || 0) < halfWidth ? endState : 0 }, 500, oldProgressAnimation);
                };
                if (kendo.support.browser.msie && kendo.support.browser.version < 10) {
                    setTimeout(oldProgressAnimation, 40);
                }
                url = url || link.data(CONTENTURL) || that._contentUrls[element.index()] || link.attr(HREF);
                that.inRequest = true;
                var ajaxOptions = {
                    type: 'GET',
                    cache: false,
                    url: url,
                    dataType: 'html',
                    data: data,
                    xhr: function () {
                        var current = this, request = xhr(), event = current.progressUpload ? 'progressUpload' : current.progress ? 'progress' : false;
                        if (request) {
                            $.each([
                                request,
                                request.upload
                            ], function () {
                                if (this.addEventListener) {
                                    this.addEventListener('progress', function (evt) {
                                        if (event) {
                                            current[event](evt);
                                        }
                                    }, false);
                                }
                            });
                        }
                        current.noProgress = !(window.XMLHttpRequest && 'upload' in new XMLHttpRequest());
                        return request;
                    },
                    progress: function (evt) {
                        if (evt.lengthComputable) {
                            var percent = parseInt(evt.loaded / evt.total * 100, 10) + '%';
                            statusIcon.stop(true).addClass('k-progress').css({
                                'width': percent,
                                'marginLeft': 0
                            });
                        }
                    },
                    error: function (xhr, status) {
                        if (that.trigger('error', {
                                xhr: xhr,
                                status: status
                            })) {
                            this.complete();
                        }
                    },
                    stopProgress: function () {
                        clearInterval(fakeProgress);
                        statusIcon.stop(true).addClass('k-progress')[0].style.cssText = '';
                    },
                    complete: function (xhr) {
                        that.inRequest = false;
                        if (this.noProgress) {
                            setTimeout(this.stopProgress, 500);
                        } else {
                            this.stopProgress();
                        }
                        if (xhr.statusText == 'abort') {
                            statusIcon.remove();
                        }
                    },
                    success: function (data) {
                        statusIcon.addClass('k-complete');
                        try {
                            var current = this, loaded = 10;
                            if (current.noProgress) {
                                statusIcon.width(loaded + '%');
                                fakeProgress = setInterval(function () {
                                    current.progress({
                                        lengthComputable: true,
                                        loaded: Math.min(loaded, 100),
                                        total: 100
                                    });
                                    loaded += 10;
                                }, 40);
                            }
                            that.angular('cleanup', function () {
                                return { elements: content.get() };
                            });
                            kendo.destroy(content);
                            content.html(data);
                        } catch (e) {
                            var console = window.console;
                            if (console && console.error) {
                                console.error(e.name + ': ' + e.message + ' in ' + url);
                            }
                            this.error(this.xhr, 'error');
                        }
                        if (complete) {
                            complete.call(that, content);
                        }
                        that.angular('compile', function () {
                            return { elements: content.get() };
                        });
                        that.trigger(CONTENTLOAD, {
                            item: element[0],
                            contentElement: content[0]
                        });
                    }
                };
                if (typeof url === 'object') {
                    ajaxOptions = $.extend(true, {}, ajaxOptions, url);
                    if (isFunction(ajaxOptions.url)) {
                        ajaxOptions.url = ajaxOptions.url();
                    }
                }
                that.xhr = $.ajax(ajaxOptions);
            }
        });
        extend(TabStrip, {
            renderItem: function (options) {
                options = extend({
                    tabStrip: {},
                    group: {}
                }, options);
                var empty = templates.empty, item = options.item;
                return templates.item(extend(options, {
                    image: item.imageUrl ? templates.image : empty,
                    sprite: item.spriteCssClass ? templates.sprite : empty,
                    itemWrapper: templates.itemWrapper
                }, rendering));
            },
            renderContent: function (options) {
                return templates.content(extend(options, rendering));
            }
        });
        kendo.ui.plugin(TabStrip);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/undoredostack', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        var UndoRedoStack = kendo.Observable.extend({
            init: function (options) {
                kendo.Observable.fn.init.call(this, options);
                this.clear();
            },
            events: [
                'undo',
                'redo'
            ],
            push: function (command) {
                this.stack = this.stack.slice(0, this.currentCommandIndex + 1);
                this.currentCommandIndex = this.stack.push(command) - 1;
            },
            undo: function () {
                if (this.canUndo()) {
                    var command = this.stack[this.currentCommandIndex--];
                    command.undo();
                    this.trigger('undo', { command: command });
                }
            },
            redo: function () {
                if (this.canRedo()) {
                    var command = this.stack[++this.currentCommandIndex];
                    command.redo();
                    this.trigger('redo', { command: command });
                }
            },
            clear: function () {
                this.stack = [];
                this.currentCommandIndex = -1;
            },
            canUndo: function () {
                return this.currentCommandIndex >= 0;
            },
            canRedo: function () {
                return this.currentCommandIndex != this.stack.length - 1;
            }
        });
        kendo.deepExtend(kendo, { util: { UndoRedoStack: UndoRedoStack } });
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/main', [
        'util/undoredostack',
        'kendo.combobox',
        'kendo.dropdownlist',
        'kendo.window',
        'kendo.colorpicker'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, Widget = kendo.ui.Widget, os = kendo.support.mobileOS, browser = kendo.support.browser, extend = $.extend, proxy = $.proxy, deepExtend = kendo.deepExtend, keys = kendo.keys;
        var SELECT = 'select';
        var SELECT_OVERLAY_SELECTOR = 'select.k-select-overlay';
        var ToolTemplate = Class.extend({
            init: function (options) {
                this.options = options;
            },
            getHtml: function () {
                var options = this.options;
                return kendo.template(options.template, { useWithBlock: false })(options);
            }
        });
        var EditorUtils = {
            editorWrapperTemplate: '<table cellspacing="4" cellpadding="0" class="k-widget k-editor k-header" role="presentation"><tbody>' + '<tr role="presentation"><td class="k-editor-toolbar-wrap" role="presentation"><ul class="k-editor-toolbar" role="toolbar" /></td></tr>' + '<tr><td class="k-editable-area" /></tr>' + '</tbody></table>',
            buttonTemplate: '# var iconCssClass= "k-icon k-i-" + kendo.toHyphens(data.cssClass.replace("k-", ""));#' + '<a tabindex="0" role="button" class="k-tool"' + '#= data.popup ? " data-popup" : "" #' + ' unselectable="on" title="#= data.title #"><span unselectable="on" class="k-tool-icon #= iconCssClass #"></span><span class="k-tool-text">#= data.title #</span></a>',
            colorPickerTemplate: '<div class="k-colorpicker k-icon k-i-#= data.cssClass.replace("k-", "") #" />',
            comboBoxTemplate: '<select title="#= data.title #" class="#= data.cssClass #" />',
            dropDownListTemplate: '<span class="k-editor-dropdown"><select title="#= data.title #" class="#= data.cssClass #" /></span>',
            separatorTemplate: '<span class="k-separator" />',
            overflowAnchorTemplate: '<a tabindex="0" role="button" class="k-tool k-overflow-anchor" data-popup' + ' unselectable="on" title="#= data.title #" aria-haspopup="true" aria-expanded="false">' + '<span unselectable="on" class="k-icon k-i-more-vertical"></span><span class="k-tool-text">#= data.title #</span></a>',
            formatByName: function (name, format) {
                for (var i = 0; i < format.length; i++) {
                    if ($.inArray(name, format[i].tags) >= 0) {
                        return format[i];
                    }
                }
            },
            getToolCssClass: function (name) {
                var toolCssClassNames = {
                    superscript: 'sup-script',
                    subscript: 'sub-script',
                    justifyLeft: 'align-left',
                    justifyCenter: 'align-center',
                    justifyRight: 'align-right',
                    justifyFull: 'align-justify',
                    insertUnorderedList: 'list-unordered',
                    insertOrderedList: 'list-ordered',
                    'import': 'login',
                    indent: 'indent-increase',
                    outdent: 'indent-decrease',
                    createLink: 'link-horizontal',
                    unlink: 'unlink-horizontal',
                    insertImage: 'image',
                    insertFile: 'file-add',
                    viewHtml: 'html',
                    foreColor: 'foreground-color',
                    backColor: 'paint',
                    createTable: 'table-insert',
                    addColumnLeft: 'table-column-insert-left',
                    addColumnRight: 'table-column-insert-right',
                    addRowAbove: 'table-row-insert-above',
                    addRowBelow: 'table-row-insert-below',
                    deleteRow: 'table-row-delete',
                    deleteColumn: 'table-column-delete',
                    tableWizard: 'table-properties',
                    tableWizardInsert: 'table-wizard',
                    cleanFormatting: 'clear-css'
                };
                var cssClass = toolCssClassNames[name];
                if (cssClass) {
                    return cssClass;
                }
                return name;
            },
            registerTool: function (toolName, tool) {
                var toolOptions = tool.options;
                if (toolOptions && toolOptions.template) {
                    toolOptions.template.options.cssClass = 'k-' + EditorUtils.getToolCssClass(toolName);
                }
                if (!tool.name) {
                    tool.options.name = toolName;
                    tool.name = toolName.toLowerCase();
                }
                Editor.defaultTools[toolName] = tool;
            },
            registerFormat: function (formatName, format) {
                Editor.fn.options.formats[formatName] = format;
            }
        };
        var messages = {
            bold: 'Bold',
            italic: 'Italic',
            underline: 'Underline',
            strikethrough: 'Strikethrough',
            superscript: 'Superscript',
            subscript: 'Subscript',
            justifyCenter: 'Center text',
            justifyLeft: 'Align text left',
            justifyRight: 'Align text right',
            justifyFull: 'Justify',
            insertUnorderedList: 'Insert unordered list',
            insertOrderedList: 'Insert ordered list',
            indent: 'Indent',
            outdent: 'Outdent',
            createLink: 'Insert hyperlink',
            unlink: 'Remove hyperlink',
            insertImage: 'Insert image',
            insertFile: 'Insert file',
            insertHtml: 'Insert HTML',
            viewHtml: 'View HTML',
            fontName: 'Select font family',
            fontNameInherit: '(inherited font)',
            fontSize: 'Select font size',
            fontSizeInherit: '(inherited size)',
            formatBlock: 'Format',
            formatting: 'Format',
            foreColor: 'Color',
            backColor: 'Background color',
            style: 'Styles',
            emptyFolder: 'Empty Folder',
            editAreaTitle: 'Editable area. Press F10 for toolbar.',
            uploadFile: 'Upload',
            overflowAnchor: 'More tools',
            orderBy: 'Arrange by:',
            orderBySize: 'Size',
            orderByName: 'Name',
            invalidFileType: 'The selected file "{0}" is not valid. Supported file types are {1}.',
            deleteFile: 'Are you sure you want to delete "{0}"?',
            overwriteFile: 'A file with name "{0}" already exists in the current directory. Do you want to overwrite it?',
            directoryNotFound: 'A directory with this name was not found.',
            imageWebAddress: 'Web address',
            imageAltText: 'Alternate text',
            imageWidth: 'Width (px)',
            imageHeight: 'Height (px)',
            fileWebAddress: 'Web address',
            fileTitle: 'Title',
            fileText: 'Text',
            linkWebAddress: 'Web address',
            linkText: 'Text',
            linkToolTip: 'ToolTip',
            linkOpenInNewWindow: 'Open link in new window',
            dialogUpdate: 'Update',
            dialogInsert: 'Insert',
            dialogOk: 'Ok',
            dialogCancel: 'Cancel',
            cleanFormatting: 'Clean formatting',
            createTable: 'Create a table',
            createTableHint: 'Create a {0} x {1} table',
            addColumnLeft: 'Add column on the left',
            addColumnRight: 'Add column on the right',
            addRowAbove: 'Add row above',
            addRowBelow: 'Add row below',
            deleteRow: 'Delete row',
            deleteColumn: 'Delete column',
            tableWizard: 'Table Wizard',
            tableTab: 'Table',
            cellTab: 'Cell',
            accessibilityTab: 'Accessibility',
            caption: 'Caption',
            summary: 'Summary',
            width: 'Width',
            height: 'Height',
            units: 'Units',
            cellSpacing: 'Cell Spacing',
            cellPadding: 'Cell Padding',
            cellMargin: 'Cell Margin',
            alignment: 'Alignment',
            background: 'Background',
            cssClass: 'CSS Class',
            id: 'ID',
            border: 'Border',
            borderStyle: 'Border Style',
            collapseBorders: 'Collapse borders',
            wrapText: 'Wrap text',
            associateCellsWithHeaders: 'Associate cells with headers',
            alignLeft: 'Align Left',
            alignCenter: 'Align Center',
            alignRight: 'Align Right',
            alignLeftTop: 'Align Left Top',
            alignCenterTop: 'Align Center Top',
            alignRightTop: 'Align Right Top',
            alignLeftMiddle: 'Align Left Middle',
            alignCenterMiddle: 'Align Center Middle',
            alignRightMiddle: 'Align Right Middle',
            alignLeftBottom: 'Align Left Bottom',
            alignCenterBottom: 'Align Center Bottom',
            alignRightBottom: 'Align Right Bottom',
            alignRemove: 'Remove Alignment',
            columns: 'Columns',
            rows: 'Rows',
            selectAllCells: 'Select All Cells',
            exportAs: 'Export As',
            'import': 'Import'
        };
        var supportedBrowser = !os || os.ios && os.flatVersion >= 500 || !os.ios && typeof document.documentElement.contentEditable != 'undefined';
        var toolGroups = {
            basic: [
                'bold',
                'italic',
                'underline'
            ],
            alignment: [
                'justifyLeft',
                'justifyCenter',
                'justifyRight'
            ],
            lists: [
                'insertUnorderedList',
                'insertOrderedList'
            ],
            indenting: [
                'indent',
                'outdent'
            ],
            links: [
                'createLink',
                'unlink'
            ],
            tables: [
                'tableWizard',
                'createTable',
                'addColumnLeft',
                'addColumnRight',
                'addRowAbove',
                'addRowBelow',
                'deleteRow',
                'deleteColumn'
            ]
        };
        var Editor = Widget.extend({
            init: function (element, options) {
                var that = this, value, editorNS = kendo.ui.editor, toolbarContainer, toolbarOptions, type;
                var domElement;
                var dom = editorNS.Dom;
                if (!supportedBrowser) {
                    return;
                }
                Widget.fn.init.call(that, element, options);
                that.options = deepExtend({}, that.options, options);
                that.options.tools = that.options.tools.slice();
                element = that.element;
                domElement = element[0];
                type = dom.name(domElement);
                this._registerHandler(element.closest('form'), 'submit', proxy(that.update, that, undefined));
                toolbarOptions = extend({}, that.options);
                toolbarOptions.editor = that;
                if (type == 'textarea') {
                    that._wrapTextarea();
                    toolbarContainer = that.wrapper.find('.k-editor-toolbar');
                    if (domElement.id) {
                        toolbarContainer.attr('aria-controls', domElement.id);
                    }
                } else {
                    that.element.attr('contenteditable', true).addClass('k-widget k-editor k-editor-inline');
                    toolbarOptions.popup = true;
                    toolbarContainer = $('<ul class="k-editor-toolbar" role="toolbar" />').insertBefore(element);
                }
                that.toolbar = new editorNS.Toolbar(toolbarContainer[0], toolbarOptions);
                that.toolbar.bindTo(that);
                if (type == 'textarea') {
                    setTimeout(function () {
                        var heightStyle = that.wrapper[0].style.height;
                        var expectedHeight = parseInt(heightStyle, 10);
                        var actualHeight = that.wrapper.height();
                        if (heightStyle.indexOf('px') > 0 && !isNaN(expectedHeight) && actualHeight > expectedHeight) {
                            that.wrapper.height(expectedHeight - (actualHeight - expectedHeight));
                        }
                    });
                }
                that._resizable();
                that._initializeContentElement(that);
                that.keyboard = new editorNS.Keyboard([
                    new editorNS.BackspaceHandler(that),
                    new editorNS.TypingHandler(that),
                    new editorNS.SystemHandler(that),
                    new editorNS.SelectAllHandler(that)
                ]);
                that.clipboard = new editorNS.Clipboard(this);
                that.undoRedoStack = new kendo.util.UndoRedoStack();
                if (options && options.value) {
                    value = options.value;
                } else if (that.textarea) {
                    value = domElement.value;
                    if (that.options.encoded && $.trim(domElement.defaultValue).length) {
                        value = domElement.defaultValue;
                    }
                    value = value.replace(/[\r\n\v\f\t ]+/gi, ' ');
                } else {
                    value = domElement.innerHTML;
                }
                that.value(value || kendo.ui.editor.emptyElementContent);
                this._registerHandler(document, {
                    'mousedown': function () {
                        that._endTyping();
                    },
                    'mouseup': function (e) {
                        that._mouseup(e);
                    }
                });
                that._initializeImmutables();
                that.toolbar.resize();
                kendo.notify(that);
            },
            setOptions: function (options) {
                var editor = this;
                Widget.fn.setOptions.call(editor, options);
                if (options.tools) {
                    editor.toolbar.bindTo(editor);
                }
            },
            _endTyping: function () {
                var keyboard = this.keyboard;
                try {
                    if (keyboard.isTypingInProgress()) {
                        keyboard.endTyping(true);
                        this.saveSelection();
                    }
                } catch (e) {
                }
            },
            _selectionChange: function () {
                this._selectionStarted = false;
                this.saveSelection();
                this.trigger('select', {});
            },
            _resizable: function () {
                var resizable = this.options.resizable;
                var isResizable = $.isPlainObject(resizable) ? resizable.content === undefined || resizable.content === true : resizable;
                if (isResizable && this.textarea) {
                    $('<div class=\'k-resize-handle\'><span class=\'k-icon k-i-arrow-45-down-right\' /></div>').insertAfter(this.textarea);
                    this.wrapper.kendoResizable(extend({}, this.options.resizable, {
                        start: function (e) {
                            var editor = this.editor = $(e.currentTarget).closest('.k-editor');
                            this.initialSize = editor.height();
                            editor.find('td:last').append('<div class=\'k-overlay\' />');
                        },
                        resize: function (e) {
                            var delta = e.y.initialDelta;
                            var newSize = this.initialSize + delta;
                            var min = this.options.min || 0;
                            var max = this.options.max || Infinity;
                            newSize = Math.min(max, Math.max(min, newSize));
                            this.editor.height(newSize);
                        },
                        resizeend: function () {
                            this.editor.find('.k-overlay').remove();
                            this.editor = null;
                        }
                    }));
                    if (kendo.support.mobileOS.ios) {
                        var resizableWidget = this.wrapper.getKendoResizable();
                        resizableWidget.draggable.options.ignore = SELECT_OVERLAY_SELECTOR;
                    }
                }
            },
            _initializeTableResizing: function () {
                var editor = this;
                kendo.ui.editor.TableResizing.create(editor);
                editor._showTableResizeHandlesProxy = proxy(editor._showTableResizeHandles, editor);
                editor.bind(SELECT, editor._showTableResizeHandlesProxy);
            },
            _destroyTableResizing: function () {
                var editor = this;
                var tableResizing = editor.tableResizing;
                if (tableResizing) {
                    tableResizing.destroy();
                    editor.tableResizing = null;
                }
                if (editor._showTableResizeHandlesProxy) {
                    editor.unbind(SELECT, editor._showTableResizeHandlesProxy);
                }
            },
            _showTableResizeHandles: function () {
                var editor = this;
                var tableResizing = editor.tableResizing;
                if (tableResizing) {
                    tableResizing.showResizeHandles();
                }
            },
            _initializeColumnResizing: function () {
                kendo.ui.editor.ColumnResizing.create(this);
            },
            _destroyColumnResizing: function () {
                var editor = this;
                if (editor.columnResizing) {
                    editor.columnResizing.destroy();
                    editor.columnResizing = null;
                }
            },
            _initializeRowResizing: function () {
                kendo.ui.editor.RowResizing.create(this);
            },
            _destroyRowResizing: function () {
                var editor = this;
                if (editor.rowResizing) {
                    editor.rowResizing.destroy();
                    editor.rowResizing = null;
                }
            },
            _wrapTextarea: function () {
                var that = this, textarea = that.element, w = textarea[0].style.width, h = textarea[0].style.height, template = EditorUtils.editorWrapperTemplate, editorWrap = $(template).insertBefore(textarea).width(w).height(h), editArea = editorWrap.find('.k-editable-area');
                textarea.attr('autocomplete', 'off').appendTo(editArea).addClass('k-content k-raw-content').css('display', 'none');
                that.textarea = textarea;
                that.wrapper = editorWrap;
            },
            _createContentElement: function (stylesheets) {
                var editor = this;
                var iframe, wnd, doc;
                var textarea = editor.textarea;
                var specifiedDomain = editor.options.domain;
                var domain = specifiedDomain || document.domain;
                var domainScript = '';
                var src = 'javascript:""';
                if (specifiedDomain || domain != location.hostname) {
                    domainScript = '<script>document.domain="' + domain + '"</script>';
                    src = 'javascript:document.write(\'' + domainScript + '\')';
                }
                textarea.hide();
                iframe = $('<iframe />', {
                    title: editor.options.messages.editAreaTitle,
                    frameBorder: '0'
                })[0];
                $(iframe).css('display', '').addClass('k-content').attr('tabindex', textarea[0].tabIndex).insertBefore(textarea);
                iframe.src = src;
                wnd = iframe.contentWindow || iframe;
                doc = wnd.document || iframe.contentDocument;
                $(iframe).one('load', function () {
                    editor.toolbar.decorateFrom(doc.body);
                });
                doc.open();
                doc.write('<!DOCTYPE html><html><head>' + '<meta charset=\'utf-8\' />' + '<style>' + 'html,body{padding:0;margin:0;height:100%;min-height:100%;}' + 'body{box-sizing:border-box;font-size:12px;font-family:Verdana,Geneva,sans-serif;margin-top:-1px;padding:5px .4em 0;' + 'word-wrap: break-word;-webkit-nbsp-mode: space;-webkit-line-break: after-white-space;' + (kendo.support.isRtl(textarea) ? 'direction:rtl;' : '') + (browser.msie || browser.edge ? 'height:auto;' : '') + (os.ios ? 'word-break:break-all;' : '') + '}' + 'h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em}h3{font-size:1.16em}h4{font-size:1em}h5{font-size:.83em}h6{font-size:.7em}' + 'p{margin:0 0 1em;}.k-marker{display:none;}.k-paste-container,.Apple-style-span{position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden}' + 'ul,ol{padding-left:2.5em}' + 'span{-ms-high-contrast-adjust:none;}' + 'a{color:#00a}' + 'code{font-size:1.23em}' + 'telerik\\3Ascript{display: none;}' + '.k-table{width:100%;border-spacing:0;margin: 0 0 1em;}' + '.k-table td{min-width:1px;padding:.2em .3em;}' + '.k-table,.k-table td{outline:0;border: 1px dotted #ccc;}' + '.k-table p{margin:0;padding:0;}' + '.k-column-resize-handle-wrapper {position: absolute; height: 10px; width:10px; cursor: col-resize; z-index: 2;}' + '.k-column-resize-handle {width: 100%; height: 100%;}' + '.k-column-resize-handle > .k-column-resize-marker {width:2px; height:100%; margin:0 auto; background-color:#00b0ff; display:none; opacity:0.8;}' + '.k-row-resize-handle-wrapper {position: absolute; cursor: row-resize; z-index:2; width: 10px; height: 10px;}' + '.k-row-resize-handle {display: table; width: 100%; height: 100%;}' + '.k-row-resize-marker-wrapper{display: table-cell; height:100%; width:100%; margin:0; padding:0; vertical-align: middle;}' + '.k-row-resize-marker{margin: 0; padding:0; width:100%; height:2px; background-color: #00b0ff; opacity:0.8; display:none;}' + '.k-table-resize-handle-wrapper {position: absolute; background-color: #fff; border: 1px solid #000; z-index: 100; width: 5px; height: 5px;}' + '.k-table-resize-handle {width: 100%; height: 100%;}' + '.k-table-resize-handle.k-resize-east{cursor:e-resize;}' + '.k-table-resize-handle.k-resize-north{cursor:n-resize;}' + '.k-table-resize-handle.k-resize-northeast{cursor:ne-resize;}' + '.k-table-resize-handle.k-resize-northwest{cursor:nw-resize;}' + '.k-table-resize-handle.k-resize-south{cursor:s-resize;}' + '.k-table-resize-handle.k-resize-southeast{cursor:se-resize;}' + '.k-table-resize-handle.k-resize-southwest{cursor:sw-resize;}' + '.k-table-resize-handle.k-resize-west{cursor:w-resize;}' + '.k-table.k-table-resizing{opacity:0.6;}' + 'k\\:script{display:none;}' + '</style>' + domainScript + '<script>(function(d,c){d[c](\'header\'),d[c](\'article\'),d[c](\'nav\'),d[c](\'section\'),d[c](\'footer\');})(document, \'createElement\');</script>' + $.map(stylesheets, function (href) {
                    return '<link rel=\'stylesheet\' href=\'' + href + '\'>';
                }).join('') + '</head><body autocorrect=\'off\' contenteditable=\'true\'></body></html>');
                doc.close();
                return wnd;
            },
            _blur: function () {
                var textarea = this.textarea;
                var old = textarea ? textarea.val() : this._oldValue;
                var value = this.options.encoded ? this.encodedValue() : this.value();
                this.update();
                if (textarea) {
                    textarea.trigger('blur');
                }
                if (value != old) {
                    this.trigger('change');
                }
            },
            _spellCorrect: function (editor) {
                var beforeCorrection;
                var falseTrigger = false;
                this._registerHandler(editor.body, {
                    'contextmenu': function () {
                        editor.one('select', function () {
                            beforeCorrection = null;
                        });
                        editor._spellCorrectTimeout = setTimeout(function () {
                            beforeCorrection = new kendo.ui.editor.RestorePoint(editor.getRange(), editor.body);
                            falseTrigger = false;
                        }, 10);
                    },
                    'input': function () {
                        if (!beforeCorrection) {
                            return;
                        }
                        if (kendo.support.browser.mozilla && !falseTrigger) {
                            falseTrigger = true;
                            return;
                        }
                        kendo.ui.editor._finishUpdate(editor, beforeCorrection);
                    }
                });
            },
            _registerHandler: function (element, type, handler) {
                var editor = this;
                var NS = '.kendoEditor';
                var eventNames;
                var i;
                element = $(element);
                if (!this._handlers) {
                    this._handlers = [];
                }
                if (element.length) {
                    if ($.isPlainObject(type)) {
                        for (var t in type) {
                            if (type.hasOwnProperty(t)) {
                                this._registerHandler(element, t, type[t]);
                            }
                        }
                    } else {
                        eventNames = kendo.applyEventMap(type).split(' ');
                        for (i = 0; i < eventNames.length; i++) {
                            editor._handlers.push({
                                element: element,
                                type: eventNames[i] + NS,
                                handler: handler
                            });
                            element.on(eventNames[i] + NS, handler);
                        }
                    }
                }
            },
            _deregisterHandlers: function () {
                var handlers = this._handlers;
                for (var i = 0; i < handlers.length; i++) {
                    var h = handlers[i];
                    h.element.off(h.type, h.handler);
                }
                this._handlers = [];
            },
            _initializeContentElement: function () {
                var editor = this;
                var doc;
                var blurTrigger;
                var mousedownTrigger;
                if (editor.textarea) {
                    editor.window = editor._createContentElement(editor.options.stylesheets);
                    doc = editor.document = editor.window.contentDocument || editor.window.document;
                    editor.body = doc.body;
                    blurTrigger = editor.window;
                    mousedownTrigger = doc;
                    this._registerHandler(doc, 'mouseup', proxy(this._mouseup, this));
                } else {
                    editor.window = window;
                    doc = editor.document = document;
                    editor.body = editor.element[0];
                    blurTrigger = editor.body;
                    mousedownTrigger = editor.body;
                    editor.toolbar.decorateFrom(editor.body);
                }
                this._registerHandler(blurTrigger, 'blur', proxy(this._blur, this));
                editor._registerHandler(mousedownTrigger, 'down', proxy(editor._mousedown, editor));
                try {
                    doc.execCommand('enableInlineTableEditing', null, false);
                } catch (e) {
                }
                if (kendo.support.touch) {
                    this._registerHandler(doc, {
                        'keydown': function () {
                            if (kendo._activeElement() != doc.body) {
                                editor.window.focus();
                            }
                        }
                    });
                }
                this._spellCorrect(editor);
                this._registerHandler(editor.body, {
                    'keydown': function (e) {
                        var range;
                        if ((e.keyCode === keys.BACKSPACE || e.keyCode === keys.DELETE) && editor.body.getAttribute('contenteditable') !== 'true') {
                            return false;
                        }
                        if (e.keyCode === keys.F10) {
                            setTimeout(proxy(editor.toolbar.focus, editor.toolbar), 100);
                            e.preventDefault();
                            return;
                        } else if (e.keyCode == keys.LEFT || e.keyCode == keys.RIGHT) {
                            range = editor.getRange();
                            var left = e.keyCode == keys.LEFT;
                            var container = range[left ? 'startContainer' : 'endContainer'];
                            var offset = range[left ? 'startOffset' : 'endOffset'];
                            var direction = left ? -1 : 1;
                            var next = offset + direction;
                            var nextChar = left ? next : offset;
                            if (container.nodeType == 3 && container.nodeValue[nextChar] == '\uFEFF') {
                                range.setStart(container, next);
                                range.collapse(true);
                                editor.selectRange(range);
                            }
                        }
                        var tools = editor.toolbar.tools;
                        var toolName = editor.keyboard.toolFromShortcut(tools, e);
                        var toolOptions = toolName ? tools[toolName].options : {};
                        if (toolName && !toolOptions.keyPressCommand) {
                            e.preventDefault();
                            if (!/^(undo|redo)$/.test(toolName)) {
                                editor.keyboard.endTyping(true);
                            }
                            editor.trigger('keydown', e);
                            editor.exec(toolName);
                            editor._runPostContentKeyCommands(e);
                            return false;
                        }
                        editor.keyboard.clearTimeout();
                        editor.keyboard.keydown(e);
                    },
                    'keypress': function (e) {
                        setTimeout(function () {
                            editor._runPostContentKeyCommands(e);
                            editor._showTableResizeHandles();
                        }, 0);
                    },
                    'keyup': function (e) {
                        var selectionCodes = [
                            keys.BACKSPACE,
                            keys.TAB,
                            keys.PAGEUP,
                            keys.PAGEDOWN,
                            keys.END,
                            keys.HOME,
                            keys.LEFT,
                            keys.UP,
                            keys.RIGHT,
                            keys.DOWN,
                            keys.INSERT,
                            keys.DELETE
                        ];
                        if ($.inArray(e.keyCode, selectionCodes) > -1 || e.keyCode == 65 && e.ctrlKey && !e.altKey && !e.shiftKey) {
                            editor._selectionChange();
                        }
                        editor.keyboard.keyup(e);
                    },
                    'click': function (e) {
                        var dom = kendo.ui.editor.Dom, range;
                        if (dom.name(e.target) === 'img') {
                            range = editor.createRange();
                            range.selectNode(e.target);
                            editor.selectRange(range);
                        }
                    },
                    'cut copy paste': function (e) {
                        editor.clipboard['on' + e.type](e);
                    },
                    'focusin': function () {
                        if (editor.body.hasAttribute('contenteditable')) {
                            $(this).addClass('k-state-active');
                            editor.toolbar.show();
                        }
                    },
                    'focusout': function () {
                        setTimeout(function () {
                            var active = kendo._activeElement();
                            var body = editor.body;
                            var toolbar = editor.toolbar;
                            if (toolbar.options.popup) {
                                var toolbarContainerElement = toolbar.window.element.get(0);
                                if (toolbarContainerElement && !($.contains(toolbarContainerElement, active) || toolbarContainerElement == active)) {
                                    toolbar.preventPopupHide = false;
                                }
                            }
                            if (active != body && !$.contains(body, active) && !$(active).is('.k-editortoolbar-dragHandle') && !toolbar.focused()) {
                                $(body).removeClass('k-state-active');
                                toolbar.hide();
                            }
                        }, 10);
                    }
                });
                editor._initializeColumnResizing();
                editor._initializeRowResizing();
                editor._initializeTableResizing();
            },
            _initializeImmutables: function () {
                var that = this, editorNS = kendo.ui.editor;
                if (that.options.immutables) {
                    that.immutables = new editorNS.Immutables(that);
                }
            },
            _mousedown: function (e) {
                var editor = this;
                editor._selectionStarted = true;
                if (browser.gecko) {
                    return;
                }
                var target = $(e.target);
                if ((e.which == 2 || e.which == 1 && e.ctrlKey) && target.is('a[href]')) {
                    window.open(target.attr('href'), '_new');
                }
            },
            _mouseup: function (e) {
                var that = this;
                if (kendo.support.mobileOS.ios && e && $(e.target).is(SELECT_OVERLAY_SELECTOR)) {
                    return;
                }
                if (that._selectionStarted) {
                    setTimeout(function () {
                        that._selectionChange();
                    }, 1);
                }
            },
            _runPostContentKeyCommands: function (e) {
                var range = this.getRange();
                var tools = this.keyboard.toolsFromShortcut(this.toolbar.tools, e);
                for (var i = 0; i < tools.length; i++) {
                    var tool = tools[i];
                    var o = tool.options;
                    if (!o.keyPressCommand) {
                        continue;
                    }
                    var cmd = new o.command({ range: range });
                    if (cmd.changesContent()) {
                        this.keyboard.endTyping(true);
                        this.exec(tool.name);
                    }
                }
            },
            refresh: function () {
                var that = this;
                if (that.textarea) {
                    that._destroyResizings();
                    var value = that.value();
                    that.textarea.val(value);
                    that.wrapper.find('iframe').remove();
                    that._initializeContentElement(that);
                    that.value(value);
                }
            },
            events: [
                'select',
                'change',
                'execute',
                'error',
                'paste',
                'keydown',
                'keyup'
            ],
            options: {
                name: 'Editor',
                messages: messages,
                formats: {},
                encoded: true,
                domain: null,
                resizable: false,
                deserialization: { custom: null },
                serialization: {
                    entities: true,
                    semantic: true,
                    scripts: false
                },
                pasteCleanup: {
                    all: false,
                    css: false,
                    custom: null,
                    keepNewLines: false,
                    msAllFormatting: false,
                    msConvertLists: true,
                    msTags: true,
                    none: false,
                    span: false
                },
                stylesheets: [],
                dialogOptions: {
                    modal: true,
                    resizable: false,
                    draggable: true,
                    animation: false
                },
                imageBrowser: null,
                fileBrowser: null,
                fontName: [
                    {
                        text: 'Arial',
                        value: 'Arial,Helvetica,sans-serif'
                    },
                    {
                        text: 'Courier New',
                        value: '\'Courier New\',Courier,monospace'
                    },
                    {
                        text: 'Georgia',
                        value: 'Georgia,serif'
                    },
                    {
                        text: 'Impact',
                        value: 'Impact,Charcoal,sans-serif'
                    },
                    {
                        text: 'Lucida Console',
                        value: '\'Lucida Console\',Monaco,monospace'
                    },
                    {
                        text: 'Tahoma',
                        value: 'Tahoma,Geneva,sans-serif'
                    },
                    {
                        text: 'Times New Roman',
                        value: '\'Times New Roman\',Times,serif'
                    },
                    {
                        text: 'Trebuchet MS',
                        value: '\'Trebuchet MS\',Helvetica,sans-serif'
                    },
                    {
                        text: 'Verdana',
                        value: 'Verdana,Geneva,sans-serif'
                    }
                ],
                fontSize: [
                    {
                        text: '1 (8pt)',
                        value: 'xx-small'
                    },
                    {
                        text: '2 (10pt)',
                        value: 'x-small'
                    },
                    {
                        text: '3 (12pt)',
                        value: 'small'
                    },
                    {
                        text: '4 (14pt)',
                        value: 'medium'
                    },
                    {
                        text: '5 (18pt)',
                        value: 'large'
                    },
                    {
                        text: '6 (24pt)',
                        value: 'x-large'
                    },
                    {
                        text: '7 (36pt)',
                        value: 'xx-large'
                    }
                ],
                formatBlock: [
                    {
                        text: 'Paragraph',
                        value: 'p'
                    },
                    {
                        text: 'Quotation',
                        value: 'blockquote'
                    },
                    {
                        text: 'Heading 1',
                        value: 'h1'
                    },
                    {
                        text: 'Heading 2',
                        value: 'h2'
                    },
                    {
                        text: 'Heading 3',
                        value: 'h3'
                    },
                    {
                        text: 'Heading 4',
                        value: 'h4'
                    },
                    {
                        text: 'Heading 5',
                        value: 'h5'
                    },
                    {
                        text: 'Heading 6',
                        value: 'h6'
                    }
                ],
                tools: [].concat.call(['formatting'], toolGroups.basic, toolGroups.alignment, toolGroups.lists, toolGroups.indenting, toolGroups.links, ['insertImage'], toolGroups.tables)
            },
            destroy: function () {
                var editor = this;
                Widget.fn.destroy.call(this);
                this._endTyping(true);
                this._deregisterHandlers();
                clearTimeout(this._spellCorrectTimeout);
                this._focusOutside();
                this.toolbar.destroy();
                editor._destroyUploadWidget();
                editor._destroyResizings();
                kendo.destroy(this.wrapper);
            },
            _destroyResizings: function () {
                var editor = this;
                editor._destroyTableResizing();
                kendo.ui.editor.TableResizing.dispose(editor);
                editor._destroyRowResizing();
                kendo.ui.editor.RowResizing.dispose(editor);
                editor._destroyColumnResizing();
                kendo.ui.editor.ColumnResizing.dispose(editor);
            },
            _focusOutside: function () {
                if (kendo.support.browser.msie && this.textarea) {
                    var tempInput = $('<input style=\'position:fixed;left:1px;top:1px;width:1px;height:1px;font-size:0;border:0;opacity:0\' />').appendTo(document.body).focus();
                    tempInput.blur().remove();
                }
            },
            _destroyUploadWidget: function () {
                var editor = this;
                if (editor._uploadWidget) {
                    editor._uploadWidget.destroy();
                    editor._uploadWidget = null;
                }
            },
            state: function (toolName) {
                var tool = Editor.defaultTools[toolName];
                var finder = tool && (tool.options.finder || tool.finder);
                var RangeUtils = kendo.ui.editor.RangeUtils;
                var range, textNodes;
                if (finder) {
                    range = this.getRange();
                    textNodes = RangeUtils.textNodes(range);
                    if (!textNodes.length && range.collapsed) {
                        textNodes = [range.startContainer];
                    }
                    return finder.getFormat ? finder.getFormat(textNodes) : finder.isFormatted(textNodes);
                }
                return false;
            },
            value: function (html) {
                var body = this.body, editorNS = kendo.ui.editor, options = this.options, currentHtml = editorNS.Serializer.domToXhtml(body, options.serialization);
                if (html === undefined) {
                    return currentHtml;
                }
                if (html == currentHtml) {
                    return;
                }
                editorNS.Serializer.htmlToDom(html, body, options.deserialization);
                this.selectionRestorePoint = null;
                this.update();
                this.toolbar.refreshTools();
            },
            saveSelection: function (range) {
                range = range || this.getRange();
                var container = range.commonAncestorContainer, body = this.body;
                if (container == body || $.contains(body, container)) {
                    this.selectionRestorePoint = new kendo.ui.editor.RestorePoint(range, body);
                }
            },
            _focusBody: function () {
                var body = this.body;
                var iframe = this.wrapper && this.wrapper.find('iframe')[0];
                var documentElement = this.document.documentElement;
                var activeElement = kendo._activeElement();
                var scrollTop;
                if (iframe) {
                    if (activeElement != body && activeElement != iframe) {
                        scrollTop = documentElement.scrollTop;
                        body.focus();
                        documentElement.scrollTop = scrollTop;
                    }
                } else {
                    scrollTop = body.scrollTop;
                    body.focus();
                    body.scrollTop = scrollTop;
                }
            },
            restoreSelection: function () {
                this._focusBody();
                if (this.selectionRestorePoint) {
                    this.selectRange(this.selectionRestorePoint.toRange());
                }
            },
            focus: function () {
                this.restoreSelection();
            },
            update: function (value) {
                value = value || this.options.encoded ? this.encodedValue() : this.value();
                if (this.textarea) {
                    this.textarea.val(value);
                } else {
                    this._oldValue = value;
                }
            },
            encodedValue: function () {
                return kendo.ui.editor.Dom.encode(this.value());
            },
            createRange: function (document) {
                return kendo.ui.editor.RangeUtils.createRange(document || this.document);
            },
            getSelection: function () {
                return kendo.ui.editor.SelectionUtils.selectionFromDocument(this.document);
            },
            selectRange: function (range) {
                this._focusBody();
                var selection = this.getSelection();
                selection.removeAllRanges();
                selection.addRange(range);
                this.saveSelection(range);
            },
            getRange: function () {
                var selection = this.getSelection(), range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : this.createRange(), doc = this.document;
                if (range.startContainer == doc && range.endContainer == doc && !range.startOffset && !range.endOffset) {
                    range.setStart(this.body, 0);
                    range.collapse(true);
                }
                return range;
            },
            _containsRange: function (range) {
                var dom = kendo.ui.editor.Dom;
                var body = this.body;
                return range && dom.isAncestorOrSelf(body, range.startContainer) && dom.isAncestorOrSelf(body, range.endContainer);
            },
            selectedHtml: function () {
                return kendo.ui.editor.Serializer.domToXhtml(this.getRange().cloneContents());
            },
            paste: function (html, options) {
                this.focus();
                var command = new kendo.ui.editor.InsertHtmlCommand($.extend({
                    range: this.getRange(),
                    html: html
                }, options));
                command.editor = this;
                command.exec();
            },
            exec: function (name, params) {
                var that = this;
                var command = null;
                var range, tool, prevented;
                if (!name) {
                    throw new Error('kendoEditor.exec(): `name` parameter cannot be empty');
                }
                if (that.body.getAttribute('contenteditable') !== 'true' && name !== 'print' && name !== 'pdf') {
                    return false;
                }
                name = name.toLowerCase();
                if (!that.keyboard.isTypingInProgress()) {
                    that._focusBody();
                    that.selectRange(that._range || that.getRange());
                }
                tool = that.toolbar.toolById(name);
                if (!tool) {
                    for (var id in Editor.defaultTools) {
                        if (id.toLowerCase() == name) {
                            tool = Editor.defaultTools[id];
                            break;
                        }
                    }
                }
                if (tool) {
                    range = that.getRange();
                    if (tool.command) {
                        command = tool.command(extend({
                            range: range,
                            body: that.body,
                            immutables: !!that.immutables
                        }, params));
                    }
                    prevented = that.trigger('execute', {
                        name: name,
                        command: command
                    });
                    if (prevented) {
                        return;
                    }
                    if (/^(undo|redo)$/i.test(name)) {
                        that.undoRedoStack[name]();
                    } else if (command) {
                        that.execCommand(command);
                        if (command.async) {
                            command.change = proxy(that._selectionChange, that);
                            return;
                        }
                    }
                    that._selectionChange();
                }
            },
            execCommand: function (command) {
                if (!command.managesUndoRedo) {
                    this.undoRedoStack.push(command);
                }
                command.editor = this;
                command.exec();
            }
        });
        Editor.defaultTools = {
            undo: {
                options: {
                    key: 'Z',
                    ctrl: true
                }
            },
            redo: {
                options: {
                    key: 'Y',
                    ctrl: true
                }
            }
        };
        kendo.ui.plugin(Editor);
        var Tool = Class.extend({
            init: function (options) {
                this.options = options;
            },
            initialize: function (ui, options) {
                ui.attr({
                    unselectable: 'on',
                    title: options.title
                });
                ui.children('.k-tool-text').html(options.title);
            },
            command: function (commandArguments) {
                return new this.options.command(commandArguments);
            },
            update: $.noop
        });
        Tool.exec = function (editor, name, value) {
            editor.exec(name, { value: value });
        };
        var FormatTool = Tool.extend({
            init: function (options) {
                Tool.fn.init.call(this, options);
            },
            command: function (commandArguments) {
                var that = this;
                return new kendo.ui.editor.FormatCommand(extend(commandArguments, { formatter: that.options.formatter }));
            },
            update: function (ui, nodes) {
                var isFormatted = this.options.finder.isFormatted(nodes);
                ui.toggleClass('k-state-selected', isFormatted);
                ui.attr('aria-pressed', isFormatted);
            }
        });
        EditorUtils.registerTool('separator', new Tool({ template: new ToolTemplate({ template: EditorUtils.separatorTemplate }) }));
        var bomFill = browser.msie && browser.version < 9 ? '\uFEFF' : '';
        var emptyElementContent = '\uFEFF';
        var emptyTableCellContent = emptyElementContent;
        if (browser.msie && browser.version == 10) {
            emptyTableCellContent = '&nbsp;';
        }
        extend(kendo.ui, {
            editor: {
                ToolTemplate: ToolTemplate,
                EditorUtils: EditorUtils,
                Tool: Tool,
                FormatTool: FormatTool,
                _bomFill: bomFill,
                emptyElementContent: emptyElementContent,
                emptyTableCellContent: emptyTableCellContent
            }
        });
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Editor.prototype);
            Editor.prototype._drawPDF = function () {
                return kendo.drawing.drawDOM(this.body, this.options.pdf);
            };
            Editor.prototype.saveAsPDF = function () {
                var progress = new $.Deferred();
                var promise = progress.promise();
                var args = { promise: promise };
                if (this.trigger('pdfExport', args)) {
                    return;
                }
                var options = this.options.pdf;
                this._drawPDF(progress).then(function (root) {
                    return kendo.drawing.exportPDF(root, options);
                }).done(function (dataURI) {
                    kendo.saveAs({
                        dataURI: dataURI,
                        fileName: options.fileName,
                        proxyURL: options.proxyURL,
                        forceProxy: options.forceProxy
                    });
                    progress.resolve();
                }).fail(function (err) {
                    progress.reject(err);
                });
                return promise;
            };
        }
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/dom', ['editor/main'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, map = $.map, extend = $.extend, browser = kendo.support.browser, STYLE = 'style', FLOAT = 'float', CSSFLOAT = 'cssFloat', STYLEFLOAT = 'styleFloat', CLASS = 'class', KMARKER = 'k-marker';
        function makeMap(items) {
            var obj = {}, i, len;
            for (i = 0, len = items.length; i < len; i++) {
                obj[items[i]] = true;
            }
            return obj;
        }
        var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'.split(',')), nonListBlockElements = 'div,p,h1,h2,h3,h4,h5,h6,address,applet,blockquote,button,center,dd,dir,dl,dt,fieldset,form,frameset,hr,iframe,isindex,map,menu,noframes,noscript,object,pre,script,table,tbody,td,tfoot,th,thead,tr,header,article,nav,footer,section,aside,main,figure,figcaption'.split(','), blockElements = nonListBlockElements.concat([
                'ul',
                'ol',
                'li'
            ]), block = makeMap(blockElements), inlineElements = 'span,em,a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,strike,strong,sub,sup,textarea,tt,u,var,data,time,mark,ruby'.split(','), inline = makeMap(inlineElements), fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'.split(','));
        var normalize = function (node) {
            if (node.nodeType == 1) {
                node.normalize();
            }
        };
        if (browser.msie && browser.version >= 8) {
            normalize = function (parent) {
                if (parent.nodeType == 1 && parent.firstChild) {
                    var prev = parent.firstChild, node = prev;
                    while (true) {
                        node = node.nextSibling;
                        if (!node) {
                            break;
                        }
                        if (node.nodeType == 3 && prev.nodeType == 3) {
                            node.nodeValue = prev.nodeValue + node.nodeValue;
                            Dom.remove(prev);
                        }
                        prev = node;
                    }
                }
            };
        }
        var whitespace = /^\s+$/, emptyspace = /^[\n\r\t]+$/, rgb = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i, bom = /\ufeff/g, whitespaceOrBom = /^(\s+|\ufeff)$/, persistedScrollTop, cssAttributes = ('color,padding-left,padding-right,padding-top,padding-bottom,' + 'background-color,background-attachment,background-image,background-position,background-repeat,' + 'border-top-style,border-top-width,border-top-color,' + 'border-bottom-style,border-bottom-width,border-bottom-color,' + 'border-left-style,border-left-width,border-left-color,' + 'border-right-style,border-right-width,border-right-color,' + 'font-family,font-size,font-style,font-variant,font-weight,line-height').split(','), htmlRe = /[<>\&]/g, entityRe = /[\u00A0-\u2666<>\&]/g, entityTable = {
                34: 'quot',
                38: 'amp',
                39: 'apos',
                60: 'lt',
                62: 'gt',
                160: 'nbsp',
                161: 'iexcl',
                162: 'cent',
                163: 'pound',
                164: 'curren',
                165: 'yen',
                166: 'brvbar',
                167: 'sect',
                168: 'uml',
                169: 'copy',
                170: 'ordf',
                171: 'laquo',
                172: 'not',
                173: 'shy',
                174: 'reg',
                175: 'macr',
                176: 'deg',
                177: 'plusmn',
                178: 'sup2',
                179: 'sup3',
                180: 'acute',
                181: 'micro',
                182: 'para',
                183: 'middot',
                184: 'cedil',
                185: 'sup1',
                186: 'ordm',
                187: 'raquo',
                188: 'frac14',
                189: 'frac12',
                190: 'frac34',
                191: 'iquest',
                192: 'Agrave',
                193: 'Aacute',
                194: 'Acirc',
                195: 'Atilde',
                196: 'Auml',
                197: 'Aring',
                198: 'AElig',
                199: 'Ccedil',
                200: 'Egrave',
                201: 'Eacute',
                202: 'Ecirc',
                203: 'Euml',
                204: 'Igrave',
                205: 'Iacute',
                206: 'Icirc',
                207: 'Iuml',
                208: 'ETH',
                209: 'Ntilde',
                210: 'Ograve',
                211: 'Oacute',
                212: 'Ocirc',
                213: 'Otilde',
                214: 'Ouml',
                215: 'times',
                216: 'Oslash',
                217: 'Ugrave',
                218: 'Uacute',
                219: 'Ucirc',
                220: 'Uuml',
                221: 'Yacute',
                222: 'THORN',
                223: 'szlig',
                224: 'agrave',
                225: 'aacute',
                226: 'acirc',
                227: 'atilde',
                228: 'auml',
                229: 'aring',
                230: 'aelig',
                231: 'ccedil',
                232: 'egrave',
                233: 'eacute',
                234: 'ecirc',
                235: 'euml',
                236: 'igrave',
                237: 'iacute',
                238: 'icirc',
                239: 'iuml',
                240: 'eth',
                241: 'ntilde',
                242: 'ograve',
                243: 'oacute',
                244: 'ocirc',
                245: 'otilde',
                246: 'ouml',
                247: 'divide',
                248: 'oslash',
                249: 'ugrave',
                250: 'uacute',
                251: 'ucirc',
                252: 'uuml',
                253: 'yacute',
                254: 'thorn',
                255: 'yuml',
                402: 'fnof',
                913: 'Alpha',
                914: 'Beta',
                915: 'Gamma',
                916: 'Delta',
                917: 'Epsilon',
                918: 'Zeta',
                919: 'Eta',
                920: 'Theta',
                921: 'Iota',
                922: 'Kappa',
                923: 'Lambda',
                924: 'Mu',
                925: 'Nu',
                926: 'Xi',
                927: 'Omicron',
                928: 'Pi',
                929: 'Rho',
                931: 'Sigma',
                932: 'Tau',
                933: 'Upsilon',
                934: 'Phi',
                935: 'Chi',
                936: 'Psi',
                937: 'Omega',
                945: 'alpha',
                946: 'beta',
                947: 'gamma',
                948: 'delta',
                949: 'epsilon',
                950: 'zeta',
                951: 'eta',
                952: 'theta',
                953: 'iota',
                954: 'kappa',
                955: 'lambda',
                956: 'mu',
                957: 'nu',
                958: 'xi',
                959: 'omicron',
                960: 'pi',
                961: 'rho',
                962: 'sigmaf',
                963: 'sigma',
                964: 'tau',
                965: 'upsilon',
                966: 'phi',
                967: 'chi',
                968: 'psi',
                969: 'omega',
                977: 'thetasym',
                978: 'upsih',
                982: 'piv',
                8226: 'bull',
                8230: 'hellip',
                8242: 'prime',
                8243: 'Prime',
                8254: 'oline',
                8260: 'frasl',
                8472: 'weierp',
                8465: 'image',
                8476: 'real',
                8482: 'trade',
                8501: 'alefsym',
                8592: 'larr',
                8593: 'uarr',
                8594: 'rarr',
                8595: 'darr',
                8596: 'harr',
                8629: 'crarr',
                8656: 'lArr',
                8657: 'uArr',
                8658: 'rArr',
                8659: 'dArr',
                8660: 'hArr',
                8704: 'forall',
                8706: 'part',
                8707: 'exist',
                8709: 'empty',
                8711: 'nabla',
                8712: 'isin',
                8713: 'notin',
                8715: 'ni',
                8719: 'prod',
                8721: 'sum',
                8722: 'minus',
                8727: 'lowast',
                8730: 'radic',
                8733: 'prop',
                8734: 'infin',
                8736: 'ang',
                8743: 'and',
                8744: 'or',
                8745: 'cap',
                8746: 'cup',
                8747: 'int',
                8756: 'there4',
                8764: 'sim',
                8773: 'cong',
                8776: 'asymp',
                8800: 'ne',
                8801: 'equiv',
                8804: 'le',
                8805: 'ge',
                8834: 'sub',
                8835: 'sup',
                8836: 'nsub',
                8838: 'sube',
                8839: 'supe',
                8853: 'oplus',
                8855: 'otimes',
                8869: 'perp',
                8901: 'sdot',
                8968: 'lceil',
                8969: 'rceil',
                8970: 'lfloor',
                8971: 'rfloor',
                9001: 'lang',
                9002: 'rang',
                9674: 'loz',
                9824: 'spades',
                9827: 'clubs',
                9829: 'hearts',
                9830: 'diams',
                338: 'OElig',
                339: 'oelig',
                352: 'Scaron',
                353: 'scaron',
                376: 'Yuml',
                710: 'circ',
                732: 'tilde',
                8194: 'ensp',
                8195: 'emsp',
                8201: 'thinsp',
                8204: 'zwnj',
                8205: 'zwj',
                8206: 'lrm',
                8207: 'rlm',
                8211: 'ndash',
                8212: 'mdash',
                8216: 'lsquo',
                8217: 'rsquo',
                8218: 'sbquo',
                8220: 'ldquo',
                8221: 'rdquo',
                8222: 'bdquo',
                8224: 'dagger',
                8225: 'Dagger',
                8240: 'permil',
                8249: 'lsaquo',
                8250: 'rsaquo',
                8364: 'euro'
            };
        var Dom = {
            block: block,
            inline: inline,
            findNodeIndex: function (node, skipText) {
                var i = 0;
                if (!node) {
                    return -1;
                }
                while (true) {
                    node = node.previousSibling;
                    if (!node) {
                        break;
                    }
                    if (!(skipText && node.nodeType == 3)) {
                        i++;
                    }
                }
                return i;
            },
            isDataNode: function (node) {
                return node && node.nodeValue !== null && node.data !== null;
            },
            isAncestorOf: function (parent, node) {
                try {
                    return !Dom.isDataNode(parent) && ($.contains(parent, Dom.isDataNode(node) ? node.parentNode : node) || node.parentNode == parent);
                } catch (e) {
                    return false;
                }
            },
            isAncestorOrSelf: function (root, node) {
                return Dom.isAncestorOf(root, node) || root == node;
            },
            findClosestAncestor: function (root, node) {
                if (Dom.isAncestorOf(root, node)) {
                    while (node && node.parentNode != root) {
                        node = node.parentNode;
                    }
                }
                return node;
            },
            getNodeLength: function (node) {
                return Dom.isDataNode(node) ? node.length : node.childNodes.length;
            },
            splitDataNode: function (node, offset) {
                var newNode = node.cloneNode(false);
                var denormalizedText = '';
                var iterator = node.nextSibling;
                var temp;
                while (iterator && iterator.nodeType == 3 && iterator.nodeValue) {
                    denormalizedText += iterator.nodeValue;
                    temp = iterator;
                    iterator = iterator.nextSibling;
                    Dom.remove(temp);
                }
                node.deleteData(offset, node.length);
                newNode.deleteData(0, offset);
                newNode.nodeValue += denormalizedText;
                Dom.insertAfter(newNode, node);
            },
            attrEquals: function (node, attributes) {
                for (var key in attributes) {
                    var value = node[key];
                    if (key == FLOAT) {
                        value = node[kendo.support.cssFloat ? CSSFLOAT : STYLEFLOAT];
                    }
                    if (typeof value == 'object') {
                        if (!Dom.attrEquals(value, attributes[key])) {
                            return false;
                        }
                    } else if (value != attributes[key]) {
                        return false;
                    }
                }
                return true;
            },
            blockParentOrBody: function (node) {
                return Dom.parentOfType(node, blockElements) || node.ownerDocument.body;
            },
            blockParents: function (nodes) {
                var blocks = [], i, len;
                for (i = 0, len = nodes.length; i < len; i++) {
                    var block = Dom.parentOfType(nodes[i], Dom.blockElements);
                    if (block && $.inArray(block, blocks) < 0) {
                        blocks.push(block);
                    }
                }
                return blocks;
            },
            windowFromDocument: function (document) {
                return document.defaultView || document.parentWindow;
            },
            normalize: normalize,
            blockElements: blockElements,
            nonListBlockElements: nonListBlockElements,
            inlineElements: inlineElements,
            empty: empty,
            fillAttrs: fillAttrs,
            nodeTypes: {
                ELEMENT_NODE: 1,
                ATTRIBUTE_NODE: 2,
                TEXT_NODE: 3,
                CDATA_SECTION_NODE: 4,
                ENTITY_REFERENCE_NODE: 5,
                ENTITY_NODE: 6,
                PROCESSING_INSTRUCTION_NODE: 7,
                COMMENT_NODE: 8,
                DOCUMENT_NODE: 9,
                DOCUMENT_TYPE_NODE: 10,
                DOCUMENT_FRAGMENT_NODE: 11,
                NOTATION_NODE: 12
            },
            toHex: function (color) {
                var matches = rgb.exec(color);
                if (!matches) {
                    return color;
                }
                return '#' + map(matches.slice(1), function (x) {
                    x = parseInt(x, 10).toString(16);
                    return x.length > 1 ? x : '0' + x;
                }).join('');
            },
            encode: function (value, options) {
                var encodableChars = !options || options.entities ? entityRe : htmlRe;
                return value.replace(encodableChars, function (c) {
                    var charCode = c.charCodeAt(0);
                    var entity = entityTable[charCode];
                    return entity ? '&' + entity + ';' : c;
                });
            },
            isBom: function (node) {
                return node && node.nodeType === 3 && /^[\ufeff]+$/.test(node.nodeValue);
            },
            stripBom: function (text) {
                return (text || '').replace(bom, '');
            },
            stripBomNode: function (node) {
                if (Dom.isBom(node)) {
                    node.parentNode.removeChild(node);
                }
            },
            insignificant: function (node) {
                var attr = node.attributes;
                return node.className == 'k-marker' || Dom.is(node, 'br') && (node.className == 'k-br' || attr._moz_dirty || attr._moz_editor_bogus_node);
            },
            tableCell: function (node) {
                return Dom.is(node, 'td') || Dom.is(node, 'th');
            },
            significantNodes: function (nodes) {
                return $.grep(nodes, function (child) {
                    var name = Dom.name(child);
                    if (name == 'br') {
                        return false;
                    } else if (Dom.insignificant(child)) {
                        return false;
                    } else if (Dom.emptyTextNode(child)) {
                        return false;
                    } else if (child.nodeType == 1 && !empty[name] && Dom.emptyNode(child)) {
                        return false;
                    }
                    return true;
                });
            },
            emptyTextNode: function (node) {
                return node && node.nodeType == 3 && whitespaceOrBom.test(node.nodeValue);
            },
            emptyNode: function (node) {
                return node.nodeType == 1 && !Dom.significantNodes(node.childNodes).length;
            },
            name: function (node) {
                return node.nodeName.toLowerCase();
            },
            significantChildNodes: function (node) {
                return $.grep(node.childNodes, function (child) {
                    return child.nodeType != 3 || !Dom.isWhitespace(child);
                });
            },
            lastTextNode: function (node) {
                var result = null;
                if (node.nodeType == 3) {
                    return node;
                }
                for (var child = node.lastChild; child; child = child.previousSibling) {
                    result = Dom.lastTextNode(child);
                    if (result) {
                        return result;
                    }
                }
                return result;
            },
            is: function (node, nodeName) {
                return node && Dom.name(node) == nodeName;
            },
            isMarker: function (node) {
                return node.className == KMARKER;
            },
            isWhitespace: function (node) {
                return whitespace.test(node.nodeValue);
            },
            allWhitespaceContent: function (node) {
                var child = node.firstChild;
                while (child && Dom.isWhitespace(child)) {
                    child = child.nextSibling;
                }
                return !child;
            },
            isEmptyspace: function (node) {
                return emptyspace.test(node.nodeValue);
            },
            htmlIndentSpace: function (node) {
                if (!(Dom.isDataNode(node) && Dom.isWhitespace(node))) {
                    return false;
                }
                if (emptyspace.test(node.nodeValue)) {
                    return true;
                }
                var sibling = function (el, direction) {
                    while (el[direction]) {
                        el = el[direction];
                        if (Dom.significantNodes([el]).length > 0) {
                            return el;
                        }
                    }
                };
                var parent = node.parentNode;
                var prev = sibling(node, 'previousSibling');
                var next = sibling(node, 'nextSibling');
                if (bom.test(node.nodeValue)) {
                    return !!(prev || next);
                }
                if ($(parent).is('tr,tbody,thead,tfoot,table,ol,ul')) {
                    return true;
                }
                if (Dom.isBlock(parent) || Dom.is(parent, 'body')) {
                    var isPrevBlock = prev && Dom.isBlock(prev);
                    var isNextBlock = next && Dom.isBlock(next);
                    if (!next && isPrevBlock || !prev && isNextBlock || isPrevBlock && isNextBlock) {
                        return true;
                    }
                }
                return false;
            },
            isBlock: function (node) {
                return block[Dom.name(node)];
            },
            isEmpty: function (node) {
                return empty[Dom.name(node)];
            },
            isInline: function (node) {
                return inline[Dom.name(node)];
            },
            list: function (node) {
                var name = node ? Dom.name(node) : '';
                return name == 'ul' || name == 'ol' || name == 'dl';
            },
            scrollContainer: function (doc) {
                var wnd = Dom.windowFromDocument(doc), scrollContainer = (wnd.contentWindow || wnd).document || wnd.ownerDocument || wnd;
                if (kendo.support.browser.webkit || scrollContainer.compatMode == 'BackCompat') {
                    scrollContainer = scrollContainer.body;
                } else {
                    scrollContainer = scrollContainer.documentElement;
                }
                return scrollContainer;
            },
            scrollTo: function (node) {
                var element = $(Dom.isDataNode(node) ? node.parentNode : node), wnd = Dom.windowFromDocument(node.ownerDocument), windowHeight = wnd.innerHeight, elementTop, elementHeight, scrollContainer = Dom.scrollContainer(node.ownerDocument);
                elementTop = element.offset().top;
                elementHeight = element[0].offsetHeight;
                if (!elementHeight) {
                    elementHeight = parseInt(element.css('line-height'), 10) || Math.ceil(1.2 * parseInt(element.css('font-size'), 10)) || 15;
                }
                if (elementHeight + elementTop > scrollContainer.scrollTop + windowHeight) {
                    scrollContainer.scrollTop = elementHeight + elementTop - windowHeight;
                }
            },
            persistScrollTop: function (doc) {
                persistedScrollTop = Dom.scrollContainer(doc).scrollTop;
            },
            offset: function (target, offsetParent) {
                var result = {
                    top: target.offsetTop,
                    left: target.offsetLeft
                };
                var parent = target.offsetParent;
                while (parent && (!offsetParent || Dom.isAncestorOf(offsetParent, parent))) {
                    result.top += parent.offsetTop;
                    result.left += parent.offsetLeft;
                    parent = parent.offsetParent;
                }
                return result;
            },
            restoreScrollTop: function (doc) {
                if (typeof persistedScrollTop == 'number') {
                    Dom.scrollContainer(doc).scrollTop = persistedScrollTop;
                }
            },
            insertAt: function (parent, newElement, position) {
                parent.insertBefore(newElement, parent.childNodes[position] || null);
            },
            insertBefore: function (newElement, referenceElement) {
                if (referenceElement.parentNode) {
                    return referenceElement.parentNode.insertBefore(newElement, referenceElement);
                } else {
                    return referenceElement;
                }
            },
            insertAfter: function (newElement, referenceElement) {
                return referenceElement.parentNode.insertBefore(newElement, referenceElement.nextSibling);
            },
            remove: function (node) {
                if (node.parentNode) {
                    node.parentNode.removeChild(node);
                }
            },
            removeChildren: function (node) {
                while (node.firstChild) {
                    node.removeChild(node.firstChild);
                }
            },
            removeTextSiblings: function (node) {
                var parentNode = node.parentNode;
                while (node.nextSibling && node.nextSibling.nodeType == 3) {
                    parentNode.removeChild(node.nextSibling);
                }
                while (node.previousSibling && node.previousSibling.nodeType == 3) {
                    parentNode.removeChild(node.previousSibling);
                }
            },
            trim: function (parent) {
                for (var i = parent.childNodes.length - 1; i >= 0; i--) {
                    var node = parent.childNodes[i];
                    if (Dom.isDataNode(node)) {
                        if (!Dom.stripBom(node.nodeValue).length) {
                            Dom.remove(node);
                        }
                    } else if (node.className != KMARKER) {
                        Dom.trim(node);
                        if (node.childNodes.length === 0 || Dom.allWhitespaceContent(node) && Dom.isBlock(node) && !Dom.isEmpty(node)) {
                            Dom.remove(node);
                        }
                    }
                }
                return parent;
            },
            closest: function (node, tag) {
                while (node && Dom.name(node) != tag) {
                    node = node.parentNode;
                }
                return node;
            },
            closestBy: function (node, condition, rootCondition) {
                while (node && !condition(node)) {
                    if (rootCondition && rootCondition(node)) {
                        return null;
                    }
                    node = node.parentNode;
                }
                return node;
            },
            sibling: function (node, direction) {
                do {
                    node = node[direction];
                } while (node && node.nodeType != 1);
                return node;
            },
            next: function (node) {
                return Dom.sibling(node, 'nextSibling');
            },
            prev: function (node) {
                return Dom.sibling(node, 'previousSibling');
            },
            parentOfType: function (node, tags) {
                do {
                    node = node.parentNode;
                } while (node && !Dom.ofType(node, tags));
                return node;
            },
            ofType: function (node, tags) {
                return $.inArray(Dom.name(node), tags) >= 0;
            },
            changeTag: function (referenceElement, tagName, skipAttributes) {
                var newElement = Dom.create(referenceElement.ownerDocument, tagName), attributes = referenceElement.attributes, i, len, name, value, attribute;
                if (!skipAttributes) {
                    for (i = 0, len = attributes.length; i < len; i++) {
                        attribute = attributes[i];
                        if (attribute.specified) {
                            name = attribute.nodeName;
                            value = attribute.nodeValue;
                            if (name == CLASS) {
                                newElement.className = value;
                            } else if (name == STYLE) {
                                newElement.style.cssText = referenceElement.style.cssText;
                            } else {
                                newElement.setAttribute(name, value);
                            }
                        }
                    }
                }
                while (referenceElement.firstChild) {
                    newElement.appendChild(referenceElement.firstChild);
                }
                Dom.insertBefore(newElement, referenceElement);
                Dom.remove(referenceElement);
                return newElement;
            },
            editableParent: function (node) {
                while (node && (node.nodeType == 3 || node.contentEditable !== 'true')) {
                    node = node.parentNode;
                }
                return node;
            },
            wrap: function (node, wrapper) {
                Dom.insertBefore(wrapper, node);
                wrapper.appendChild(node);
                return wrapper;
            },
            unwrap: function (node) {
                var parent = node.parentNode;
                while (node.firstChild) {
                    parent.insertBefore(node.firstChild, node);
                }
                parent.removeChild(node);
            },
            wrapper: function (node) {
                var wrapper = Dom.closestBy(node, function (el) {
                    return el.parentNode && Dom.significantNodes(el.parentNode.childNodes).length > 1;
                });
                return $(wrapper).is('body,.k-editor') ? undefined : wrapper;
            },
            create: function (document, tagName, attributes) {
                return Dom.attr(document.createElement(tagName), attributes);
            },
            attr: function (element, attributes) {
                attributes = extend({}, attributes);
                if (attributes && STYLE in attributes) {
                    Dom.style(element, attributes.style);
                    delete attributes.style;
                }
                for (var attr in attributes) {
                    if (attributes[attr] === null) {
                        element.removeAttribute(attr);
                        delete attributes[attr];
                    } else if (attr == 'className') {
                        element[attr] = attributes[attr];
                    }
                }
                return extend(element, attributes);
            },
            style: function (node, value) {
                $(node).css(value || {});
            },
            unstyle: function (node, value) {
                for (var key in value) {
                    if (key == FLOAT) {
                        key = kendo.support.cssFloat ? CSSFLOAT : STYLEFLOAT;
                    }
                    node.style[key] = '';
                }
                if (node.style.cssText === '') {
                    node.removeAttribute(STYLE);
                }
            },
            inlineStyle: function (body, name, attributes) {
                var span = $(Dom.create(body.ownerDocument, name, attributes)), style;
                body.appendChild(span[0]);
                style = map(cssAttributes, function (value) {
                    if (browser.msie && value == 'line-height' && span.css(value) == '1px') {
                        return 'line-height:1.5';
                    } else {
                        return value + ':' + span.css(value);
                    }
                }).join(';');
                span.remove();
                return style;
            },
            getEffectiveBackground: function (element) {
                var backgroundStyle = element.css('background-color') || '';
                if (backgroundStyle.indexOf('rgba(0, 0, 0, 0') < 0 && backgroundStyle !== 'transparent') {
                    return backgroundStyle;
                } else if (element[0].tagName.toLowerCase() === 'html') {
                    return 'Window';
                } else {
                    return Dom.getEffectiveBackground(element.parent());
                }
            },
            innerText: function (node) {
                var text = node.innerHTML;
                text = text.replace(/<!--(.|\s)*?-->/gi, '');
                text = text.replace(/<\/?[^>]+?\/?>/gm, '');
                return text;
            },
            removeClass: function (node, classNames) {
                var className = ' ' + node.className + ' ', classes = classNames.split(' '), i, len;
                for (i = 0, len = classes.length; i < len; i++) {
                    className = className.replace(' ' + classes[i] + ' ', ' ');
                }
                className = $.trim(className);
                if (className.length) {
                    node.className = className;
                } else {
                    node.removeAttribute(CLASS);
                }
            },
            commonAncestor: function () {
                var count = arguments.length, paths = [], minPathLength = Infinity, output = null, i, ancestors, node, first, j;
                if (!count) {
                    return null;
                }
                if (count == 1) {
                    return arguments[0];
                }
                for (i = 0; i < count; i++) {
                    ancestors = [];
                    node = arguments[i];
                    while (node) {
                        ancestors.push(node);
                        node = node.parentNode;
                    }
                    paths.push(ancestors.reverse());
                    minPathLength = Math.min(minPathLength, ancestors.length);
                }
                if (count == 1) {
                    return paths[0][0];
                }
                for (i = 0; i < minPathLength; i++) {
                    first = paths[0][i];
                    for (j = 1; j < count; j++) {
                        if (first != paths[j][i]) {
                            return output;
                        }
                    }
                    output = first;
                }
                return output;
            },
            closestSplittableParent: function (nodes) {
                var result;
                if (nodes.length == 1) {
                    result = Dom.parentOfType(nodes[0], [
                        'ul',
                        'ol'
                    ]);
                } else {
                    result = Dom.commonAncestor.apply(null, nodes);
                }
                if (!result) {
                    result = Dom.parentOfType(nodes[0], [
                        'p',
                        'td'
                    ]) || nodes[0].ownerDocument.body;
                }
                if (Dom.isInline(result)) {
                    result = Dom.blockParentOrBody(result);
                }
                var editableParents = map(nodes, Dom.editableParent);
                var editableAncestor = Dom.commonAncestor(editableParents)[0];
                if ($.contains(result, editableAncestor)) {
                    result = editableAncestor;
                }
                return result;
            },
            closestEditable: function (node, types) {
                var closest;
                var editable = Dom.editableParent(node);
                if (Dom.ofType(node, types)) {
                    closest = node;
                } else {
                    closest = Dom.parentOfType(node, types);
                }
                if (closest && editable && $.contains(closest, editable)) {
                    closest = editable;
                } else if (!closest && editable) {
                    closest = editable;
                }
                return closest;
            },
            closestEditableOfType: function (node, types) {
                var editable = Dom.closestEditable(node, types);
                if (editable && Dom.ofType(editable, types)) {
                    return editable;
                }
            },
            filter: function (tagName, nodes, invert) {
                var filterFn = function (node) {
                    return Dom.name(node) == tagName;
                };
                return Dom.filterBy(nodes, filterFn, invert);
            },
            filterBy: function (nodes, condition, invert) {
                var i = 0;
                var len = nodes.length;
                var result = [];
                var match;
                for (; i < len; i++) {
                    match = condition(nodes[i]);
                    if (match && !invert || !match && invert) {
                        result.push(nodes[i]);
                    }
                }
                return result;
            },
            ensureTrailingBreaks: function (node) {
                var elements = $(node).find('p,td,th');
                var length = elements.length;
                var i = 0;
                if (length) {
                    for (; i < length; i++) {
                        Dom.ensureTrailingBreak(elements[i]);
                    }
                } else {
                    Dom.ensureTrailingBreak(node);
                }
            },
            removeTrailingBreak: function (node) {
                $(node).find('br[type=_moz],.k-br').remove();
            },
            ensureTrailingBreak: function (node) {
                Dom.removeTrailingBreak(node);
                var lastChild = node.lastChild;
                var name = lastChild && Dom.name(lastChild);
                var br;
                if (!name || name != 'br' && name != 'img' || name == 'br' && lastChild.className != 'k-br') {
                    br = node.ownerDocument.createElement('br');
                    br.className = 'k-br';
                    node.appendChild(br);
                }
            }
        };
        kendo.ui.editor.Dom = Dom;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/serializer', ['editor/dom'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo;
        var Editor = kendo.ui.editor;
        var dom = Editor.Dom;
        var extend = $.extend;
        var fontSizeMappings = 'xx-small,x-small,small,medium,large,x-large,xx-large'.split(',');
        var quoteRe = /"/g;
        var brRe = /<br[^>]*>/i;
        var pixelRe = /^\d+(\.\d*)?(px)?$/i;
        var emptyPRe = /<p>(?:&nbsp;)?<\/p>/i;
        var cssDeclaration = /(\*?[-#\/\*\\\w]+(?:\[[0-9a-z_-]+\])?)\s*:\s*((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/g;
        var sizzleAttr = /^sizzle-\d+/i;
        var scriptAttr = /^k-script-/i;
        var onerrorRe = /\s*onerror\s*=\s*(?:'|")?([^'">\s]*)(?:'|")?/i;
        var br = '<br class="k-br">';
        var div = document.createElement('div');
        div.innerHTML = ' <hr>';
        var supportsLeadingWhitespace = div.firstChild.nodeType === 3;
        div = null;
        var isFunction = $.isFunction;
        var TD = 'td';
        var Serializer = {
            toEditableHtml: function (html) {
                return (html || '').replace(/<!\[CDATA\[(.*)?\]\]>/g, '<!--[CDATA[$1]]-->').replace(/<(\/?)script([^>]*)>/gi, '<$1k:script$2>').replace(/<img([^>]*)>/gi, function (match) {
                    return match.replace(onerrorRe, '');
                }).replace(/(<\/?img[^>]*>)[\r\n\v\f\t ]+/gi, '$1').replace(/^<(table|blockquote)/i, br + '<$1').replace(/^[\s]*(&nbsp;|\u00a0)/i, '$1').replace(/<\/(table|blockquote)>$/i, '</$1>' + br);
            },
            _toEditableImmutables: function (body) {
                var immutable = Editor.Immutables.immutable, emptyTextNode = dom.emptyTextNode, first = body.firstChild, last = body.lastChild;
                while (emptyTextNode(first)) {
                    first = first.nextSibling;
                }
                while (emptyTextNode(last)) {
                    last = last.previousSibling;
                }
                if (first && immutable(first)) {
                    $(br).prependTo(body);
                }
                if (last && immutable(last)) {
                    $(br).appendTo(body);
                }
            },
            _fillEmptyElements: function (body) {
                $(body).find('p,td').each(function () {
                    var p = $(this);
                    if (/^\s*$/g.test(p.text()) && !p.find('img,input').length) {
                        var node = this;
                        while (node.firstChild && node.firstChild.nodeType != 3) {
                            node = node.firstChild;
                        }
                        if (node.nodeType == 1 && !dom.empty[dom.name(node)]) {
                            if (dom.is(node, 'td')) {
                                node.innerHTML = kendo.ui.editor.emptyTableCellContent;
                            } else {
                                node.innerHTML = kendo.ui.editor.emptyElementContent;
                            }
                        }
                    }
                });
            },
            _removeSystemElements: function (body) {
                $('.k-paste-container', body).remove();
            },
            _resetOrderedLists: function (root) {
                var ols = root.getElementsByTagName('ol'), i, ol, originalStart;
                for (i = 0; i < ols.length; i++) {
                    ol = ols[i];
                    originalStart = ol.getAttribute('start');
                    ol.setAttribute('start', 1);
                    if (originalStart) {
                        ol.setAttribute('start', originalStart);
                    } else {
                        ol.removeAttribute(originalStart);
                    }
                }
            },
            _preventScriptExecution: function (root) {
                $(root).find('*').each(function () {
                    var attributes = this.attributes;
                    var attribute, i, l, name;
                    for (i = 0, l = attributes.length; i < l; i++) {
                        attribute = attributes[i];
                        name = attribute.nodeName;
                        if (attribute.specified && /^on/i.test(name)) {
                            this.setAttribute('k-script-' + name, attribute.value);
                            this.removeAttribute(name);
                        }
                    }
                });
            },
            htmlToDom: function (html, root, options) {
                var browser = kendo.support.browser;
                var msie = browser.msie;
                var legacyIE = msie && browser.version < 9;
                var originalSrc = 'originalsrc';
                var originalHref = 'originalhref';
                var o = options || {};
                var immutables = o.immutables;
                html = Serializer.toEditableHtml(html);
                if (legacyIE) {
                    html = '<br/>' + html;
                    html = html.replace(/href\s*=\s*(?:'|")?([^'">\s]*)(?:'|")?/, originalHref + '="$1"');
                    html = html.replace(/src\s*=\s*(?:'|")?([^'">\s]*)(?:'|")?/, originalSrc + '="$1"');
                }
                if (isFunction(o.custom)) {
                    html = o.custom(html) || html;
                }
                root.innerHTML = html;
                if (immutables) {
                    immutables.deserialize(root);
                }
                if (legacyIE) {
                    dom.remove(root.firstChild);
                    $(root).find('k\\:script,script,link,img,a').each(function () {
                        var node = this;
                        if (node[originalHref]) {
                            node.setAttribute('href', node[originalHref]);
                            node.removeAttribute(originalHref);
                        }
                        if (node[originalSrc]) {
                            node.setAttribute('src', node[originalSrc]);
                            node.removeAttribute(originalSrc);
                        }
                    });
                } else if (msie) {
                    dom.normalize(root);
                    Serializer._resetOrderedLists(root);
                }
                Serializer._preventScriptExecution(root);
                Serializer._fillEmptyElements(root);
                Serializer._removeSystemElements(root);
                Serializer._toEditableImmutables(root);
                $('table', root).addClass('k-table');
                return root;
            },
            domToXhtml: function (root, options) {
                var result = [];
                var immutables = options && options.immutables;
                function semanticFilter(attributes) {
                    return $.grep(attributes, function (attr) {
                        return attr.name != 'style';
                    });
                }
                var tagMap = {
                    iframe: {
                        start: function (node) {
                            result.push('<iframe');
                            attr(node);
                            result.push('>');
                        },
                        end: function () {
                            result.push('</iframe>');
                        }
                    },
                    'k:script': {
                        start: function (node) {
                            result.push('<script');
                            attr(node);
                            result.push('>');
                        },
                        end: function () {
                            result.push('</script>');
                        },
                        skipEncoding: true
                    },
                    span: {
                        semantic: true,
                        start: function (node) {
                            var style = node.style;
                            var attributes = specifiedAttributes(node);
                            var semanticAttributes = semanticFilter(attributes);
                            if (semanticAttributes.length) {
                                result.push('<span');
                                attr(node, semanticAttributes);
                                result.push('>');
                            }
                            if (style.textDecoration == 'underline') {
                                result.push('<u>');
                            }
                            var font = [];
                            if (style.color) {
                                font.push('color="' + dom.toHex(style.color) + '"');
                            }
                            if (style.fontFamily) {
                                font.push('face="' + style.fontFamily + '"');
                            }
                            if (style.fontSize) {
                                var size = $.inArray(style.fontSize, fontSizeMappings);
                                font.push('size="' + size + '"');
                            }
                            if (font.length) {
                                result.push('<font ' + font.join(' ') + '>');
                            }
                        },
                        end: function (node) {
                            var style = node.style;
                            if (style.color || style.fontFamily || style.fontSize) {
                                result.push('</font>');
                            }
                            if (style.textDecoration == 'underline') {
                                result.push('</u>');
                            }
                            if (semanticFilter(specifiedAttributes(node)).length) {
                                result.push('</span>');
                            }
                        }
                    },
                    strong: {
                        semantic: true,
                        start: function () {
                            result.push('<b>');
                        },
                        end: function () {
                            result.push('</b>');
                        }
                    },
                    em: {
                        semantic: true,
                        start: function () {
                            result.push('<i>');
                        },
                        end: function () {
                            result.push('</i>');
                        }
                    },
                    b: {
                        semantic: false,
                        start: function () {
                            result.push('<strong>');
                        },
                        end: function () {
                            result.push('</strong>');
                        }
                    },
                    i: {
                        semantic: false,
                        start: function () {
                            result.push('<em>');
                        },
                        end: function () {
                            result.push('</em>');
                        }
                    },
                    u: {
                        semantic: false,
                        start: function () {
                            result.push('<span style="text-decoration:underline;">');
                        },
                        end: function () {
                            result.push('</span>');
                        }
                    },
                    font: {
                        semantic: false,
                        start: function (node) {
                            result.push('<span style="');
                            var color = node.getAttribute('color');
                            var size = fontSizeMappings[node.getAttribute('size')];
                            var face = node.getAttribute('face');
                            if (color) {
                                result.push('color:');
                                result.push(dom.toHex(color));
                                result.push(';');
                            }
                            if (face) {
                                result.push('font-family:');
                                result.push(face);
                                result.push(';');
                            }
                            if (size) {
                                result.push('font-size:');
                                result.push(size);
                                result.push(';');
                            }
                            result.push('">');
                        },
                        end: function () {
                            result.push('</span>');
                        }
                    }
                };
                tagMap.script = tagMap['k:script'];
                options = options || {};
                if (typeof options.semantic == 'undefined') {
                    options.semantic = true;
                }
                function cssProperties(cssText) {
                    var trim = $.trim;
                    var css = trim(cssText);
                    var match;
                    var property, value;
                    var properties = [];
                    cssDeclaration.lastIndex = 0;
                    while (true) {
                        match = cssDeclaration.exec(css);
                        if (!match) {
                            break;
                        }
                        property = trim(match[1].toLowerCase());
                        value = trim(match[2]);
                        if (property == 'font-size-adjust' || property == 'font-stretch') {
                            continue;
                        }
                        if (property.indexOf('color') >= 0) {
                            value = dom.toHex(value);
                        } else if (property.indexOf('font') >= 0) {
                            value = value.replace(quoteRe, '\'');
                        } else if (/\burl\(/g.test(value)) {
                            value = value.replace(quoteRe, '');
                        }
                        properties.push({
                            property: property,
                            value: value
                        });
                    }
                    return properties;
                }
                function styleAttr(cssText) {
                    var properties = cssProperties(cssText);
                    var i;
                    for (i = 0; i < properties.length; i++) {
                        result.push(properties[i].property);
                        result.push(':');
                        result.push(properties[i].value);
                        result.push(';');
                    }
                }
                function specifiedAttributes(node) {
                    var result = [];
                    var attributes = node.attributes;
                    var attribute, i, l;
                    var name, value, specified;
                    for (i = 0, l = attributes.length; i < l; i++) {
                        attribute = attributes[i];
                        name = attribute.nodeName;
                        value = attribute.value;
                        specified = attribute.specified;
                        if (name == 'value' && 'value' in node && node.value) {
                            specified = true;
                        } else if (name == 'type' && value == 'text') {
                            specified = true;
                        } else if (name == 'class' && !value) {
                            specified = false;
                        } else if (sizzleAttr.test(name)) {
                            specified = false;
                        } else if (name == 'complete') {
                            specified = false;
                        } else if (name == 'altHtml') {
                            specified = false;
                        } else if (name == 'start' && dom.is(node, 'ul')) {
                            specified = false;
                        } else if (name == 'start' && dom.is(node, 'ol') && value == '1') {
                            specified = false;
                        } else if (name.indexOf('_moz') >= 0) {
                            specified = false;
                        } else if (scriptAttr.test(name)) {
                            specified = !!options.scripts;
                        } else if (name == 'data-role' && value == 'resizable' && (dom.is(node, 'tr') || dom.is(node, 'td'))) {
                            specified = false;
                        }
                        if (specified) {
                            result.push(attribute);
                        }
                    }
                    return result;
                }
                function attr(node, attributes) {
                    var i, l, attribute, name, value;
                    attributes = attributes || specifiedAttributes(node);
                    if (dom.is(node, 'img')) {
                        var width = node.style.width, height = node.style.height, $node = $(node);
                        if (width && pixelRe.test(width)) {
                            $node.attr('width', parseInt(width, 10));
                            dom.unstyle(node, { width: undefined });
                        }
                        if (height && pixelRe.test(height)) {
                            $node.attr('height', parseInt(height, 10));
                            dom.unstyle(node, { height: undefined });
                        }
                    }
                    if (!attributes.length) {
                        return;
                    }
                    attributes.sort(function (a, b) {
                        return a.nodeName > b.nodeName ? 1 : a.nodeName < b.nodeName ? -1 : 0;
                    });
                    for (i = 0, l = attributes.length; i < l; i++) {
                        attribute = attributes[i];
                        name = attribute.nodeName;
                        value = attribute.value;
                        if (name == 'class' && value == 'k-table') {
                            continue;
                        }
                        name = name.replace(scriptAttr, '');
                        result.push(' ');
                        result.push(name);
                        result.push('="');
                        if (name == 'style') {
                            styleAttr(value || node.style.cssText);
                        } else if (name == 'src' || name == 'href') {
                            result.push(kendo.htmlEncode(node.getAttribute(name, 2)));
                        } else {
                            result.push(dom.fillAttrs[name] ? name : value);
                        }
                        result.push('"');
                    }
                }
                function children(node, skip, skipEncoding) {
                    for (var childNode = node.firstChild; childNode; childNode = childNode.nextSibling) {
                        child(childNode, skip, skipEncoding);
                    }
                }
                function text(node) {
                    return node.nodeValue.replace(/\ufeff/g, '');
                }
                function isEmptyBomNode(node) {
                    if (node.nodeValue === '\uFEFF') {
                        do {
                            node = node.parentNode;
                            if (dom.is(node, TD) && node.childNodes.length === 1) {
                                return true;
                            }
                            if (node.childNodes.length !== 1) {
                                return false;
                            }
                        } while (!dom.isBlock(node));
                        return true;
                    }
                    return false;
                }
                function child(node, skip, skipEncoding) {
                    var nodeType = node.nodeType, tagName, mapper, parent, value, previous, jqNode;
                    if (immutables && Editor.Immutables.immutable(node)) {
                        result.push(immutables.serialize(node));
                    } else if (nodeType == 1) {
                        tagName = dom.name(node);
                        jqNode = $(node);
                        if (jqNode.hasClass('k-table-resize-handle-wrapper') || jqNode.hasClass('k-column-resize-handle-wrapper') || jqNode.hasClass('k-row-resize-handle-wrapper')) {
                            return;
                        }
                        if (!tagName || dom.insignificant(node)) {
                            return;
                        }
                        if (!options.scripts && (tagName == 'script' || tagName == 'k:script')) {
                            return;
                        }
                        mapper = tagMap[tagName];
                        if (mapper) {
                            if (typeof mapper.semantic == 'undefined' || options.semantic ^ mapper.semantic) {
                                mapper.start(node);
                                children(node, false, mapper.skipEncoding);
                                mapper.end(node);
                                return;
                            }
                        }
                        result.push('<');
                        result.push(tagName);
                        attr(node);
                        if (dom.empty[tagName]) {
                            result.push(' />');
                        } else {
                            result.push('>');
                            children(node, skip || dom.is(node, 'pre'));
                            result.push('</');
                            result.push(tagName);
                            result.push('>');
                        }
                    } else if (nodeType == 3) {
                        if (isEmptyBomNode(node)) {
                            result.push('&nbsp;');
                            return;
                        }
                        value = text(node);
                        if (!skip && supportsLeadingWhitespace) {
                            parent = node.parentNode;
                            previous = node.previousSibling;
                            if (!previous) {
                                previous = (dom.isInline(parent) ? parent : node).previousSibling;
                            }
                            if (!previous || previous.innerHTML === '' || dom.isBlock(previous)) {
                                value = value.replace(/^[\r\n\v\f\t ]+/, '');
                            }
                            value = value.replace(/ +/, ' ');
                        }
                        result.push(skipEncoding ? value : dom.encode(value, options));
                    } else if (nodeType == 4) {
                        result.push('<![CDATA[');
                        result.push(node.data);
                        result.push(']]>');
                    } else if (nodeType == 8) {
                        if (node.data.indexOf('[CDATA[') < 0) {
                            result.push('<!--');
                            result.push(node.data);
                            result.push('-->');
                        } else {
                            result.push('<!');
                            result.push(node.data);
                            result.push('>');
                        }
                    }
                }
                function textOnly(root) {
                    var childrenCount = root.childNodes.length;
                    var textChild = childrenCount && root.firstChild.nodeType == 3;
                    return textChild && (childrenCount == 1 || childrenCount == 2 && dom.insignificant(root.lastChild));
                }
                function runCustom() {
                    if ($.isFunction(options.custom)) {
                        result = options.custom(result) || result;
                    }
                }
                if (textOnly(root)) {
                    result = dom.encode(text(root.firstChild).replace(/[\r\n\v\f\t ]+/, ' '), options);
                    runCustom();
                    return result;
                }
                children(root);
                result = result.join('');
                runCustom();
                if (result.replace(brRe, '').replace(emptyPRe, '') === '') {
                    return '';
                }
                return result;
            }
        };
        extend(Editor, { Serializer: Serializer });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/range', ['editor/serializer'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, browser = kendo.support.browser, dom = Editor.Dom, findNodeIndex = dom.findNodeIndex, isDataNode = dom.isDataNode, findClosestAncestor = dom.findClosestAncestor, getNodeLength = dom.getNodeLength, normalize = dom.normalize;
        var SelectionUtils = {
            selectionFromWindow: function (window) {
                if (!('getSelection' in window)) {
                    return new W3CSelection(window.document);
                }
                return window.getSelection();
            },
            selectionFromRange: function (range) {
                var rangeDocument = RangeUtils.documentFromRange(range);
                return SelectionUtils.selectionFromDocument(rangeDocument);
            },
            selectionFromDocument: function (document) {
                return SelectionUtils.selectionFromWindow(dom.windowFromDocument(document));
            }
        };
        var W3CRange = Class.extend({
            init: function (doc) {
                $.extend(this, {
                    ownerDocument: doc,
                    startContainer: doc,
                    endContainer: doc,
                    commonAncestorContainer: doc,
                    startOffset: 0,
                    endOffset: 0,
                    collapsed: true
                });
            },
            setStart: function (node, offset) {
                this.startContainer = node;
                this.startOffset = offset;
                updateRangeProperties(this);
                fixIvalidRange(this, true);
            },
            setEnd: function (node, offset) {
                this.endContainer = node;
                this.endOffset = offset;
                updateRangeProperties(this);
                fixIvalidRange(this, false);
            },
            setStartBefore: function (node) {
                this.setStart(node.parentNode, findNodeIndex(node));
            },
            setStartAfter: function (node) {
                this.setStart(node.parentNode, findNodeIndex(node) + 1);
            },
            setEndBefore: function (node) {
                this.setEnd(node.parentNode, findNodeIndex(node));
            },
            setEndAfter: function (node) {
                this.setEnd(node.parentNode, findNodeIndex(node) + 1);
            },
            selectNode: function (node) {
                this.setStartBefore(node);
                this.setEndAfter(node);
            },
            selectNodeContents: function (node) {
                this.setStart(node, 0);
                this.setEnd(node, node[node.nodeType === 1 ? 'childNodes' : 'nodeValue'].length);
            },
            collapse: function (toStart) {
                var that = this;
                if (toStart) {
                    that.setEnd(that.startContainer, that.startOffset);
                } else {
                    that.setStart(that.endContainer, that.endOffset);
                }
            },
            deleteContents: function () {
                var that = this, range = that.cloneRange();
                if (that.startContainer != that.commonAncestorContainer) {
                    that.setStartAfter(findClosestAncestor(that.commonAncestorContainer, that.startContainer));
                }
                that.collapse(true);
                (function deleteSubtree(iterator) {
                    while (iterator.next()) {
                        if (iterator.hasPartialSubtree()) {
                            deleteSubtree(iterator.getSubtreeIterator());
                        } else {
                            iterator.remove();
                        }
                    }
                }(new RangeIterator(range)));
            },
            cloneContents: function () {
                var document = RangeUtils.documentFromRange(this);
                return function cloneSubtree(iterator) {
                    var node, frag = document.createDocumentFragment();
                    while (node = iterator.next()) {
                        node = node.cloneNode(!iterator.hasPartialSubtree());
                        if (iterator.hasPartialSubtree()) {
                            node.appendChild(cloneSubtree(iterator.getSubtreeIterator()));
                        }
                        frag.appendChild(node);
                    }
                    return frag;
                }(new RangeIterator(this));
            },
            extractContents: function () {
                var that = this, range = that.cloneRange();
                if (that.startContainer != that.commonAncestorContainer) {
                    that.setStartAfter(findClosestAncestor(that.commonAncestorContainer, that.startContainer));
                }
                that.collapse(true);
                var document = RangeUtils.documentFromRange(that);
                return function extractSubtree(iterator) {
                    var node, frag = document.createDocumentFragment();
                    while (node = iterator.next()) {
                        if (iterator.hasPartialSubtree()) {
                            node = node.cloneNode(false);
                            node.appendChild(extractSubtree(iterator.getSubtreeIterator()));
                        } else {
                            iterator.remove(that.originalRange);
                        }
                        frag.appendChild(node);
                    }
                    return frag;
                }(new RangeIterator(range));
            },
            insertNode: function (node) {
                var that = this;
                if (isDataNode(that.startContainer)) {
                    if (that.startOffset != that.startContainer.nodeValue.length) {
                        dom.splitDataNode(that.startContainer, that.startOffset);
                    }
                    dom.insertAfter(node, that.startContainer);
                } else {
                    dom.insertAt(that.startContainer, node, that.startOffset);
                }
                that.setStart(that.startContainer, that.startOffset);
            },
            cloneRange: function () {
                return $.extend(new W3CRange(this.ownerDocument), {
                    startContainer: this.startContainer,
                    endContainer: this.endContainer,
                    commonAncestorContainer: this.commonAncestorContainer,
                    startOffset: this.startOffset,
                    endOffset: this.endOffset,
                    collapsed: this.collapsed,
                    originalRange: this
                });
            },
            toString: function () {
                var startNodeName = this.startContainer.nodeName, endNodeName = this.endContainer.nodeName;
                return [
                    startNodeName == '#text' ? this.startContainer.nodeValue : startNodeName,
                    '(',
                    this.startOffset,
                    ') : ',
                    endNodeName == '#text' ? this.endContainer.nodeValue : endNodeName,
                    '(',
                    this.endOffset,
                    ')'
                ].join('');
            }
        });
        W3CRange.fromNode = function (node) {
            return new W3CRange(node.ownerDocument);
        };
        function compareBoundaries(start, end, startOffset, endOffset) {
            if (start == end) {
                return endOffset - startOffset;
            }
            var container = end;
            while (container && container.parentNode != start) {
                container = container.parentNode;
            }
            if (container) {
                return findNodeIndex(container) - startOffset;
            }
            container = start;
            while (container && container.parentNode != end) {
                container = container.parentNode;
            }
            if (container) {
                return endOffset - findNodeIndex(container) - 1;
            }
            var root = dom.commonAncestor(start, end);
            var startAncestor = start;
            while (startAncestor && startAncestor.parentNode != root) {
                startAncestor = startAncestor.parentNode;
            }
            if (!startAncestor) {
                startAncestor = root;
            }
            var endAncestor = end;
            while (endAncestor && endAncestor.parentNode != root) {
                endAncestor = endAncestor.parentNode;
            }
            if (!endAncestor) {
                endAncestor = root;
            }
            if (startAncestor == endAncestor) {
                return 0;
            }
            return findNodeIndex(endAncestor) - findNodeIndex(startAncestor);
        }
        function fixIvalidRange(range, toStart) {
            function isInvalidRange(range) {
                try {
                    return compareBoundaries(range.startContainer, range.endContainer, range.startOffset, range.endOffset) < 0;
                } catch (ex) {
                    return true;
                }
            }
            if (isInvalidRange(range)) {
                if (toStart) {
                    range.commonAncestorContainer = range.endContainer = range.startContainer;
                    range.endOffset = range.startOffset;
                } else {
                    range.commonAncestorContainer = range.startContainer = range.endContainer;
                    range.startOffset = range.endOffset;
                }
                range.collapsed = true;
            }
        }
        function updateRangeProperties(range) {
            range.collapsed = range.startContainer == range.endContainer && range.startOffset == range.endOffset;
            var node = range.startContainer;
            while (node && node != range.endContainer && !dom.isAncestorOf(node, range.endContainer)) {
                node = node.parentNode;
            }
            range.commonAncestorContainer = node;
        }
        var RangeIterator = Class.extend({
            init: function (range) {
                $.extend(this, {
                    range: range,
                    _current: null,
                    _next: null,
                    _end: null
                });
                if (range.collapsed) {
                    return;
                }
                var root = range.commonAncestorContainer;
                this._next = range.startContainer == root && !isDataNode(range.startContainer) ? range.startContainer.childNodes[range.startOffset] : findClosestAncestor(root, range.startContainer);
                this._end = range.endContainer == root && !isDataNode(range.endContainer) ? range.endContainer.childNodes[range.endOffset] : findClosestAncestor(root, range.endContainer).nextSibling;
            },
            hasNext: function () {
                return !!this._next;
            },
            next: function () {
                var that = this, current = that._current = that._next;
                that._next = that._current && that._current.nextSibling != that._end ? that._current.nextSibling : null;
                if (isDataNode(that._current)) {
                    if (that.range.endContainer == that._current) {
                        current = current.cloneNode(true);
                        current.deleteData(that.range.endOffset, current.length - that.range.endOffset);
                    }
                    if (that.range.startContainer == that._current) {
                        current = current.cloneNode(true);
                        current.deleteData(0, that.range.startOffset);
                    }
                }
                return current;
            },
            traverse: function (callback) {
                var that = this, current;
                function next() {
                    that._current = that._next;
                    that._next = that._current && that._current.nextSibling != that._end ? that._current.nextSibling : null;
                    return that._current;
                }
                while (current = next()) {
                    if (that.hasPartialSubtree()) {
                        that.getSubtreeIterator().traverse(callback);
                    } else {
                        callback(current);
                    }
                }
                return current;
            },
            remove: function (originalRange) {
                var that = this, inStartContainer = that.range.startContainer == that._current, inEndContainer = that.range.endContainer == that._current, start, end, delta;
                if (isDataNode(that._current) && (inStartContainer || inEndContainer)) {
                    start = inStartContainer ? that.range.startOffset : 0;
                    end = inEndContainer ? that.range.endOffset : that._current.length;
                    delta = end - start;
                    if (originalRange && (inStartContainer || inEndContainer)) {
                        if (that._current == originalRange.startContainer && start <= originalRange.startOffset) {
                            originalRange.startOffset -= delta;
                        }
                        if (that._current == originalRange.endContainer && end <= originalRange.endOffset) {
                            originalRange.endOffset -= delta;
                        }
                    }
                    that._current.deleteData(start, delta);
                } else {
                    var parent = that._current.parentNode;
                    if (originalRange && (that.range.startContainer == parent || that.range.endContainer == parent)) {
                        var nodeIndex = findNodeIndex(that._current);
                        if (parent == originalRange.startContainer && nodeIndex <= originalRange.startOffset) {
                            originalRange.startOffset -= 1;
                        }
                        if (parent == originalRange.endContainer && nodeIndex < originalRange.endOffset) {
                            originalRange.endOffset -= 1;
                        }
                    }
                    dom.remove(that._current);
                }
            },
            hasPartialSubtree: function () {
                return !isDataNode(this._current) && (dom.isAncestorOrSelf(this._current, this.range.startContainer) || dom.isAncestorOrSelf(this._current, this.range.endContainer));
            },
            getSubtreeIterator: function () {
                return new RangeIterator(this.getSubRange());
            },
            getSubRange: function () {
                var that = this, subRange = that.range.cloneRange();
                subRange.selectNodeContents(that._current);
                if (dom.isAncestorOrSelf(that._current, that.range.startContainer)) {
                    subRange.setStart(that.range.startContainer, that.range.startOffset);
                }
                if (dom.isAncestorOrSelf(that._current, that.range.endContainer)) {
                    subRange.setEnd(that.range.endContainer, that.range.endOffset);
                }
                return subRange;
            }
        });
        var W3CSelection = Class.extend({
            init: function (doc) {
                this.ownerDocument = doc;
                this.rangeCount = 1;
            },
            addRange: function (range) {
                var textRange = this.ownerDocument.body.createTextRange();
                adoptContainer(textRange, range, false);
                adoptContainer(textRange, range, true);
                textRange.select();
            },
            removeAllRanges: function () {
                var selection = this.ownerDocument.selection;
                if (selection.type != 'None') {
                    selection.empty();
                }
            },
            getRangeAt: function () {
                var textRange, range = new W3CRange(this.ownerDocument), selection = this.ownerDocument.selection, element, commonAncestor;
                try {
                    textRange = selection.createRange();
                    element = textRange.item ? textRange.item(0) : textRange.parentElement();
                    if (element.ownerDocument != this.ownerDocument) {
                        return range;
                    }
                } catch (ex) {
                    return range;
                }
                if (selection.type == 'Control') {
                    range.selectNode(textRange.item(0));
                } else {
                    commonAncestor = textRangeContainer(textRange);
                    adoptEndPoint(textRange, range, commonAncestor, true);
                    adoptEndPoint(textRange, range, commonAncestor, false);
                    if (range.startContainer.nodeType == 9) {
                        range.setStart(range.endContainer, range.startOffset);
                    }
                    if (range.endContainer.nodeType == 9) {
                        range.setEnd(range.startContainer, range.endOffset);
                    }
                    if (textRange.compareEndPoints('StartToEnd', textRange) === 0) {
                        range.collapse(false);
                    }
                    var startContainer = range.startContainer, endContainer = range.endContainer, body = this.ownerDocument.body;
                    if (!range.collapsed && range.startOffset === 0 && range.endOffset == getNodeLength(range.endContainer) && !(startContainer == endContainer && isDataNode(startContainer) && startContainer.parentNode == body)) {
                        var movedStart = false, movedEnd = false;
                        while (findNodeIndex(startContainer) === 0 && startContainer == startContainer.parentNode.firstChild && startContainer != body) {
                            startContainer = startContainer.parentNode;
                            movedStart = true;
                        }
                        while (findNodeIndex(endContainer) == getNodeLength(endContainer.parentNode) - 1 && endContainer == endContainer.parentNode.lastChild && endContainer != body) {
                            endContainer = endContainer.parentNode;
                            movedEnd = true;
                        }
                        if (startContainer == body && endContainer == body && movedStart && movedEnd) {
                            range.setStart(startContainer, 0);
                            range.setEnd(endContainer, getNodeLength(body));
                        }
                    }
                }
                return range;
            }
        });
        function textRangeContainer(textRange) {
            var left = textRange.duplicate(), right = textRange.duplicate();
            left.collapse(true);
            right.collapse(false);
            return dom.commonAncestor(textRange.parentElement(), left.parentElement(), right.parentElement());
        }
        function adoptContainer(textRange, range, start) {
            var container = range[start ? 'startContainer' : 'endContainer'], offset = range[start ? 'startOffset' : 'endOffset'], textOffset = 0, isData = isDataNode(container), anchorNode = isData ? container : container.childNodes[offset] || null, anchorParent = isData ? container.parentNode : container, doc = range.ownerDocument, cursor = doc.body.createTextRange(), cursorNode;
            if (container.nodeType == 3 || container.nodeType == 4) {
                textOffset = offset;
            }
            if (!anchorParent) {
                anchorParent = doc.body;
            }
            if (anchorParent.nodeName.toLowerCase() == 'img') {
                cursor.moveToElementText(anchorParent);
                cursor.collapse(false);
                textRange.setEndPoint(start ? 'StartToStart' : 'EndToStart', cursor);
            } else {
                cursorNode = anchorParent.insertBefore(dom.create(doc, 'a'), anchorNode);
                cursor.moveToElementText(cursorNode);
                dom.remove(cursorNode);
                cursor[start ? 'moveStart' : 'moveEnd']('character', textOffset);
                cursor.collapse(false);
                textRange.setEndPoint(start ? 'StartToStart' : 'EndToStart', cursor);
            }
        }
        function adoptEndPoint(textRange, range, commonAncestor, start) {
            var cursorNode = dom.create(range.ownerDocument, 'a'), cursor = textRange.duplicate(), comparison = start ? 'StartToStart' : 'StartToEnd', result, parent, target, previous, next, args, index, appended = false;
            cursorNode.innerHTML = '\uFEFF';
            cursor.collapse(start);
            parent = cursor.parentElement();
            if (!dom.isAncestorOrSelf(commonAncestor, parent)) {
                parent = commonAncestor;
            }
            do {
                if (appended) {
                    parent.insertBefore(cursorNode, cursorNode.previousSibling);
                } else {
                    parent.appendChild(cursorNode);
                    appended = true;
                }
                cursor.moveToElementText(cursorNode);
            } while ((result = cursor.compareEndPoints(comparison, textRange)) > 0 && cursorNode.previousSibling);
            target = cursorNode.nextSibling;
            if (result == -1 && isDataNode(target)) {
                cursor.setEndPoint(start ? 'EndToStart' : 'EndToEnd', textRange);
                dom.remove(cursorNode);
                args = [
                    target,
                    cursor.text.length
                ];
            } else {
                previous = !start && cursorNode.previousSibling;
                next = start && cursorNode.nextSibling;
                if (isDataNode(next)) {
                    args = [
                        next,
                        0
                    ];
                } else if (isDataNode(previous)) {
                    args = [
                        previous,
                        previous.length
                    ];
                } else {
                    index = findNodeIndex(cursorNode);
                    if (parent.nextSibling && index == parent.childNodes.length - 1) {
                        args = [
                            parent.nextSibling,
                            0
                        ];
                    } else {
                        args = [
                            parent,
                            index
                        ];
                    }
                }
                dom.remove(cursorNode);
            }
            range[start ? 'setStart' : 'setEnd'].apply(range, args);
        }
        var RangeEnumerator = Class.extend({
            init: function (range) {
                this.enumerate = function () {
                    var nodes = [];
                    function visit(node) {
                        if (dom.is(node, 'img') || node.nodeType == 3 && (!dom.isEmptyspace(node) || node.nodeValue == '\uFEFF')) {
                            nodes.push(node);
                        } else {
                            node = node.firstChild;
                            while (node) {
                                visit(node);
                                node = node.nextSibling;
                            }
                        }
                    }
                    new RangeIterator(range).traverse(visit);
                    return nodes;
                };
            }
        });
        var ImmutablesRangeIterator = RangeIterator.extend({
            hasPartialSubtree: function () {
                var immutable = Editor.Immutables && Editor.Immutables.immutable;
                return immutable && !immutable(this._current) && RangeIterator.fn.hasPartialSubtree.call(this);
            },
            getSubtreeIterator: function () {
                return new ImmutablesRangeIterator(this.getSubRange());
            }
        });
        var ImmutablesRangeEnumerator = Class.extend({
            init: function (range) {
                this.enumerate = function () {
                    var nodes = [];
                    var immutable = Editor.Immutables && Editor.Immutables.immutable;
                    function visit(node) {
                        if (immutable && !immutable(node)) {
                            if (dom.is(node, 'img') || node.nodeType == 3 && (!dom.isEmptyspace(node) || node.nodeValue == '\uFEFF')) {
                                nodes.push(node);
                            } else {
                                node = node.firstChild;
                                while (node) {
                                    visit(node);
                                    node = node.nextSibling;
                                }
                            }
                        }
                    }
                    new ImmutablesRangeIterator(range).traverse(visit);
                    return nodes;
                };
            }
        });
        var RestorePoint = Class.extend({
            init: function (range, body, options) {
                var that = this;
                that.range = range;
                that.rootNode = RangeUtils.documentFromRange(range);
                that.body = body || that.getEditable(range);
                if (dom.name(that.body) != 'body') {
                    that.rootNode = that.body;
                }
                that.startContainer = that.nodeToPath(range.startContainer);
                that.endContainer = that.nodeToPath(range.endContainer);
                that.startOffset = that.offset(range.startContainer, range.startOffset);
                that.endOffset = that.offset(range.endContainer, range.endOffset);
                that.immutables = options && options.immutables;
                if (that.immutables) {
                    that.serializedImmutables = Editor.Immutables.removeImmutables(that.body);
                }
                that.html = that.body.innerHTML;
                if (that.immutables && !that.serializedImmutables.empty) {
                    Editor.Immutables.restoreImmutables(that.body, that.serializedImmutables);
                }
            },
            index: function (node) {
                var result = 0, lastType = node.nodeType;
                while (node = node.previousSibling) {
                    var nodeType = node.nodeType;
                    if (nodeType != 3 || lastType != nodeType) {
                        result++;
                    }
                    lastType = nodeType;
                }
                return result;
            },
            getEditable: function (range) {
                var root = range.commonAncestorContainer;
                while (root && (root.nodeType == 3 || root.attributes && (!root.attributes.contentEditable || root.attributes.contentEditable.nodeValue.toLowerCase() == 'false'))) {
                    root = root.parentNode;
                }
                return root;
            },
            restoreHtml: function () {
                var that = this;
                dom.removeChildren(that.body);
                that.body.innerHTML = that.html;
                if (that.immutables && !that.serializedImmutables.empty) {
                    Editor.Immutables.restoreImmutables(that.body, that.serializedImmutables);
                }
            },
            offset: function (node, value) {
                if (node.nodeType == 3) {
                    while ((node = node.previousSibling) && node.nodeType == 3) {
                        value += node.nodeValue.length;
                    }
                }
                return value;
            },
            nodeToPath: function (node) {
                var path = [];
                while (node != this.rootNode) {
                    path.push(this.index(node));
                    node = node.parentNode;
                }
                return path;
            },
            toRangePoint: function (range, start, path, denormalizedOffset) {
                var node = this.rootNode, length = path.length, offset = denormalizedOffset;
                while (length--) {
                    node = node.childNodes[path[length]];
                }
                while (node && node.nodeType == 3 && node.nodeValue.length < offset) {
                    offset -= node.nodeValue.length;
                    node = node.nextSibling;
                }
                if (node && offset >= 0) {
                    range[start ? 'setStart' : 'setEnd'](node, offset);
                }
            },
            toRange: function () {
                var that = this, result = that.range.cloneRange();
                that.toRangePoint(result, true, that.startContainer, that.startOffset);
                that.toRangePoint(result, false, that.endContainer, that.endOffset);
                return result;
            }
        });
        var Marker = Class.extend({
            init: function () {
                this.caret = null;
            },
            addCaret: function (range) {
                var that = this;
                var caret = that.caret = dom.create(RangeUtils.documentFromRange(range), 'span', { className: 'k-marker' });
                range.insertNode(caret);
                dom.stripBomNode(caret.previousSibling);
                dom.stripBomNode(caret.nextSibling);
                range.selectNode(caret);
                return caret;
            },
            removeCaret: function (range) {
                var that = this, previous = that.caret.previousSibling, startOffset = 0;
                if (previous) {
                    startOffset = isDataNode(previous) ? previous.nodeValue.length : findNodeIndex(previous);
                }
                var container = that.caret.parentNode;
                var containerIndex = previous ? findNodeIndex(previous) : 0;
                dom.remove(that.caret);
                normalize(container);
                var node = container.childNodes[containerIndex];
                if (isDataNode(node)) {
                    range.setStart(node, startOffset);
                } else if (node) {
                    var textNode = dom.lastTextNode(node);
                    if (textNode) {
                        range.setStart(textNode, textNode.nodeValue.length);
                    } else {
                        range[previous ? 'setStartAfter' : 'setStartBefore'](node);
                    }
                } else {
                    if (!browser.msie && !container.innerHTML) {
                        container.innerHTML = '<br _moz_dirty="" />';
                    }
                    range.selectNodeContents(container);
                }
                range.collapse(true);
            },
            add: function (range, expand) {
                var that = this;
                var collapsed = range.collapsed && !RangeUtils.isExpandable(range);
                var doc = RangeUtils.documentFromRange(range);
                if (expand && range.collapsed) {
                    that.addCaret(range);
                    range = RangeUtils.expand(range);
                }
                var rangeBoundary = range.cloneRange();
                rangeBoundary.collapse(false);
                that.end = dom.create(doc, 'span', { className: 'k-marker' });
                rangeBoundary.insertNode(that.end);
                rangeBoundary = range.cloneRange();
                rangeBoundary.collapse(true);
                that.start = that.end.cloneNode(true);
                rangeBoundary.insertNode(that.start);
                that._removeDeadMarkers(that.start, that.end);
                if (collapsed) {
                    var bom = doc.createTextNode('\uFEFF');
                    dom.insertAfter(bom.cloneNode(), that.start);
                    dom.insertBefore(bom, that.end);
                }
                normalize(range.commonAncestorContainer);
                range.setStartBefore(that.start);
                range.setEndAfter(that.end);
                return range;
            },
            _removeDeadMarkers: function (start, end) {
                if (start.previousSibling && start.previousSibling.nodeValue == '\uFEFF') {
                    dom.remove(start.previousSibling);
                }
                if (end.nextSibling && end.nextSibling.nodeValue == '\uFEFF') {
                    dom.remove(end.nextSibling);
                }
            },
            _normalizedIndex: function (node) {
                var index = findNodeIndex(node);
                var pointer = node;
                while (pointer.previousSibling) {
                    if (pointer.nodeType == 3 && pointer.previousSibling.nodeType == 3) {
                        index--;
                    }
                    pointer = pointer.previousSibling;
                }
                return index;
            },
            remove: function (range) {
                var that = this, start = that.start, end = that.end, shouldNormalizeStart, shouldNormalizeEnd, shouldNormalize;
                normalize(range.commonAncestorContainer);
                while (!start.nextSibling && start.parentNode) {
                    start = start.parentNode;
                }
                while (!end.previousSibling && end.parentNode) {
                    end = end.parentNode;
                }
                shouldNormalizeStart = start.previousSibling && start.previousSibling.nodeType == 3 && (start.nextSibling && start.nextSibling.nodeType == 3);
                shouldNormalizeEnd = end.previousSibling && end.previousSibling.nodeType == 3 && (end.nextSibling && end.nextSibling.nodeType == 3);
                shouldNormalize = shouldNormalizeStart && shouldNormalizeEnd;
                start = start.nextSibling;
                end = end.previousSibling;
                var collapsed = false;
                var collapsedToStart = false;
                if (start == that.end) {
                    collapsedToStart = !!that.start.previousSibling;
                    start = end = that.start.previousSibling || that.end.nextSibling;
                    collapsed = true;
                }
                dom.remove(that.start);
                dom.remove(that.end);
                if (!start || !end) {
                    range.selectNodeContents(range.commonAncestorContainer);
                    range.collapse(true);
                    return;
                }
                var startOffset = collapsed ? isDataNode(start) ? start.nodeValue.length : start.childNodes.length : 0;
                var endOffset = isDataNode(end) ? end.nodeValue.length : end.childNodes.length;
                if (start.nodeType == 3) {
                    while (start.previousSibling && start.previousSibling.nodeType == 3) {
                        start = start.previousSibling;
                        startOffset += start.nodeValue.length;
                    }
                }
                if (end.nodeType == 3) {
                    while (end.previousSibling && end.previousSibling.nodeType == 3) {
                        end = end.previousSibling;
                        endOffset += end.nodeValue.length;
                    }
                }
                var startParent = start.parentNode;
                var endParent = end.parentNode;
                var startIndex = this._normalizedIndex(start);
                var endIndex = this._normalizedIndex(end);
                normalize(startParent);
                if (start.nodeType == 3) {
                    start = startParent.childNodes[startIndex];
                }
                normalize(endParent);
                if (end.nodeType == 3) {
                    end = endParent.childNodes[endIndex];
                }
                if (collapsed) {
                    if (start.nodeType == 3) {
                        range.setStart(start, startOffset);
                    } else {
                        range[collapsedToStart ? 'setStartAfter' : 'setStartBefore'](start);
                    }
                    range.collapse(true);
                } else {
                    if (start.nodeType == 3) {
                        range.setStart(start, startOffset);
                    } else {
                        range.setStartBefore(start);
                    }
                    if (end.nodeType == 3) {
                        range.setEnd(end, endOffset);
                    } else {
                        range.setEndAfter(end);
                    }
                }
                if (that.caret) {
                    that.removeCaret(range);
                }
            }
        });
        var boundary = /[\u0009-\u000d]|\u0020|\u00a0|\ufeff|\.|,|;|:|!|\(|\)|\?/;
        var RangeUtils = {
            nodes: function (range) {
                var nodes = RangeUtils.textNodes(range);
                if (!nodes.length) {
                    range.selectNodeContents(range.commonAncestorContainer);
                    nodes = RangeUtils.textNodes(range);
                    if (!nodes.length) {
                        nodes = dom.significantChildNodes(range.commonAncestorContainer);
                    }
                }
                return nodes;
            },
            textNodes: function (range) {
                return new RangeEnumerator(range).enumerate();
            },
            editableTextNodes: function (range) {
                var nodes = [], immutableParent = Editor.Immutables && Editor.Immutables.immutableParent;
                if (immutableParent && !immutableParent(range.commonAncestorContainer)) {
                    nodes = new ImmutablesRangeEnumerator(range).enumerate();
                }
                return nodes;
            },
            documentFromRange: function (range) {
                var startContainer = range.startContainer;
                return startContainer.nodeType == 9 ? startContainer : startContainer.ownerDocument;
            },
            createRange: function (document) {
                if (browser.msie && browser.version < 9) {
                    return new W3CRange(document);
                }
                return document.createRange();
            },
            selectRange: function (range) {
                var image = RangeUtils.image(range);
                if (image) {
                    range.setStartAfter(image);
                    range.setEndAfter(image);
                }
                var selection = SelectionUtils.selectionFromRange(range);
                selection.removeAllRanges();
                selection.addRange(range);
            },
            stringify: function (range) {
                return kendo.format('{0}:{1} - {2}:{3}', dom.name(range.startContainer), range.startOffset, dom.name(range.endContainer), range.endOffset);
            },
            split: function (range, node, trim) {
                function partition(start) {
                    var partitionRange = range.cloneRange();
                    partitionRange.collapse(start);
                    partitionRange[start ? 'setStartBefore' : 'setEndAfter'](node);
                    var contents = partitionRange.extractContents();
                    if (trim) {
                        contents = dom.trim(contents);
                    }
                    dom[start ? 'insertBefore' : 'insertAfter'](contents, node);
                }
                partition(true);
                partition(false);
            },
            mapAll: function (range, map) {
                var nodes = [];
                new RangeIterator(range).traverse(function (node) {
                    var mapped = map(node);
                    if (mapped && $.inArray(mapped, nodes) < 0) {
                        nodes.push(mapped);
                    }
                });
                return nodes;
            },
            getAll: function (range, predicate) {
                var selector = predicate;
                if (typeof predicate == 'string') {
                    predicate = function (node) {
                        return dom.is(node, selector);
                    };
                }
                return RangeUtils.mapAll(range, function (node) {
                    if (predicate(node)) {
                        return node;
                    }
                });
            },
            getMarkers: function (range) {
                return RangeUtils.getAll(range, function (node) {
                    return node.className == 'k-marker';
                });
            },
            image: function (range) {
                var nodes = RangeUtils.getAll(range, 'img');
                if (nodes.length == 1) {
                    return nodes[0];
                }
            },
            isStartOf: function (originalRange, node) {
                if (originalRange.startOffset !== 0) {
                    return false;
                }
                var range = originalRange.cloneRange();
                while (range.startOffset === 0 && range.startContainer != node) {
                    var index = dom.findNodeIndex(range.startContainer);
                    var parent = range.startContainer.parentNode;
                    while (index > 0 && parent[index - 1] && dom.insignificant(parent[index - 1])) {
                        index--;
                    }
                    range.setStart(parent, index);
                }
                return range.startOffset === 0 && range.startContainer == node;
            },
            isEndOf: function (originalRange, node) {
                var range = originalRange.cloneRange();
                range.collapse(false);
                var start = range.startContainer;
                if (dom.isDataNode(start) && range.startOffset == dom.getNodeLength(start)) {
                    range.setStart(start.parentNode, dom.findNodeIndex(start) + 1);
                    range.collapse(true);
                }
                range.setEnd(node, dom.getNodeLength(node));
                var nodes = [];
                function visit(node) {
                    if (!dom.insignificant(node)) {
                        nodes.push(node);
                    }
                }
                new RangeIterator(range).traverse(visit);
                return !nodes.length;
            },
            wrapSelectedElements: function (range) {
                var startEditable = dom.editableParent(range.startContainer);
                var endEditable = dom.editableParent(range.endContainer);
                while (range.startOffset === 0 && range.startContainer != startEditable) {
                    range.setStart(range.startContainer.parentNode, dom.findNodeIndex(range.startContainer));
                }
                function isEnd(offset, container) {
                    var length = dom.getNodeLength(container);
                    if (offset == length) {
                        return true;
                    }
                    for (var i = offset; i < length; i++) {
                        if (!dom.insignificant(container.childNodes[i])) {
                            return false;
                        }
                    }
                    return true;
                }
                while (isEnd(range.endOffset, range.endContainer) && range.endContainer != endEditable) {
                    range.setEnd(range.endContainer.parentNode, dom.findNodeIndex(range.endContainer) + 1);
                }
                return range;
            },
            expand: function (range) {
                var result = range.cloneRange();
                var startContainer = result.startContainer.childNodes[result.startOffset === 0 ? 0 : result.startOffset - 1];
                var endContainer = result.endContainer.childNodes[result.endOffset];
                if (!isDataNode(startContainer) || !isDataNode(endContainer)) {
                    return result;
                }
                var beforeCaret = startContainer.nodeValue;
                var afterCaret = endContainer.nodeValue;
                if (!beforeCaret || !afterCaret) {
                    return result;
                }
                var startOffset = beforeCaret.split('').reverse().join('').search(boundary);
                var endOffset = afterCaret.search(boundary);
                if (!startOffset || !endOffset) {
                    return result;
                }
                endOffset = endOffset == -1 ? afterCaret.length : endOffset;
                startOffset = startOffset == -1 ? 0 : beforeCaret.length - startOffset;
                result.setStart(startContainer, startOffset);
                result.setEnd(endContainer, endOffset);
                return result;
            },
            isExpandable: function (range) {
                var node = range.startContainer;
                var rangeDocument = RangeUtils.documentFromRange(range);
                if (node == rangeDocument || node == rangeDocument.body) {
                    return false;
                }
                var result = range.cloneRange();
                var value = node.nodeValue;
                if (!value) {
                    return false;
                }
                var beforeCaret = value.substring(0, result.startOffset);
                var afterCaret = value.substring(result.startOffset);
                var startOffset = 0, endOffset = 0;
                if (beforeCaret) {
                    startOffset = beforeCaret.split('').reverse().join('').search(boundary);
                }
                if (afterCaret) {
                    endOffset = afterCaret.search(boundary);
                }
                return startOffset && endOffset;
            }
        };
        extend(Editor, {
            SelectionUtils: SelectionUtils,
            W3CRange: W3CRange,
            RangeIterator: RangeIterator,
            W3CSelection: W3CSelection,
            RangeEnumerator: RangeEnumerator,
            RestorePoint: RestorePoint,
            Marker: Marker,
            RangeUtils: RangeUtils
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/system', ['editor/range'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, editorNS = kendo.ui.editor, EditorUtils = editorNS.EditorUtils, RangeUtils = editorNS.RangeUtils, registerTool = EditorUtils.registerTool, dom = editorNS.Dom, Tool = editorNS.Tool, ToolTemplate = editorNS.ToolTemplate, RestorePoint = editorNS.RestorePoint, Marker = editorNS.Marker, browser = kendo.support.browser, br = '<br class="k-br">', extend = $.extend;
        var nodeTypes = dom.nodeTypes;
        var PREVIOUS_SIBLING = 'previousSibling';
        function finishUpdate(editor, startRestorePoint) {
            var endRestorePoint = editor.selectionRestorePoint = new RestorePoint(editor.getRange(), editor.body);
            var command = new GenericCommand(startRestorePoint, endRestorePoint);
            command.editor = editor;
            editor.undoRedoStack.push(command);
            return endRestorePoint;
        }
        function selected(node, range) {
            return range.startContainer === node && range.endContainer === node && range.startOffset === 0 && range.endOffset == node.childNodes.length;
        }
        function getSibling(node, direction, condition) {
            var sibling = node ? node[direction] : null;
            while (sibling && !condition(sibling)) {
                sibling = sibling[direction];
            }
            return sibling;
        }
        var Command = Class.extend({
            init: function (options) {
                this.options = options;
                this.restorePoint = new RestorePoint(options.range, options.body, { immutables: options.immutables });
                this.marker = new Marker();
                this.formatter = options.formatter;
            },
            getRange: function () {
                return this.restorePoint.toRange();
            },
            lockRange: function (expand) {
                return this.marker.add(this.getRange(), expand);
            },
            releaseRange: function (range) {
                this.marker.remove(range);
                this.editor.selectRange(range);
            },
            undo: function () {
                var point = this.restorePoint;
                point.restoreHtml();
                this.editor.selectRange(point.toRange());
            },
            redo: function () {
                this.exec();
            },
            createDialog: function (content, options) {
                var editor = this.editor;
                return $(content).appendTo(document.body).kendoWindow(extend({}, editor.options.dialogOptions, options)).closest('.k-window').toggleClass('k-rtl', kendo.support.isRtl(editor.wrapper)).end();
            },
            exec: function () {
                var range = this.lockRange(true);
                this.formatter.editor = this.editor;
                this.formatter.toggle(range);
                this.releaseRange(range);
            },
            immutables: function () {
                return this.editor && this.editor.options.immutables;
            },
            expandImmutablesIn: function (range) {
                if (this.immutables()) {
                    kendo.ui.editor.Immutables.expandImmutablesIn(range);
                    this.restorePoint = new RestorePoint(range, this.editor.body);
                }
            }
        });
        var GenericCommand = Class.extend({
            init: function (startRestorePoint, endRestorePoint) {
                this.body = startRestorePoint.body;
                this.startRestorePoint = startRestorePoint;
                this.endRestorePoint = endRestorePoint;
            },
            redo: function () {
                dom.removeChildren(this.body);
                this.body.innerHTML = this.endRestorePoint.html;
                this.editor.selectRange(this.endRestorePoint.toRange());
            },
            undo: function () {
                dom.removeChildren(this.body);
                this.body.innerHTML = this.startRestorePoint.html;
                this.editor.selectRange(this.startRestorePoint.toRange());
            }
        });
        var InsertHtmlCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this.managesUndoRedo = true;
            },
            exec: function () {
                var editor = this.editor;
                var options = this.options;
                var range = options.range;
                var body = editor.body;
                var startRestorePoint = new RestorePoint(range, body);
                var html = options.html || options.value || '';
                editor.selectRange(range);
                editor.clipboard.paste(html, options);
                if (options.postProcess) {
                    options.postProcess(editor, editor.getRange());
                }
                var genericCommand = new GenericCommand(startRestorePoint, new RestorePoint(editor.getRange(), body));
                genericCommand.editor = editor;
                editor.undoRedoStack.push(genericCommand);
                editor.focus();
            }
        });
        var InsertHtmlTool = Tool.extend({
            initialize: function (ui, initOptions) {
                var editor = initOptions.editor, options = this.options, dataSource = options.items ? options.items : editor.options.insertHtml;
                this._selectBox = new editorNS.SelectBox(ui, {
                    dataSource: dataSource,
                    dataTextField: 'text',
                    dataValueField: 'value',
                    change: function () {
                        Tool.exec(editor, 'insertHtml', this.value());
                    },
                    title: editor.options.messages.insertHtml,
                    highlightFirst: false
                });
            },
            command: function (commandArguments) {
                return new InsertHtmlCommand(commandArguments);
            },
            update: function (ui) {
                var selectbox = ui.data('kendoSelectBox') || ui.find('select').data('kendoSelectBox');
                selectbox.close();
                selectbox.value(selectbox.options.title);
            }
        });
        var tableCells = 'td,th,caption';
        var tableCellsWrappers = 'table,tbody,thead,tfoot,tr';
        var tableElements = tableCellsWrappers + ',' + tableCells;
        var inTable = function (range) {
            return !range.collapsed && $(range.commonAncestorContainer).is(tableCellsWrappers);
        };
        var RemoveTableContent = Class.extend({
            remove: function (range) {
                var that = this;
                var marker = new Marker();
                marker.add(range, false);
                var nodes = RangeUtils.getAll(range, function (node) {
                    return $(node).is(tableElements);
                });
                var doc = RangeUtils.documentFromRange(range);
                var start = marker.start;
                var end = marker.end;
                var cellsTypes = tableCells.split(',');
                var startCell = dom.parentOfType(start, cellsTypes);
                var endCell = dom.parentOfType(end, cellsTypes);
                that._removeContent(start, startCell, true);
                that._removeContent(end, endCell, false);
                $(nodes).each(function (i, node) {
                    node = $(node);
                    (node.is(tableCells) ? node : node.find(tableCells)).each(function (j, cell) {
                        cell.innerHTML = '&#65279;';
                    });
                });
                if (startCell && !start.previousSibling) {
                    dom.insertBefore(doc.createTextNode('\uFEFF'), start);
                }
                if (endCell && !end.nextSibling) {
                    dom.insertAfter(doc.createTextNode('\uFEFF'), end);
                }
                if (startCell) {
                    range.setStartBefore(start);
                } else if (nodes[0]) {
                    startCell = $(nodes[0]);
                    startCell = startCell.is(tableCells) ? startCell : startCell.find(tableCells).first();
                    if (startCell.length) {
                        range.setStart(startCell.get(0), 0);
                    }
                }
                range.collapse(true);
                dom.remove(start);
                dom.remove(end);
            },
            _removeContent: function (start, top, forwards) {
                if (top) {
                    var sibling = forwards ? 'nextSibling' : 'previousSibling', next, getNext = function (node) {
                            while (node && !node[sibling]) {
                                node = node.parentNode;
                            }
                            return node && $.contains(top, node) ? node[sibling] : null;
                        };
                    start = getNext(start);
                    while (start) {
                        next = getNext(start);
                        dom.remove(start);
                        start = next;
                    }
                }
            }
        });
        var TypingHandler = Class.extend({
            init: function (editor) {
                this.editor = editor;
            },
            keydown: function (e) {
                var that = this, editor = that.editor, keyboard = editor.keyboard, isTypingKey = keyboard.isTypingKey(e), evt = extend($.Event(), e);
                that.editor.trigger('keydown', evt);
                if (evt.isDefaultPrevented()) {
                    e.preventDefault();
                    return true;
                }
                if (!evt.isDefaultPrevented() && isTypingKey && !keyboard.isTypingInProgress()) {
                    var range = editor.getRange();
                    var body = editor.body;
                    that.startRestorePoint = new RestorePoint(range, body);
                    if (inTable(range)) {
                        var removeTableContent = new RemoveTableContent(editor);
                        removeTableContent.remove(range);
                        editor.selectRange(range);
                    }
                    if (browser.webkit && !range.collapsed && selected(body, range)) {
                        body.innerHTML = '';
                    }
                    if (editor.immutables && editorNS.Immutables.immutablesContext(range)) {
                        var backspaceHandler = new editorNS.BackspaceHandler(editor);
                        backspaceHandler.deleteSelection(range);
                    }
                    keyboard.startTyping(function () {
                        that.endRestorePoint = finishUpdate(editor, that.startRestorePoint);
                    });
                    return true;
                }
                return false;
            },
            keyup: function (e) {
                var keyboard = this.editor.keyboard;
                this.editor.trigger('keyup', e);
                if (keyboard.isTypingInProgress()) {
                    keyboard.endTyping();
                    return true;
                }
                return false;
            }
        });
        var BackspaceHandler = Class.extend({
            init: function (editor) {
                this.editor = editor;
            },
            _addCaret: function (container) {
                var caret = dom.create(this.editor.document, 'a');
                dom.insertAt(container, caret, 0);
                dom.stripBomNode(caret.previousSibling);
                dom.stripBomNode(caret.nextSibling);
                return caret;
            },
            _restoreCaret: function (caret) {
                var range = this.editor.createRange();
                range.setStartAfter(caret);
                range.collapse(true);
                this.editor.selectRange(range);
                dom.remove(caret);
            },
            _handleDelete: function (range) {
                var node = range.endContainer;
                var block = dom.closestEditableOfType(node, dom.blockElements);
                if (block && editorNS.RangeUtils.isEndOf(range, block)) {
                    var next = dom.next(block);
                    if (!next || dom.name(next) != 'p') {
                        return false;
                    }
                    var caret = this._addCaret(next);
                    this._merge(block, next);
                    this._restoreCaret(caret);
                    return true;
                }
                return false;
            },
            _cleanBomBefore: function (range) {
                var offset = range.startOffset;
                var node = range.startContainer;
                var text = node.nodeValue;
                var count = 0;
                while (offset - count >= 0 && text[offset - count - 1] == '\uFEFF') {
                    count++;
                }
                if (count > 0) {
                    node.deleteData(offset - count, count);
                    range.setStart(node, Math.max(0, offset - count));
                    range.collapse(true);
                    this.editor.selectRange(range);
                }
            },
            _handleBackspace: function (range) {
                var node = range.startContainer;
                var li = dom.closestEditableOfType(node, ['li']);
                var block = dom.closestEditableOfType(node, 'p,h1,h2,h3,h4,h5,h6'.split(','));
                var editor = this.editor;
                var previousSibling;
                if (dom.isDataNode(node)) {
                    this._cleanBomBefore(range);
                }
                previousSibling = getSibling(block, PREVIOUS_SIBLING, function (sibling) {
                    return !dom.htmlIndentSpace(sibling);
                });
                if (range.collapsed && range.startOffset !== range.endOffset && range.startOffset < 0) {
                    range.startOffset = 0;
                    range.endOffset = 0;
                    editor.selectRange(range);
                }
                if (block && previousSibling && editorNS.RangeUtils.isStartOf(range, block)) {
                    var caret = this._addCaret(block);
                    this._merge(previousSibling, block);
                    this._restoreCaret(caret);
                    return true;
                }
                if (li && editorNS.RangeUtils.isStartOf(range, li)) {
                    var child = li.firstChild;
                    if (!child) {
                        li.innerHTML = editorNS.emptyElementContent;
                        child = li.firstChild;
                    }
                    var formatter = new editorNS.ListFormatter(dom.name(li.parentNode), 'p');
                    range.selectNodeContents(li);
                    formatter.toggle(range);
                    if (dom.insignificant(child)) {
                        range.setStartBefore(child);
                    } else {
                        range.setStart(child, 0);
                    }
                    editor.selectRange(range);
                    return true;
                }
                var linkRange = range;
                var previousNode = node.previousSibling;
                if (linkRange.startOffset === 0 && previousNode && previousNode.nodeName.toLowerCase() === 'a') {
                    linkRange = editor.createRange();
                    linkRange.setStart(previousNode, previousNode.childNodes.length);
                    linkRange.setEnd(previousNode, previousNode.childNodes.length);
                }
                var a = dom.closestEditableOfType(linkRange.startContainer, ['a']);
                var isEndOfLink = a && editorNS.RangeUtils.isEndOf(linkRange, a);
                if (isEndOfLink) {
                    var command = new editorNS.UnlinkCommand({
                        range: linkRange,
                        body: editor.body,
                        immutables: !!editor.immutables
                    });
                    editor.execCommand(command);
                    editor._selectionChange();
                }
                return false;
            },
            _handleSelection: function (range) {
                var ancestor = range.commonAncestorContainer;
                var table = dom.closest(ancestor, 'table');
                var emptyParagraphContent = editorNS.emptyElementContent;
                var editor = this.editor;
                if (inTable(range)) {
                    var removeTableContent = new RemoveTableContent(editor);
                    removeTableContent.remove(range);
                    editor.selectRange(range);
                    return true;
                }
                var marker = new Marker();
                marker.add(range, false);
                if (editor.immutables) {
                    this._handleImmutables(marker);
                }
                this._surroundFullySelectedAnchor(marker, range);
                range.setStartAfter(marker.start);
                range.setEndBefore(marker.end);
                var start = range.startContainer;
                var end = range.endContainer;
                range.deleteContents();
                if (table && $(table).text() === '') {
                    range.selectNode(table);
                    range.deleteContents();
                }
                ancestor = range.commonAncestorContainer;
                if (dom.name(ancestor) === 'p' && ancestor.innerHTML === '') {
                    ancestor.innerHTML = emptyParagraphContent;
                    range.setStart(ancestor, 0);
                }
                this._join(start, end);
                dom.insertAfter(editor.document.createTextNode('\uFEFF'), marker.start);
                marker.remove(range);
                start = range.startContainer;
                if (dom.name(start) == 'tr') {
                    start = start.childNodes[Math.max(0, range.startOffset - 1)];
                    range.setStart(start, dom.getNodeLength(start));
                }
                range.collapse(true);
                editor.selectRange(range);
                return true;
            },
            _handleImmutables: function (marker) {
                var immutableParent = editorNS.Immutables.immutableParent;
                var startImmutable = immutableParent(marker.start);
                var endImmutable = immutableParent(marker.start);
                if (startImmutable) {
                    dom.insertBefore(marker.start, startImmutable);
                }
                if (endImmutable) {
                    dom.insertAfter(marker.end, endImmutable);
                }
                if (startImmutable) {
                    dom.remove(startImmutable);
                }
                if (endImmutable && endImmutable.parentNode) {
                    dom.remove(endImmutable);
                }
            },
            _surroundFullySelectedAnchor: function (marker, range) {
                var start = marker.start, startParent = $(start).closest('a').get(0), end = marker.end, endParent = $(end).closest('a').get(0);
                if (startParent && RangeUtils.isStartOf(range, startParent)) {
                    dom.insertBefore(start, startParent);
                }
                if (endParent && RangeUtils.isEndOf(range, endParent)) {
                    dom.insertAfter(end, endParent);
                }
            },
            _root: function (node) {
                while (node && node.parentNode && dom.name(node.parentNode) != 'body') {
                    node = node.parentNode;
                }
                return node;
            },
            _join: function (start, end) {
                start = this._root(start);
                end = this._root(end);
                if (start != end && dom.is(end, 'p')) {
                    this._merge(start, end);
                }
            },
            _merge: function (dest, src) {
                dom.removeTrailingBreak(dest);
                while (dest && src.firstChild) {
                    if (dest.nodeType == 1) {
                        dest = dom.list(dest) ? dest.children[dest.children.length - 1] : dest;
                        if (dest) {
                            dest.appendChild(src.firstChild);
                        }
                    } else if (dest.nodeType === nodeTypes.TEXT_NODE) {
                        this._mergeWithTextNode(dest, src.firstChild);
                    } else {
                        dest.parentNode.appendChild(src.firstChild);
                    }
                }
                dom.remove(src);
            },
            _mergeWithTextNode: function (textNode, appendedNode) {
                if (textNode && textNode.nodeType === nodeTypes.TEXT_NODE) {
                    if (textNode.nextSibling && this._isCaret(textNode.nextSibling)) {
                        dom.insertAfter(appendedNode, textNode.nextSibling);
                    } else {
                        dom.insertAfter(appendedNode, textNode);
                    }
                }
            },
            _isCaret: function (element) {
                return $(element).is('a');
            },
            keydown: function (e) {
                var method, startRestorePoint;
                var editor = this.editor;
                var range = editor.getRange();
                var keyCode = e.keyCode;
                var keys = kendo.keys;
                var backspace = keyCode === keys.BACKSPACE;
                var del = keyCode == keys.DELETE;
                if (editor.immutables && editor.immutables.keydown(e, range)) {
                    return;
                }
                if ((backspace || del) && !range.collapsed) {
                    method = '_handleSelection';
                } else if (backspace) {
                    method = '_handleBackspace';
                } else if (del) {
                    method = '_handleDelete';
                }
                if (!method) {
                    return;
                }
                startRestorePoint = new RestorePoint(range, editor.body);
                if (this[method](range)) {
                    e.preventDefault();
                    finishUpdate(editor, startRestorePoint);
                }
            },
            deleteSelection: function (range) {
                this._handleSelection(range);
            },
            keyup: $.noop
        });
        var SystemHandler = Class.extend({
            init: function (editor) {
                this.editor = editor;
                this.systemCommandIsInProgress = false;
            },
            createUndoCommand: function () {
                this.startRestorePoint = this.endRestorePoint = finishUpdate(this.editor, this.startRestorePoint);
            },
            changed: function () {
                if (this.startRestorePoint) {
                    return this.startRestorePoint.html != this.editor.body.innerHTML;
                }
                return false;
            },
            keydown: function (e) {
                var that = this, editor = that.editor, keyboard = editor.keyboard;
                if (keyboard.isModifierKey(e)) {
                    if (keyboard.isTypingInProgress()) {
                        keyboard.endTyping(true);
                    }
                    that.startRestorePoint = new RestorePoint(editor.getRange(), editor.body);
                    return true;
                }
                if (keyboard.isSystem(e)) {
                    that.systemCommandIsInProgress = true;
                    if (that.changed()) {
                        that.systemCommandIsInProgress = false;
                        that.createUndoCommand();
                    }
                    return true;
                }
                return false;
            },
            keyup: function () {
                var that = this;
                if (that.systemCommandIsInProgress && that.changed()) {
                    that.systemCommandIsInProgress = false;
                    that.createUndoCommand();
                    return true;
                }
                return false;
            }
        });
        var SelectAllHandler = Class.extend({
            init: function (editor) {
                this.editor = editor;
            },
            keydown: function (e) {
                if (!browser.webkit || e.isDefaultPrevented() || !(e.ctrlKey && e.keyCode == 65 && !e.altKey && !e.shiftKey)) {
                    return;
                }
                if (this.editor.options.immutables) {
                    this._toSelectableImmutables();
                }
                this._selectEditorBody();
            },
            _selectEditorBody: function () {
                var editor = this.editor;
                var range = editor.getRange();
                range.selectNodeContents(editor.body);
                editor.selectRange(range);
            },
            _toSelectableImmutables: function () {
                var editor = this.editor, body = editor.body, immutable = editorNS.Immutables.immutable, emptyTextNode = dom.emptyTextNode, first = body.firstChild, last = body.lastChild;
                while (emptyTextNode(first)) {
                    first = first.nextSibling;
                }
                while (emptyTextNode(last)) {
                    last = last.previousSibling;
                }
                if (first && immutable(first)) {
                    $(br).prependTo(body);
                }
                if (last && immutable(last)) {
                    $(br).appendTo(body);
                }
            },
            keyup: $.noop
        });
        var Keyboard = Class.extend({
            init: function (handlers) {
                this.handlers = handlers;
                this.typingInProgress = false;
            },
            isCharacter: function (keyCode) {
                return keyCode >= 48 && keyCode <= 90 || keyCode >= 96 && keyCode <= 111 || keyCode >= 186 && keyCode <= 192 || keyCode >= 219 && keyCode <= 222 || keyCode == 229;
            },
            toolFromShortcut: function (tools, e) {
                var key = String.fromCharCode(e.keyCode), toolName, toolOptions, modifier = this._getShortcutModifier(e, navigator.platform);
                for (toolName in tools) {
                    toolOptions = $.extend({
                        ctrl: false,
                        alt: false,
                        shift: false
                    }, tools[toolName].options);
                    if ((toolOptions.key == key || toolOptions.key == e.keyCode) && toolOptions.ctrl == modifier && toolOptions.alt == e.altKey && toolOptions.shift == e.shiftKey) {
                        return toolName;
                    }
                }
            },
            _getShortcutModifier: function (e, platform) {
                var mac = platform.toUpperCase().indexOf('MAC') >= 0;
                return mac ? e.metaKey : e.ctrlKey;
            },
            toolsFromShortcut: function (tools, e) {
                var key = String.fromCharCode(e.keyCode), toolName, o, matchesKey, found = [];
                var matchKey = function (toolKey) {
                    return toolKey == key || toolKey == e.keyCode || toolKey == e.charCode;
                };
                for (toolName in tools) {
                    o = $.extend({
                        ctrl: false,
                        alt: false,
                        shift: false
                    }, tools[toolName].options);
                    matchesKey = $.isArray(o.key) ? $.grep(o.key, matchKey).length > 0 : matchKey(o.key);
                    if (matchesKey && o.ctrl == e.ctrlKey && o.alt == e.altKey && o.shift == e.shiftKey) {
                        found.push(tools[toolName]);
                    }
                }
                return found;
            },
            isTypingKey: function (e) {
                var keyCode = e.keyCode;
                return this.isCharacter(keyCode) && !e.ctrlKey && !e.altKey || keyCode == 32 || keyCode == 13 || keyCode == 8 || keyCode == 46 && !e.shiftKey && !e.ctrlKey && !e.altKey;
            },
            isModifierKey: function (e) {
                var keyCode = e.keyCode;
                return keyCode == 17 && !e.shiftKey && !e.altKey || keyCode == 16 && !e.ctrlKey && !e.altKey || keyCode == 18 && !e.ctrlKey && !e.shiftKey;
            },
            isSystem: function (e) {
                return e.keyCode == 46 && e.ctrlKey && !e.altKey && !e.shiftKey;
            },
            startTyping: function (callback) {
                this.onEndTyping = callback;
                this.typingInProgress = true;
            },
            stopTyping: function () {
                if (this.typingInProgress && this.onEndTyping) {
                    this.onEndTyping();
                }
                this.typingInProgress = false;
            },
            endTyping: function (force) {
                var that = this;
                that.clearTimeout();
                if (force) {
                    that.stopTyping();
                } else {
                    that.timeout = window.setTimeout($.proxy(that.stopTyping, that), 1000);
                }
            },
            isTypingInProgress: function () {
                return this.typingInProgress;
            },
            clearTimeout: function () {
                window.clearTimeout(this.timeout);
            },
            notify: function (e, what) {
                var i, handlers = this.handlers;
                for (i = 0; i < handlers.length; i++) {
                    if (handlers[i][what](e)) {
                        break;
                    }
                }
            },
            keydown: function (e) {
                this.notify(e, 'keydown');
            },
            keyup: function (e) {
                this.notify(e, 'keyup');
            }
        });
        var Clipboard = Class.extend({
            init: function (editor) {
                this.editor = editor;
                var pasteCleanup = editor.options.pasteCleanup;
                this.cleaners = [
                    new ScriptCleaner(pasteCleanup),
                    new TabCleaner(pasteCleanup),
                    new MSWordFormatCleaner(pasteCleanup),
                    new WebkitFormatCleaner(pasteCleanup),
                    new HtmlTagsCleaner(pasteCleanup),
                    new HtmlAttrCleaner(pasteCleanup),
                    new HtmlContentCleaner(pasteCleanup),
                    new CustomCleaner(pasteCleanup)
                ];
            },
            htmlToFragment: function (html) {
                var editor = this.editor, doc = editor.document, container = dom.create(doc, 'div'), fragment = doc.createDocumentFragment();
                container.innerHTML = html;
                while (container.firstChild) {
                    fragment.appendChild(container.firstChild);
                }
                return fragment;
            },
            isBlock: function (html) {
                return /<(div|p|ul|ol|table|h[1-6])/i.test(html);
            },
            _startModification: function () {
                var range;
                var restorePoint;
                var editor = this.editor;
                if (this._inProgress) {
                    return;
                }
                this._inProgress = true;
                range = editor.getRange();
                restorePoint = new RestorePoint(range, editor.body);
                dom.persistScrollTop(editor.document);
                return {
                    range: range,
                    restorePoint: restorePoint
                };
            },
            _endModification: function (modificationInfo) {
                finishUpdate(this.editor, modificationInfo.restorePoint);
                this.editor._selectionChange();
                this._inProgress = false;
            },
            _contentModification: function (before, after) {
                var that = this;
                var editor = that.editor;
                var modificationInfo = that._startModification();
                if (!modificationInfo) {
                    return;
                }
                before.call(that, editor, modificationInfo.range);
                setTimeout(function () {
                    after.call(that, editor, modificationInfo.range);
                    that._endModification(modificationInfo);
                });
            },
            _removeBomNodes: function (range) {
                var nodes = editorNS.RangeUtils.textNodes(range);
                for (var i = 0; i < nodes.length; i++) {
                    nodes[i].nodeValue = dom.stripBom(nodes[i].nodeValue);
                }
            },
            _onBeforeCopy: function (range) {
                var marker = new Marker();
                marker.add(range);
                this._removeBomNodes(range);
                marker.remove(range);
                this.editor.selectRange(range);
            },
            oncopy: function () {
                this._onBeforeCopy(this.editor.getRange());
            },
            oncut: function () {
                this._onBeforeCopy(this.editor.getRange());
                this._contentModification($.noop, $.noop);
            },
            _fileToDataURL: function (blob) {
                var deferred = $.Deferred();
                var reader = new FileReader();
                if (!(blob instanceof window.File) && blob.getAsFile) {
                    blob = blob.getAsFile();
                }
                reader.onload = $.proxy(deferred.resolve, deferred);
                reader.readAsDataURL(blob);
                return deferred.promise();
            },
            _triggerPaste: function (html, options) {
                var args = { html: html || '' };
                args.html = args.html.replace(/\ufeff/g, '');
                this.editor.trigger('paste', args);
                this.paste(args.html, options || {});
            },
            _handleImagePaste: function (e) {
                if (!('FileReader' in window) || browser.msie && browser.version > 10) {
                    return;
                }
                var clipboardData = e.clipboardData || e.originalEvent.clipboardData || window.clipboardData || {};
                var items = clipboardData.items || clipboardData.files;
                if (!items) {
                    return;
                }
                var images = $.grep(items, function (item) {
                    return /^image\//i.test(item.type);
                });
                var html = $.grep(items, function (item) {
                    return /^text\/html/i.test(item.type);
                });
                if (html.length || !images.length) {
                    return;
                }
                var modificationInfo = this._startModification();
                if (!modificationInfo) {
                    return;
                }
                $.when.apply($, $.map(images, this._fileToDataURL)).done($.proxy(function () {
                    var results = Array.prototype.slice.call(arguments);
                    var html = $.map(results, function (e) {
                        return '<img src="' + e.target.result + '" />';
                    }).join('');
                    this._triggerPaste(html);
                    this._endModification(modificationInfo);
                }, this));
                return true;
            },
            onpaste: function (e) {
                if (this._handleImagePaste(e)) {
                    e.preventDefault();
                    return;
                }
                this.expandImmutablesIn();
                this._contentModification(function beforePaste(editor, range) {
                    var clipboardNode = dom.create(editor.document, 'div', {
                        className: 'k-paste-container',
                        innerHTML: '\uFEFF'
                    });
                    var browser = kendo.support.browser;
                    var body = editor.body;
                    this._decoreateClipboardNode(clipboardNode, body);
                    body.appendChild(clipboardNode);
                    if (browser.webkit) {
                        this._moveToCaretPosition(clipboardNode, range);
                    }
                    if (browser.msie && browser.version < 11) {
                        e.preventDefault();
                        var r = editor.createRange();
                        r.selectNodeContents(clipboardNode);
                        editor.selectRange(r);
                        var textRange = editor.document.body.createTextRange();
                        textRange.moveToElementText(clipboardNode);
                        $(body).unbind('paste');
                        textRange.execCommand('Paste');
                        $(body).bind('paste', $.proxy(this.onpaste, this));
                    } else {
                        var clipboardRange = editor.createRange();
                        clipboardRange.selectNodeContents(clipboardNode);
                        editor.selectRange(clipboardRange);
                    }
                    range.deleteContents();
                }, function afterPaste(editor, range) {
                    var html = '', containers;
                    editor.selectRange(range);
                    containers = $(editor.body).children('.k-paste-container');
                    containers.each(function () {
                        var lastChild = this.lastChild;
                        if (lastChild && dom.is(lastChild, 'br')) {
                            dom.remove(lastChild);
                        }
                        html += this.innerHTML;
                    });
                    containers.remove();
                    this._triggerPaste(html, { clean: true });
                });
            },
            _decoreateClipboardNode: function (node, body) {
                if (!browser.msie && !browser.webkit) {
                    return;
                }
                node = $(node);
                node.css({
                    borderWidth: '0px',
                    width: '0px',
                    height: '0px',
                    overflow: 'hidden',
                    margin: '0',
                    padding: '0'
                });
                if (browser.msie) {
                    var documentElement = $(body.ownerDocument.documentElement);
                    node.css({
                        fontVariant: 'normal',
                        fontWeight: 'normal',
                        lineSpacing: 'normal',
                        lineHeight: 'normal',
                        textDecoration: 'none'
                    });
                    var color = documentElement.css('color');
                    if (color) {
                        node.css('color', color);
                    }
                    var fontFamily = documentElement.css('fontFamily');
                    if (fontFamily) {
                        node.css('fontFamily', fontFamily);
                    }
                    var fontSize = documentElement.css('fontSize');
                    if (fontSize) {
                        node.css('fontSize', fontSize);
                    }
                }
            },
            _moveToCaretPosition: function (node, range) {
                var that = this;
                var body = that.editor.body;
                var nodeOffset = dom.offset(node, body);
                var caretOffset = that._caretOffset(range, body);
                var translateX = caretOffset.left - nodeOffset.left;
                var translateY = caretOffset.top - nodeOffset.top;
                var translate = 'translate(' + translateX + 'px,' + translateY + 'px)';
                $(node).css({
                    '-webkit-transform': translate,
                    'transform': translate
                });
            },
            _caretOffset: function (range, body) {
                var editor = this.editor;
                var caret = dom.create(editor.document, 'span', { innerHTML: '\uFEFF' });
                var startContainer = range.startContainer;
                var rangeChanged;
                if (range.collapsed) {
                    var isStartTextNode = dom.isDataNode(startContainer);
                    if (isStartTextNode && (dom.isBom(startContainer) || range.startOffset === 0)) {
                        dom.insertBefore(caret, startContainer);
                    } else if (isStartTextNode && range.startOffset === startContainer.length) {
                        dom.insertAfter(caret, startContainer);
                    } else {
                        range.insertNode(caret);
                        rangeChanged = true;
                    }
                } else {
                    startContainer = startContainer === body ? startContainer.childNodes[range.startOffset] : startContainer;
                    dom.insertBefore(caret, startContainer);
                }
                var offset = dom.offset(caret, body);
                var prev = caret.previousSibling;
                var next = caret.nextSibling;
                dom.remove(caret);
                if (rangeChanged && dom.isDataNode(prev) && dom.isDataNode(next) && !dom.isBom(prev) && !dom.isBom(next)) {
                    var prevLength = prev.length;
                    next.data = prev.data + next.data;
                    range.setStart(next, prevLength);
                    dom.remove(prev);
                    range.collapse(true);
                    editor.selectRange(range);
                }
                return offset;
            },
            expandImmutablesIn: function (range) {
                var editor = this.editor;
                if (editor && editor.options.immutables) {
                    var body = editor.body;
                    range = range || editor.getRange();
                    kendo.ui.editor.Immutables.expandImmutablesIn(range);
                    if (range.startContainer === body && range.startOffset === 0) {
                        var doc = body.ownerDocument;
                        var bomNode = doc.createTextNode('\uFEFF');
                        body.insertBefore(bomNode, body.childNodes[0]);
                        range.setStartBefore(bomNode);
                    }
                    editor.selectRange(range);
                }
            },
            splittableParent: function (block, node) {
                var parentNode, body;
                if (block) {
                    return dom.closestEditableOfType(node, [
                        'p',
                        'ul',
                        'ol'
                    ]) || node.parentNode;
                }
                parentNode = node.parentNode;
                body = node.ownerDocument.body;
                if (dom.isInline(parentNode)) {
                    while (parentNode.parentNode != body && !dom.isBlock(parentNode.parentNode)) {
                        parentNode = parentNode.parentNode;
                    }
                }
                return parentNode;
            },
            paste: function (html, options) {
                var editor = this.editor, i, l;
                this.expandImmutablesIn();
                options = extend({
                    clean: false,
                    split: true
                }, options);
                if (!options.skipCleaners) {
                    for (i = 0, l = this.cleaners.length; i < l; i++) {
                        if (this.cleaners[i].applicable(html)) {
                            html = this.cleaners[i].clean(html);
                        }
                    }
                }
                if (options.clean) {
                    html = html.replace(/(<br>(\s|&nbsp;)*)+(<\/?(div|p|li|col|t))/gi, '$3');
                    html = html.replace(/<(a|span)[^>]*><\/\1>/gi, '');
                }
                html = html.replace(/^<li/i, '<ul><li').replace(/li>$/g, 'li></ul>');
                var block = this.isBlock(html);
                editor.focus();
                var range = editor.getRange();
                range.deleteContents();
                if (range.startContainer == editor.document) {
                    range.selectNodeContents(editor.body);
                }
                var marker = new Marker();
                var caret = marker.addCaret(range);
                var parent = this.splittableParent(block, caret);
                var unwrap = false;
                var splittable = parent != editor.body && !dom.is(parent, 'td');
                if (options.split && splittable && (block || dom.isInline(parent))) {
                    range.selectNode(caret);
                    editorNS.RangeUtils.split(range, parent, true);
                    unwrap = true;
                }
                var fragment = this.htmlToFragment(html);
                if (fragment.firstChild && fragment.firstChild.className === 'k-paste-container') {
                    var fragmentsHtml = [];
                    for (i = 0, l = fragment.childNodes.length; i < l; i++) {
                        fragmentsHtml.push(fragment.childNodes[i].innerHTML);
                    }
                    fragment = this.htmlToFragment(fragmentsHtml.join('<br />'));
                }
                $(fragment.childNodes).filter('table').addClass('k-table').end().find('table').addClass('k-table');
                range.insertNode(fragment);
                parent = this.splittableParent(block, caret);
                if (unwrap) {
                    while (caret.parentNode != parent) {
                        dom.unwrap(caret.parentNode);
                    }
                    dom.unwrap(caret.parentNode);
                }
                dom.normalize(range.commonAncestorContainer);
                caret.style.display = 'inline';
                dom.restoreScrollTop(editor.document);
                dom.scrollTo(caret);
                marker.removeCaret(range);
                var rangeEnd = range.commonAncestorContainer.parentNode;
                if (range.collapsed && dom.name(rangeEnd) == 'tbody') {
                    range.setStartAfter($(rangeEnd).closest('table')[0]);
                    range.collapse(true);
                }
                editor.selectRange(range);
            }
        });
        var Cleaner = Class.extend({
            init: function (options) {
                this.options = options || {};
                this.replacements = [];
            },
            clean: function (html, customReplacements) {
                var that = this, replacements = customReplacements || that.replacements, i, l;
                for (i = 0, l = replacements.length; i < l; i += 2) {
                    html = html.replace(replacements[i], replacements[i + 1]);
                }
                return html;
            }
        });
        var ScriptCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                this.replacements = [
                    /<(\/?)script([^>]*)>/i,
                    '<$1telerik:script$2>'
                ];
            },
            applicable: function (html) {
                return !this.options.none && /<script[^>]*>/i.test(html);
            }
        });
        var TabCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                var replacement = ' ';
                this.replacements = [
                    /<span\s+class="Apple-tab-span"[^>]*>\s*<\/span>/gi,
                    replacement,
                    /\t/gi,
                    replacement,
                    /&nbsp;&nbsp; &nbsp;/gi,
                    replacement
                ];
            },
            applicable: function (html) {
                return /&nbsp;&nbsp; &nbsp;|class="?Apple-tab-span/i.test(html);
            }
        });
        var MSWordFormatCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                this.junkReplacements = [
                    /<\?xml[^>]*>/gi,
                    '',
                    /<!--(.|\n)*?-->/g,
                    '',
                    /&quot;/g,
                    '\'',
                    /<o:p>&nbsp;<\/o:p>/gi,
                    '&nbsp;',
                    /<\/?(meta|link|style|o:|v:|x:)[^>]*>((?:.|\n)*?<\/(meta|link|style|o:|v:|x:)[^>]*>)?/gi,
                    '',
                    /<\/o>/g,
                    ''
                ];
                this.replacements = this.junkReplacements.concat([
                    /(?:<br>&nbsp;[\s\r\n]+|<br>)*(<\/?(h[1-6]|hr|p|div|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|address|pre|form|blockquote|dl|dt|dd|dir|fieldset)[^>]*>)(?:<br>&nbsp;[\s\r\n]+|<br>)*/g,
                    '$1',
                    /<br><br>/g,
                    '<BR><BR>',
                    /<br>(?!\n)/g,
                    ' ',
                    /<table([^>]*)>(\s|&nbsp;)+<t/gi,
                    '<table$1><t',
                    /<tr[^>]*>(\s|&nbsp;)*<\/tr>/gi,
                    '',
                    /<tbody[^>]*>(\s|&nbsp;)*<\/tbody>/gi,
                    '',
                    /<table[^>]*>(\s|&nbsp;)*<\/table>/gi,
                    '',
                    /<BR><BR>/g,
                    '<br>',
                    /^\s*(&nbsp;)+/gi,
                    '',
                    /(&nbsp;|<br[^>]*>)+\s*$/gi,
                    '',
                    /mso-[^;"]*;?/gi,
                    '',
                    /<(\/?)b(\s[^>]*)?>/gi,
                    '<$1strong$2>',
                    /<(\/?)font(\s[^>]*)?>/gi,
                    this.convertFontMatch,
                    /<(\/?)i(\s[^>]*)?>/gi,
                    '<$1em$2>',
                    /style=(["|'])\s*\1/g,
                    '',
                    /(<br[^>]*>)?\n/g,
                    function ($0, $1) {
                        return $1 ? $0 : ' ';
                    }
                ]);
            },
            convertFontMatch: function (match, closing, args) {
                var faceRe = /face=['"]([^'"]+)['"]/i;
                var face = faceRe.exec(args);
                var family = args && face && face[1];
                if (closing) {
                    return '</span>';
                } else if (family) {
                    return '<span style="font-family:' + family + '">';
                } else {
                    return '<span>';
                }
            },
            applicable: function (html) {
                return /class="?Mso/i.test(html) || /style="[^"]*mso-/i.test(html) || /urn:schemas-microsoft-com:office/.test(html);
            },
            stripEmptyAnchors: function (html) {
                return html.replace(/<a([^>]*)>\s*<\/a>/gi, function (a, attributes) {
                    if (!attributes || attributes.indexOf('href') < 0) {
                        return '';
                    }
                    return a;
                });
            },
            listType: function (p, listData) {
                var html = p.innerHTML;
                var text = dom.innerText(p);
                var startingSymbol;
                var matchSymbol = html.match(/^(?:<span [^>]*texhtml[^>]*>)?<span [^>]*(?:Symbol|Wingdings)[^>]*>([^<]+)/i);
                var symbol = matchSymbol && matchSymbol[1];
                var isNumber = /^[a-z\d]/i.test(symbol);
                var trimStartText = function (text) {
                    return text.replace(/^(?:&nbsp;|[\u00a0\n\r\s])+/, '');
                };
                if (matchSymbol) {
                    startingSymbol = true;
                }
                html = html.replace(/<\/?\w+[^>]*>/g, '').replace(/&nbsp;/g, '\xA0');
                if (!startingSymbol && /^[\u2022\u00b7\u00a7\u00d8o]\u00a0+/.test(html) || startingSymbol && /^.\u00a0+/.test(html) || symbol && !isNumber && listData) {
                    return {
                        tag: 'ul',
                        style: this._guessUnorderedListStyle(trimStartText(text))
                    };
                }
                if (/^\s*\w+[\.\)][\u00a0 ]{2,}/.test(html)) {
                    return {
                        tag: 'ol',
                        style: this._guessOrderedListStyle(trimStartText(text))
                    };
                }
            },
            _convertToLi: function (p) {
                var content;
                if (p.childNodes.length == 1) {
                    content = p.firstChild.innerHTML.replace(/^\w+[\.\)](&nbsp;)+ /, '');
                } else {
                    dom.remove(p.firstChild);
                    if (p.firstChild.nodeType == 3) {
                        if (/^[ivxlcdm]+\.$/i.test(p.firstChild.nodeValue)) {
                            dom.remove(p.firstChild);
                        }
                    }
                    if (/^(&nbsp;|\s)+$/i.test(p.firstChild.innerHTML)) {
                        dom.remove(p.firstChild);
                    }
                    content = p.innerHTML;
                }
                dom.remove(p);
                return dom.create(document, 'li', { innerHTML: content });
            },
            _guessUnorderedListStyle: function (symbol) {
                if (/^[\u2022\u00b7\u00FC\u00D8\u002dv-]/.test(symbol)) {
                    return null;
                } else if (/^o/.test(symbol)) {
                    return 'circle';
                } else {
                    return 'square';
                }
            },
            _guessOrderedListStyle: function (symbol) {
                var listType = null;
                if (!/^\d/.test(symbol)) {
                    listType = (/^[a-z]/.test(symbol) ? 'lower-' : 'upper-') + (/^[ivxlcdm]/i.test(symbol) ? 'roman' : 'alpha');
                }
                return listType;
            },
            extractListLevels: function (html) {
                var msoListRegExp = /style=['"]?[^'"]*?mso-list:\s?[a-zA-Z]+(\d+)\s[a-zA-Z]+(\d+)\s(\w+)/gi;
                html = html.replace(msoListRegExp, function (match, list, level) {
                    return kendo.format('data-list="{0}" data-level="{1}" {2}', list, level, match);
                });
                return html;
            },
            lists: function (placeholder) {
                var blockChildren = $(placeholder).find(dom.blockElements.join(',')), lastMargin = -1, name, levels = {}, li = placeholder, rootMargin, listContainer, i, p, type, margin, list, listData;
                for (i = 0; i < blockChildren.length; i++) {
                    p = blockChildren[i];
                    listData = $(p).data();
                    var listIndex = listData.list;
                    name = dom.name(p);
                    if (name == 'td') {
                        continue;
                    }
                    var listType = this.listType(p, listData);
                    type = listType && listType.tag;
                    if (!type || name != 'p') {
                        if (!p.innerHTML) {
                            dom.remove(p);
                        } else {
                            lastMargin = -1;
                            li = placeholder;
                        }
                        continue;
                    }
                    margin = parseFloat(p.style.marginLeft || 0);
                    if (rootMargin === undefined) {
                        rootMargin = margin;
                    }
                    var levelType = type + listIndex;
                    if (!levels[margin]) {
                        levels[margin] = {};
                    }
                    list = levels[margin][levelType];
                    if (margin > lastMargin || !list) {
                        list = dom.create(document, type, { style: { listStyleType: listType.style } });
                        if (li == placeholder || margin <= lastMargin) {
                            if (listContainer && rootMargin !== margin) {
                                listContainer.appendChild(list);
                            } else {
                                dom.insertBefore(list, p);
                            }
                            levels[margin] = {};
                        } else {
                            listContainer = li;
                            li.appendChild(list);
                        }
                        levels[margin][levelType] = list;
                    }
                    li = this._convertToLi(p);
                    list.appendChild(li);
                    lastMargin = margin;
                }
            },
            removeAttributes: function (element) {
                var attributes = element.attributes, i = attributes.length;
                while (i--) {
                    if (dom.name(attributes[i]) != 'colspan') {
                        element.removeAttributeNode(attributes[i]);
                    }
                }
            },
            createColGroup: function (row) {
                var cells = row.cells;
                var table = $(row).closest('table');
                var colgroup = table.children('colgroup');
                if (cells.length < 2) {
                    return;
                } else if (colgroup.length) {
                    cells = colgroup.children();
                    colgroup[0].parentNode.removeChild(colgroup[0]);
                }
                colgroup = $($.map(cells, function (cell) {
                    var width = cell.width;
                    if (width && parseInt(width, 10) !== 0) {
                        return kendo.format('<col style="width:{0}px;"/>', width);
                    }
                    return '<col />';
                }).join(''));
                if (!colgroup.is('colgroup')) {
                    colgroup = $('<colgroup/>').append(colgroup);
                }
                colgroup.prependTo(table);
            },
            convertHeaders: function (row) {
                var cells = row.cells, i, boldedCells = $.map(cells, function (cell) {
                        var child = $(cell).children('p').children('strong')[0];
                        if (child && dom.name(child) == 'strong') {
                            return child;
                        }
                    });
                if (boldedCells.length == cells.length) {
                    for (i = 0; i < boldedCells.length; i++) {
                        dom.unwrap(boldedCells[i]);
                    }
                    $(row).closest('table').find('colgroup').after('<thead></thead>').end().find('thead').append(row);
                    for (i = 0; i < cells.length; i++) {
                        dom.changeTag(cells[i], 'th');
                    }
                }
            },
            removeParagraphs: function (cells) {
                var i, j, len, cell, paragraphs;
                for (i = 0; i < cells.length; i++) {
                    this.removeAttributes(cells[i]);
                    cell = $(cells[i]);
                    paragraphs = cell.children('p');
                    for (j = 0, len = paragraphs.length; j < len; j++) {
                        if (j < len - 1) {
                            dom.insertAfter(dom.create(document, 'br'), paragraphs[j]);
                        }
                        dom.unwrap(paragraphs[j]);
                    }
                }
            },
            removeDefaultColors: function (spans) {
                for (var i = 0; i < spans.length; i++) {
                    if (/^\s*color:\s*[^;]*;?$/i.test(spans[i].style.cssText)) {
                        dom.unwrap(spans[i]);
                    }
                }
            },
            tables: function (placeholder) {
                var tables = $(placeholder).find('table'), that = this, rows, firstRow, longestRow, i, j;
                for (i = 0; i < tables.length; i++) {
                    rows = tables[i].rows;
                    longestRow = firstRow = rows[0];
                    for (j = 1; j < rows.length; j++) {
                        if (rows[j].cells.length > longestRow.cells.length) {
                            longestRow = rows[j];
                        }
                    }
                    that.createColGroup(longestRow);
                    that.convertHeaders(firstRow);
                    that.removeAttributes(tables[i]);
                    that.removeParagraphs(tables.eq(i).find('td,th'));
                    that.removeDefaultColors(tables.eq(i).find('span'));
                }
            },
            headers: function (placeholder) {
                var titles = $(placeholder).find('p.MsoTitle');
                for (var i = 0; i < titles.length; i++) {
                    dom.changeTag(titles[i], 'h1');
                }
            },
            removeFormatting: function (placeholder) {
                $(placeholder).find('*').each(function () {
                    $(this).css({
                        fontSize: '',
                        fontFamily: ''
                    });
                    if (!this.getAttribute('style') && !this.style.cssText) {
                        this.removeAttribute('style');
                    }
                });
            },
            clean: function (html) {
                var that = this, placeholder;
                var filters = this.options;
                if (filters.none) {
                    html = Cleaner.fn.clean.call(that, html, this.junkReplacements);
                    html = that.stripEmptyAnchors(html);
                } else {
                    html = this.extractListLevels(html);
                    html = Cleaner.fn.clean.call(that, html);
                    html = that.stripEmptyAnchors(html);
                    placeholder = dom.create(document, 'div', { innerHTML: html });
                    that.headers(placeholder);
                    if (filters.msConvertLists) {
                        that.lists(placeholder);
                    }
                    that.tables(placeholder);
                    if (filters.msAllFormatting) {
                        that.removeFormatting(placeholder);
                    }
                    html = placeholder.innerHTML.replace(/(<[^>]*)\s+class="?[^"\s>]*"?/gi, '$1');
                }
                return html;
            }
        });
        var WebkitFormatCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                this.replacements = [
                    /\s+class="Apple-style-span[^"]*"/gi,
                    '',
                    /<(div|p|h[1-6])\s+style="[^"]*"/gi,
                    '<$1',
                    /^<div>(.*)<\/div>$/,
                    '$1'
                ];
            },
            applicable: function (html) {
                return /class="?Apple-style-span|style="[^"]*-webkit-nbsp-mode/i.test(html);
            }
        });
        var DomCleaner = Cleaner.extend({
            clean: function (html) {
                var container = dom.create(document, 'div', { innerHTML: html });
                container = this.cleanDom(container);
                return container.innerHTML;
            },
            cleanDom: function (container) {
                return container;
            }
        });
        var HtmlTagsCleaner = DomCleaner.extend({
            cleanDom: function (container) {
                var tags = this.collectTags();
                $(container).find(tags).each(function () {
                    dom.unwrap(this);
                });
                return container;
            },
            collectTags: function () {
                if (this.options.span) {
                    return 'span';
                }
            },
            applicable: function () {
                return this.options.span;
            }
        });
        var HtmlAttrCleaner = DomCleaner.extend({
            cleanDom: function (container) {
                var attributes = this.collectAttr();
                var nodes = $(container).find('[' + attributes.join('],[') + ']');
                nodes.removeAttr(attributes.join(' '));
                return container;
            },
            collectAttr: function () {
                if (this.options.css) {
                    return [
                        'class',
                        'style'
                    ];
                }
                return [];
            },
            applicable: function () {
                return this.options.css;
            }
        });
        var TextContainer = function () {
            this.text = '';
            this.add = function (text) {
                this.text += text;
            };
        };
        var HtmlTextLines = Class.extend({
            init: function (separators) {
                this.separators = separators || {
                    text: ' ',
                    line: '<br/>'
                };
                this.lines = [];
                this.inlineBlockText = [];
                this.resetLine();
            },
            appendText: function (text) {
                if (text.nodeType === 3) {
                    text = text.nodeValue;
                }
                this.textContainer.add(text);
            },
            appendInlineBlockText: function (text) {
                this.inlineBlockText.push(text);
            },
            flashInlineBlockText: function () {
                if (this.inlineBlockText.length) {
                    this.appendText(this.inlineBlockText.join(' '));
                    this.inlineBlockText = [];
                }
            },
            endLine: function () {
                this.flashInlineBlockText();
                this.resetLine();
            },
            html: function () {
                var separators = this.separators;
                var result = '';
                var lines = this.lines;
                this.flashInlineBlockText();
                for (var i = 0, il = lines.length, il1 = il - 1; i < il; i++) {
                    var line = lines[i];
                    for (var j = 0, jl = line.length, jl1 = jl - 1; j < jl; j++) {
                        var text = line[j].text;
                        result += text;
                        if (j !== jl1) {
                            result += separators.text;
                        }
                    }
                    if (i !== il1) {
                        result += separators.line;
                    }
                }
                return result;
            },
            resetLine: function () {
                this.textContainer = new TextContainer();
                this.line = [];
                this.line.push(this.textContainer);
                this.lines.push(this.line);
            }
        });
        var DomEnumerator = Class.extend({
            init: function (callback) {
                this.callback = callback;
            },
            enumerate: function (node) {
                if (!node) {
                    return;
                }
                var preventDown = this.callback(node);
                var child = node.firstChild;
                if (!preventDown && child) {
                    this.enumerate(child);
                }
                this.enumerate(node.nextSibling);
            }
        });
        var HtmlContentCleaner = Cleaner.extend({
            init: function (options) {
                Cleaner.fn.init.call(this, options);
                this.hasText = false;
                this.enumerator = new DomEnumerator($.proxy(this.buildText, this));
            },
            clean: function (html) {
                var container = dom.create(document, 'div', { innerHTML: html });
                return this.cleanDom(container);
            },
            cleanDom: function (container) {
                this.separators = this.getDefaultSeparators();
                this.htmlLines = new HtmlTextLines(this.separators);
                this.enumerator.enumerate(container.firstChild);
                this.hasText = false;
                return this.htmlLines.html();
            },
            buildText: function (node) {
                if (dom.isDataNode(node)) {
                    if (dom.isEmptyspace(node)) {
                        return;
                    }
                    this.htmlLines.appendText(node.nodeValue.replace('\n', this.separators.line));
                    this.hasText = true;
                } else if (dom.isBlock(node) && this.hasText) {
                    var action = this.actions[dom.name(node)] || this.actions.block;
                    return action(this, node);
                }
            },
            applicable: function () {
                var o = this.options;
                return o.all || o.keepNewLines;
            },
            getDefaultSeparators: function () {
                if (this.options.all) {
                    return {
                        text: ' ',
                        line: ' '
                    };
                } else {
                    return {
                        text: ' ',
                        line: '<br/>'
                    };
                }
            },
            actions: {
                ul: $.noop,
                ol: $.noop,
                table: $.noop,
                thead: $.noop,
                tbody: $.noop,
                td: function (cleaner, node) {
                    var tdCleaner = new HtmlContentCleaner({ all: true });
                    var cellText = tdCleaner.cleanDom(node);
                    cleaner.htmlLines.appendInlineBlockText(cellText);
                    return true;
                },
                block: function (cleaner) {
                    cleaner.htmlLines.endLine();
                }
            }
        });
        var CustomCleaner = Cleaner.extend({
            clean: function (html) {
                return this.options.custom(html);
            },
            applicable: function () {
                return typeof this.options.custom === 'function';
            }
        });
        var PrintCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this.managesUndoRedo = true;
            },
            exec: function () {
                var editor = this.editor;
                if (kendo.support.browser.msie) {
                    editor.document.execCommand('print', false, null);
                } else if (editor.window.print) {
                    editor.window.print();
                }
            }
        });
        var ExportPdfCommand = Command.extend({
            init: function (options) {
                this.async = true;
                Command.fn.init.call(this, options);
            },
            exec: function () {
                var that = this;
                var range = that.lockRange(true);
                var editor = that.editor;
                editor._destroyResizings();
                editor.saveAsPDF().then(function () {
                    that.releaseRange(range);
                    editor._initializeColumnResizing();
                    editor._initializeRowResizing();
                    editor._initializeTableResizing();
                });
            }
        });
        extend(editorNS, {
            _finishUpdate: finishUpdate,
            Command: Command,
            GenericCommand: GenericCommand,
            InsertHtmlCommand: InsertHtmlCommand,
            InsertHtmlTool: InsertHtmlTool,
            TypingHandler: TypingHandler,
            SystemHandler: SystemHandler,
            BackspaceHandler: BackspaceHandler,
            SelectAllHandler: SelectAllHandler,
            Keyboard: Keyboard,
            Clipboard: Clipboard,
            Cleaner: Cleaner,
            ScriptCleaner: ScriptCleaner,
            TabCleaner: TabCleaner,
            MSWordFormatCleaner: MSWordFormatCleaner,
            WebkitFormatCleaner: WebkitFormatCleaner,
            HtmlTagsCleaner: HtmlTagsCleaner,
            HtmlAttrCleaner: HtmlAttrCleaner,
            HtmlContentCleaner: HtmlContentCleaner,
            HtmlTextLines: HtmlTextLines,
            CustomCleaner: CustomCleaner,
            PrintCommand: PrintCommand,
            ExportPdfCommand: ExportPdfCommand
        });
        registerTool('insertHtml', new InsertHtmlTool({
            template: new ToolTemplate({
                template: EditorUtils.dropDownListTemplate,
                title: 'Insert HTML',
                initialValue: 'Insert HTML'
            })
        }));
        registerTool('print', new Tool({
            command: PrintCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Print'
            })
        }));
        registerTool('pdf', new Tool({
            command: ExportPdfCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Export PDF'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/inlineformat', ['editor/system'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, Editor = kendo.ui.editor, formats = kendo.ui.Editor.fn.options.formats, EditorUtils = Editor.EditorUtils, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, FormatTool = Editor.FormatTool, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, extend = $.extend, registerTool = Editor.EditorUtils.registerTool, registerFormat = Editor.EditorUtils.registerFormat, preventDefault = function (ev) {
                ev.preventDefault();
            }, MOUSEDOWN_NS = 'mousedown.kendoEditor', KEYDOWN_NS = 'keydown.kendoEditor', KMARKER = 'k-marker';
        var InlineFormatFinder = Class.extend({
            init: function (format) {
                this.format = format;
            },
            numberOfSiblings: function (referenceNode) {
                var textNodesCount = 0, elementNodesCount = 0, markerCount = 0, parentNode = referenceNode.parentNode, node;
                for (node = parentNode.firstChild; node; node = node.nextSibling) {
                    if (node != referenceNode) {
                        if (node.className == KMARKER) {
                            markerCount++;
                        } else if (node.nodeType == 3) {
                            textNodesCount++;
                        } else {
                            elementNodesCount++;
                        }
                    }
                }
                if (markerCount > 1 && parentNode.firstChild.className == KMARKER && parentNode.lastChild.className == KMARKER) {
                    return 0;
                } else {
                    return elementNodesCount + textNodesCount;
                }
            },
            findSuitable: function (sourceNode, skip) {
                if (!skip && this.numberOfSiblings(sourceNode) > 0) {
                    return null;
                }
                var node = sourceNode.parentNode;
                var tags = this.format[0].tags;
                while (!dom.ofType(node, tags)) {
                    if (this.numberOfSiblings(node) > 0) {
                        return null;
                    }
                    node = node.parentNode;
                }
                return node;
            },
            findFormat: function (sourceNode) {
                var format = this.format, attrEquals = dom.attrEquals, i, len, node, tags, attributes;
                for (i = 0, len = format.length; i < len; i++) {
                    node = sourceNode;
                    tags = format[i].tags;
                    attributes = format[i].attr;
                    if (node && dom.ofType(node, tags) && attrEquals(node, attributes)) {
                        return node;
                    }
                    while (node) {
                        node = dom.parentOfType(node, tags);
                        if (node && attrEquals(node, attributes)) {
                            return node;
                        }
                    }
                }
                return null;
            },
            isFormatted: function (nodes) {
                var i, len;
                for (i = 0, len = nodes.length; i < len; i++) {
                    if (this.findFormat(nodes[i])) {
                        return true;
                    }
                }
                return false;
            }
        });
        var InlineFormatter = Class.extend({
            init: function (format, values) {
                this.finder = new InlineFormatFinder(format);
                this.attributes = extend({}, format[0].attr, values);
                this.tag = format[0].tags[0];
            },
            wrap: function (node) {
                return dom.wrap(node, dom.create(node.ownerDocument, this.tag, this.attributes));
            },
            activate: function (range, nodes) {
                if (this.finder.isFormatted(nodes)) {
                    this.split(range);
                    this.remove(nodes);
                } else {
                    this.apply(nodes);
                }
            },
            toggle: function (range) {
                var textNodes = this.immutables() ? RangeUtils.editableTextNodes : RangeUtils.textNodes;
                var nodes = textNodes(range);
                if (nodes.length > 0) {
                    this.activate(range, nodes);
                }
            },
            immutables: function () {
                return this.editor && this.editor.options.immutables;
            },
            apply: function (nodes) {
                var formatNodes = [];
                var i, l, node, formatNode;
                var attributes = this.attributes;
                var styleAttr = attributes ? attributes.style || {} : {};
                for (i = 0, l = nodes.length; i < l; i++) {
                    node = nodes[i];
                    formatNode = this.finder.findSuitable(node);
                    if (formatNode) {
                        if (dom.is(formatNode, 'font')) {
                            if (styleAttr.color) {
                                formatNode.removeAttribute('color');
                            }
                            if (styleAttr.fontName) {
                                formatNode.removeAttribute('face');
                            }
                            if (styleAttr.fontSize) {
                                formatNode.removeAttribute('size');
                            }
                        }
                        dom.attr(formatNode, attributes);
                    } else {
                        while (!dom.isBlock(node.parentNode) && node.parentNode.childNodes.length == 1 && node.parentNode.contentEditable !== 'true') {
                            node = node.parentNode;
                        }
                        formatNode = this.wrap(node);
                    }
                    formatNodes.push(formatNode);
                }
                this.consolidate(formatNodes);
            },
            remove: function (nodes) {
                var i, l, formatNode;
                for (i = 0, l = nodes.length; i < l; i++) {
                    formatNode = this.finder.findFormat(nodes[i]);
                    if (formatNode) {
                        if (this.attributes && this.attributes.style) {
                            dom.unstyle(formatNode, this.attributes.style);
                            if (!formatNode.style.cssText && !formatNode.attributes['class']) {
                                dom.unwrap(formatNode);
                            }
                        } else {
                            dom.unwrap(formatNode);
                        }
                    }
                }
            },
            split: function (range) {
                var nodes = RangeUtils.textNodes(range);
                var l = nodes.length;
                var i, formatNode;
                if (l > 0) {
                    for (i = 0; i < l; i++) {
                        formatNode = this.finder.findFormat(nodes[i]);
                        if (formatNode) {
                            RangeUtils.split(range, formatNode, true);
                        }
                    }
                }
            },
            consolidate: function (nodes) {
                var node, last;
                while (nodes.length > 1) {
                    node = nodes.pop();
                    last = nodes[nodes.length - 1];
                    if (node.previousSibling && node.previousSibling.className == KMARKER) {
                        last.appendChild(node.previousSibling);
                    }
                    if (node.tagName == last.tagName && node.previousSibling == last && node.style.cssText == last.style.cssText) {
                        while (node.firstChild) {
                            last.appendChild(node.firstChild);
                        }
                        dom.remove(node);
                    }
                }
            }
        });
        var GreedyInlineFormatFinder = InlineFormatFinder.extend({
            init: function (format, greedyProperty) {
                this.format = format;
                this.greedyProperty = greedyProperty;
                InlineFormatFinder.fn.init.call(this, format);
            },
            getInlineCssValue: function (node) {
                var attributes = node.attributes;
                var trim = $.trim;
                var i, l, attribute, name, attributeValue, css, pair, cssIndex, len;
                var propertyAndValue, property, value;
                if (!attributes) {
                    return;
                }
                for (i = 0, l = attributes.length; i < l; i++) {
                    attribute = attributes[i];
                    name = attribute.nodeName;
                    attributeValue = attribute.nodeValue;
                    if (attribute.specified && name == 'style') {
                        css = trim(attributeValue || node.style.cssText).split(';');
                        for (cssIndex = 0, len = css.length; cssIndex < len; cssIndex++) {
                            pair = css[cssIndex];
                            if (pair.length) {
                                propertyAndValue = pair.split(':');
                                property = trim(propertyAndValue[0].toLowerCase());
                                value = trim(propertyAndValue[1]);
                                if (property != this.greedyProperty) {
                                    continue;
                                }
                                return property.indexOf('color') >= 0 ? dom.toHex(value) : value;
                            }
                        }
                    }
                }
            },
            getFormatInner: function (node) {
                var $node = $(dom.isDataNode(node) ? node.parentNode : node);
                var parents = $node.parentsUntil('[contentEditable]').addBack().toArray().reverse();
                var i, len, value;
                for (i = 0, len = parents.length; i < len; i++) {
                    value = this.greedyProperty == 'className' ? parents[i].className : this.getInlineCssValue(parents[i]);
                    if (value) {
                        return value;
                    }
                }
                return 'inherit';
            },
            getFormat: function (nodes) {
                var result = this.getFormatInner(nodes[0]), i, len;
                for (i = 1, len = nodes.length; i < len; i++) {
                    if (result != this.getFormatInner(nodes[i])) {
                        return '';
                    }
                }
                return result;
            },
            isFormatted: function (nodes) {
                return this.getFormat(nodes) !== '';
            }
        });
        var GreedyInlineFormatter = InlineFormatter.extend({
            init: function (format, values, greedyProperty) {
                InlineFormatter.fn.init.call(this, format, values);
                this.values = values;
                this.finder = new GreedyInlineFormatFinder(format, greedyProperty);
                if (greedyProperty) {
                    this.greedyProperty = kendo.toCamelCase(greedyProperty);
                }
            },
            activate: function (range, nodes) {
                var greedyProperty = this.greedyProperty;
                var action = 'apply';
                this.split(range);
                if (greedyProperty && this.values.style[greedyProperty] == 'inherit') {
                    action = 'remove';
                }
                this[action](nodes);
            }
        });
        var InlineFormatTool = FormatTool.extend({
            init: function (options) {
                FormatTool.fn.init.call(this, extend(options, {
                    finder: new InlineFormatFinder(options.format),
                    formatter: function () {
                        return new InlineFormatter(options.format);
                    }
                }));
            }
        });
        var DelayedExecutionTool = Tool.extend({
            update: function (ui, nodes) {
                var list = ui.data(this.type);
                list.close();
                list.value(this.finder.getFormat(nodes));
            }
        });
        var FontTool = DelayedExecutionTool.extend({
            init: function (options) {
                Tool.fn.init.call(this, options);
                this.type = kendo.support.browser.msie || kendo.support.touch ? 'kendoDropDownList' : 'kendoComboBox';
                this.format = [{
                        tags: [
                            'span',
                            'font'
                        ]
                    }];
                this.finder = new GreedyInlineFormatFinder(this.format, options.cssAttr);
            },
            command: function (commandArguments) {
                var options = this.options, format = this.format, style = {};
                return new Editor.FormatCommand(extend(commandArguments, {
                    formatter: function () {
                        style[options.domAttr] = commandArguments.value;
                        return new GreedyInlineFormatter(format, { style: style }, options.cssAttr);
                    }
                }));
            },
            initialize: function (ui, initOptions) {
                var editor = initOptions.editor, options = this.options, toolName = options.name, dataSource, range, defaultValue = [];
                if (options.defaultValue) {
                    defaultValue = [{
                            text: editor.options.messages[options.defaultValue[0].text],
                            value: options.defaultValue[0].value
                        }];
                }
                dataSource = defaultValue.concat(options.items ? options.items : editor.options[toolName] || []);
                ui.attr({ title: initOptions.title });
                ui[this.type]({
                    dataTextField: 'text',
                    dataValueField: 'value',
                    dataSource: dataSource,
                    change: function () {
                        editor._range = range;
                        Tool.exec(editor, toolName, this.value());
                    },
                    close: function () {
                        setTimeout(function () {
                            if ('_range' in editor) {
                                delete editor._range;
                            }
                        }, 0);
                    },
                    highlightFirst: false
                });
                ui.closest('.k-widget').removeClass('k-' + toolName).find('*').addBack().attr('unselectable', 'on');
                var widget = ui.data(this.type);
                widget.value('inherit');
                widget.wrapper.on(MOUSEDOWN_NS, '.k-select,.k-input', function () {
                    var newRange = editor.getRange();
                    range = editor._containsRange(newRange) ? newRange : range;
                }).on(KEYDOWN_NS, function (e) {
                    if (e.keyCode === kendo.keys.ENTER) {
                        e.preventDefault();
                    }
                });
            }
        });
        var ColorTool = Tool.extend({
            init: function (options) {
                Tool.fn.init.call(this, options);
                this.format = [{
                        tags: [
                            'span',
                            'font'
                        ]
                    }];
                this.finder = new GreedyInlineFormatFinder(this.format, options.cssAttr);
            },
            options: { palette: 'websafe' },
            update: function () {
                this._widget.close();
            },
            command: function (commandArguments) {
                var options = this.options, format = this.format, style = {};
                return new Editor.FormatCommand(extend(commandArguments, {
                    formatter: function () {
                        style[options.domAttr] = commandArguments.value;
                        return new GreedyInlineFormatter(format, { style: style }, options.cssAttr);
                    }
                }));
            },
            initialize: function (ui, initOptions) {
                var editor = initOptions.editor, toolName = this.name, options = extend({}, ColorTool.fn.options, this.options), palette = options.palette;
                ui = this._widget = new kendo.ui.ColorPicker(ui, {
                    toolIcon: 'k-icon k-i-' + EditorUtils.getToolCssClass(options.name),
                    palette: palette,
                    change: function () {
                        var color = ui.value();
                        if (color) {
                            Tool.exec(editor, toolName, color);
                        }
                        editor.focus();
                    },
                    open: function (e) {
                        var picker = e.sender;
                        picker.value(null);
                        picker._popup.element.on(MOUSEDOWN_NS, preventDefault);
                    },
                    close: function (e) {
                        e.sender._popup.element.off(MOUSEDOWN_NS);
                    },
                    activate: function (e) {
                        e.preventDefault();
                        ui.trigger('change');
                    }
                });
                ui.wrapper.attr({
                    title: initOptions.title,
                    unselectable: 'on'
                }).find('*').attr('unselectable', 'on');
            }
        });
        extend(Editor, {
            InlineFormatFinder: InlineFormatFinder,
            InlineFormatter: InlineFormatter,
            DelayedExecutionTool: DelayedExecutionTool,
            GreedyInlineFormatFinder: GreedyInlineFormatFinder,
            GreedyInlineFormatter: GreedyInlineFormatter,
            InlineFormatTool: InlineFormatTool,
            FontTool: FontTool,
            ColorTool: ColorTool
        });
        registerFormat('bold', [
            {
                tags: [
                    'strong',
                    'b'
                ]
            },
            {
                tags: ['span'],
                attr: { style: { fontWeight: 'bold' } }
            }
        ]);
        registerTool('bold', new InlineFormatTool({
            key: 'B',
            ctrl: true,
            format: formats.bold,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Bold'
            })
        }));
        registerFormat('italic', [
            {
                tags: [
                    'em',
                    'i'
                ]
            },
            {
                tags: ['span'],
                attr: { style: { fontStyle: 'italic' } }
            }
        ]);
        registerTool('italic', new InlineFormatTool({
            key: 'I',
            ctrl: true,
            format: formats.italic,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Italic'
            })
        }));
        registerFormat('underline', [
            {
                tags: ['span'],
                attr: { style: { textDecoration: 'underline' } }
            },
            { tags: ['u'] }
        ]);
        registerTool('underline', new InlineFormatTool({
            key: 'U',
            ctrl: true,
            format: formats.underline,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Underline'
            })
        }));
        registerFormat('strikethrough', [
            {
                tags: [
                    'del',
                    'strike'
                ]
            },
            {
                tags: ['span'],
                attr: { style: { textDecoration: 'line-through' } }
            }
        ]);
        registerTool('strikethrough', new InlineFormatTool({
            format: formats.strikethrough,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Strikethrough'
            })
        }));
        registerFormat('superscript', [{ tags: ['sup'] }]);
        registerTool('superscript', new InlineFormatTool({
            format: formats.superscript,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Superscript'
            })
        }));
        registerFormat('subscript', [{ tags: ['sub'] }]);
        registerTool('subscript', new InlineFormatTool({
            format: formats.subscript,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Subscript'
            })
        }));
        registerTool('foreColor', new ColorTool({
            cssAttr: 'color',
            domAttr: 'color',
            name: 'foreColor',
            template: new ToolTemplate({
                template: EditorUtils.colorPickerTemplate,
                title: 'Color'
            })
        }));
        registerTool('backColor', new ColorTool({
            cssAttr: 'background-color',
            domAttr: 'backgroundColor',
            name: 'backColor',
            template: new ToolTemplate({
                template: EditorUtils.colorPickerTemplate,
                title: 'Background Color'
            })
        }));
        registerTool('fontName', new FontTool({
            cssAttr: 'font-family',
            domAttr: 'fontFamily',
            name: 'fontName',
            defaultValue: [{
                    text: 'fontNameInherit',
                    value: 'inherit'
                }],
            template: new ToolTemplate({
                template: EditorUtils.comboBoxTemplate,
                title: 'Font Name'
            })
        }));
        registerTool('fontSize', new FontTool({
            cssAttr: 'font-size',
            domAttr: 'fontSize',
            name: 'fontSize',
            defaultValue: [{
                    text: 'fontSizeInherit',
                    value: 'inherit'
                }],
            template: new ToolTemplate({
                template: EditorUtils.comboBoxTemplate,
                title: 'Font Size'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/formatblock', ['editor/inlineformat'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, formats = kendo.ui.Editor.fn.options.formats, dom = Editor.Dom, Command = Editor.Command, ToolTemplate = Editor.ToolTemplate, FormatTool = Editor.FormatTool, EditorUtils = Editor.EditorUtils, registerTool = EditorUtils.registerTool, registerFormat = EditorUtils.registerFormat, RangeUtils = Editor.RangeUtils;
        var BlockFormatFinder = Class.extend({
            init: function (format) {
                this.format = format;
            },
            contains: function (node, children) {
                var i, len, child;
                for (i = 0, len = children.length; i < len; i++) {
                    child = children[i];
                    if (!child || !dom.isAncestorOrSelf(node, child)) {
                        return false;
                    }
                }
                return true;
            },
            findSuitable: function (nodes) {
                var format = this.format, suitable = [], i, len, candidate;
                for (i = 0, len = nodes.length; i < len; i++) {
                    for (var f = format.length - 1; f >= 0; f--) {
                        candidate = dom.ofType(nodes[i], format[f].tags) ? nodes[i] : dom.closestEditableOfType(nodes[i], format[f].tags);
                        if (candidate) {
                            break;
                        }
                    }
                    if (!candidate || candidate.contentEditable === 'true') {
                        return [];
                    }
                    if ($.inArray(candidate, suitable) < 0) {
                        suitable.push(candidate);
                    }
                }
                this._resolveListsItems(suitable);
                for (i = 0, len = suitable.length; i < len; i++) {
                    if (this.contains(suitable[i], suitable)) {
                        return [suitable[i]];
                    }
                }
                return suitable;
            },
            _resolveListsItems: function (nodes) {
                var i, node, wrapper;
                for (i = 0; i < nodes.length; i++) {
                    node = nodes[i];
                    wrapper = dom.is(node, 'li') ? node : dom.wrapper(node);
                    wrapper = wrapper && dom.list(wrapper) ? wrapper.children[0] : wrapper;
                    if (dom.is(wrapper, 'li')) {
                        node = nodes[i] = wrapper;
                    }
                }
            },
            findFormat: function (sourceNode) {
                var format = this.format, i, len, node, tags, attributes;
                var editableParent = dom.editableParent(sourceNode);
                var immutables = this.options && this.options.immutables;
                var ImmutablesNS = Editor.Immutables;
                for (i = 0, len = format.length; i < len; i++) {
                    node = sourceNode;
                    tags = format[i].tags;
                    attributes = format[i].attr;
                    if (immutables && tags && tags[0] == 'immutable') {
                        var immutable = ImmutablesNS.immutableParent(node);
                        if (immutable && dom.attrEquals(immutable, attributes)) {
                            return node;
                        }
                    }
                    while (node && dom.isAncestorOf(editableParent, node)) {
                        if (dom.ofType(node, tags) && dom.attrEquals(node, attributes)) {
                            return node;
                        }
                        node = node.parentNode;
                    }
                }
                return null;
            },
            getFormat: function (nodes) {
                var that = this, findFormat = function (node) {
                        return that.findFormat(dom.isDataNode(node) ? node.parentNode : node);
                    }, result = findFormat(nodes[0]), i, len;
                if (!result) {
                    return '';
                }
                for (i = 1, len = nodes.length; i < len; i++) {
                    if (result != findFormat(nodes[i])) {
                        return '';
                    }
                }
                return result.nodeName.toLowerCase();
            },
            isFormatted: function (nodes) {
                for (var i = 0, len = nodes.length; i < len; i++) {
                    if (!this.findFormat(nodes[i])) {
                        return false;
                    }
                }
                return true;
            }
        });
        var BlockFormatter = Class.extend({
            init: function (format, values) {
                this.format = format;
                this.values = values;
                this.finder = new BlockFormatFinder(format);
            },
            wrap: function (tag, attributes, nodes) {
                var commonAncestor = nodes.length == 1 ? dom.blockParentOrBody(nodes[0]) : dom.commonAncestor.apply(null, nodes);
                if (dom.isInline(commonAncestor)) {
                    commonAncestor = dom.blockParentOrBody(commonAncestor);
                }
                var ancestors = dom.significantChildNodes(commonAncestor), position = dom.findNodeIndex(ancestors[0]), wrapper = dom.create(commonAncestor.ownerDocument, tag, attributes), i, ancestor;
                for (i = 0; i < ancestors.length; i++) {
                    ancestor = ancestors[i];
                    if (dom.isBlock(ancestor)) {
                        dom.attr(ancestor, attributes);
                        if (wrapper.childNodes.length) {
                            dom.insertBefore(wrapper, ancestor);
                            wrapper = wrapper.cloneNode(false);
                        }
                        position = dom.findNodeIndex(ancestor) + 1;
                        continue;
                    }
                    wrapper.appendChild(ancestor);
                }
                if (wrapper.firstChild) {
                    dom.insertAt(commonAncestor, wrapper, position);
                }
            },
            apply: function (nodes) {
                var format, values = this.values;
                function attributes(format) {
                    return extend({}, format && format.attr, values);
                }
                this._handleImmutables(nodes, true);
                var images = dom.filter('img', nodes);
                var imageFormat = EditorUtils.formatByName('img', this.format);
                var imageAttributes = attributes(imageFormat);
                $.each(images, function () {
                    dom.attr(this, imageAttributes);
                });
                if (images.length == nodes.length) {
                    return;
                }
                var nonImages = dom.filter('img', nodes, true);
                var formatNodes = this.finder.findSuitable(nonImages);
                if (formatNodes.length) {
                    for (var i = 0, len = formatNodes.length; i < len; i++) {
                        format = EditorUtils.formatByName(dom.name(formatNodes[i]), this.format);
                        dom.attr(formatNodes[i], attributes(format));
                    }
                } else {
                    format = this.format[0];
                    this.wrap(format.tags[0], attributes(format), nonImages);
                }
            },
            _handleImmutables: function (nodes, applyFormatting) {
                if (!this.immutables()) {
                    return;
                }
                var immutableFormat = EditorUtils.formatByName('immutable', this.format);
                if (!immutableFormat) {
                    return;
                }
                var ImmutablesNS = Editor.Immutables;
                var l = nodes.length - 1;
                for (var i = l; i >= 0; i--) {
                    var immutableParent = ImmutablesNS.immutableParent(nodes[i]);
                    if (!immutableParent) {
                        continue;
                    }
                    if (immutableParent !== nodes[i + 1]) {
                        if (applyFormatting) {
                            dom.attr(immutableParent, immutableFormat.attr);
                        } else {
                            dom.unstyle(immutableParent, immutableFormat.attr.style);
                        }
                    }
                    nodes.splice(i, 1);
                }
            },
            immutables: function () {
                return this.editor && this.editor.options.immutables;
            },
            remove: function (nodes) {
                var i, l, formatNode, namedFormat, name;
                this._handleImmutables(nodes, false);
                for (i = 0, l = nodes.length; i < l; i++) {
                    formatNode = this.finder.findFormat(nodes[i]);
                    if (formatNode) {
                        name = dom.name(formatNode);
                        if (name == 'div' && !formatNode.getAttribute('class')) {
                            dom.unwrap(formatNode);
                        } else {
                            namedFormat = EditorUtils.formatByName(name, this.format);
                            if (namedFormat.attr.style) {
                                dom.unstyle(formatNode, namedFormat.attr.style);
                            }
                            if (namedFormat.attr.className) {
                                dom.removeClass(formatNode, namedFormat.attr.className);
                            }
                        }
                    }
                }
            },
            toggle: function (range) {
                var that = this, nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
                if (that.finder.isFormatted(nodes)) {
                    that.remove(nodes);
                } else {
                    that.apply(nodes);
                }
            }
        });
        var GreedyBlockFormatter = Class.extend({
            init: function (format, values) {
                var that = this;
                that.format = format;
                that.values = values;
                that.finder = new BlockFormatFinder(format);
            },
            apply: function (nodes) {
                var format = this.format;
                var blocks = dom.blockParents(nodes);
                var formatTag = format[0].tags[0];
                var i, len, list, formatter, range;
                var element;
                var tagName;
                var block;
                var immutalbeParent;
                if (blocks.length) {
                    for (i = 0, len = blocks.length; i < len; i++) {
                        block = blocks[i];
                        immutalbeParent = this.immutables() && Editor.Immutables.immutableParent(block);
                        if (!immutalbeParent) {
                            tagName = dom.name(block);
                            if (tagName == 'li') {
                                list = block.parentNode;
                                formatter = new Editor.ListFormatter(list.nodeName.toLowerCase(), formatTag);
                                range = this.editor.createRange();
                                range.selectNode(blocks[i]);
                                formatter.toggle(range);
                            } else if (formatTag && (tagName == 'td' || block.attributes.contentEditable)) {
                                new BlockFormatter(format, this.values).apply(block.childNodes);
                            } else {
                                element = dom.changeTag(block, formatTag);
                                dom.attr(element, format[0].attr);
                            }
                        }
                    }
                } else {
                    var blockFormatter = new BlockFormatter(format, this.values);
                    blockFormatter.editor = this.editor;
                    blockFormatter.apply(nodes);
                }
            },
            toggle: function (range) {
                var nodes = RangeUtils.textNodes(range);
                if (!nodes.length) {
                    range.selectNodeContents(range.commonAncestorContainer);
                    nodes = RangeUtils.textNodes(range);
                    if (!nodes.length) {
                        nodes = dom.significantChildNodes(range.commonAncestorContainer);
                    }
                }
                this.apply(nodes);
            },
            immutables: function () {
                return this.editor && this.editor.options.immutables;
            }
        });
        var FormatCommand = Command.extend({
            init: function (options) {
                options.formatter = options.formatter();
                var finder = options.formatter.finder;
                if (finder && EditorUtils.formatByName('immutable', finder.format)) {
                    finder._initOptions({ immutables: options.immutables });
                }
                Command.fn.init.call(this, options);
            }
        });
        var BlockFormatTool = FormatTool.extend({
            init: function (options) {
                FormatTool.fn.init.call(this, extend(options, {
                    finder: new BlockFormatFinder(options.format),
                    formatter: function () {
                        return new BlockFormatter(options.format);
                    }
                }));
            }
        });
        extend(Editor, {
            BlockFormatFinder: BlockFormatFinder,
            BlockFormatter: BlockFormatter,
            GreedyBlockFormatter: GreedyBlockFormatter,
            FormatCommand: FormatCommand,
            BlockFormatTool: BlockFormatTool
        });
        var listElements = [
            'ul',
            'ol',
            'li'
        ];
        registerFormat('justifyLeft', [
            {
                tags: dom.nonListBlockElements,
                attr: { style: { textAlign: 'left' } }
            },
            {
                tags: ['img'],
                attr: {
                    style: {
                        'float': 'left',
                        display: '',
                        marginLeft: '',
                        marginRight: ''
                    }
                }
            },
            {
                tags: ['immutable'],
                attr: {
                    style: {
                        'float': 'left',
                        display: '',
                        marginLeft: '',
                        marginRight: ''
                    }
                }
            },
            {
                tags: listElements,
                attr: {
                    style: {
                        textAlign: 'left',
                        listStylePosition: ''
                    }
                }
            }
        ]);
        registerTool('justifyLeft', new BlockFormatTool({
            format: formats.justifyLeft,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Justify Left'
            })
        }));
        registerFormat('justifyCenter', [
            {
                tags: dom.nonListBlockElements,
                attr: { style: { textAlign: 'center' } }
            },
            {
                tags: ['img'],
                attr: {
                    style: {
                        display: 'block',
                        marginLeft: 'auto',
                        marginRight: 'auto',
                        'float': ''
                    }
                }
            },
            {
                tags: ['immutable'],
                attr: {
                    style: {
                        display: 'block',
                        marginLeft: 'auto',
                        marginRight: 'auto',
                        'float': ''
                    }
                }
            },
            {
                tags: listElements,
                attr: {
                    style: {
                        textAlign: 'center',
                        listStylePosition: 'inside'
                    }
                }
            }
        ]);
        registerTool('justifyCenter', new BlockFormatTool({
            format: formats.justifyCenter,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Justify Center'
            })
        }));
        registerFormat('justifyRight', [
            {
                tags: dom.nonListBlockElements,
                attr: { style: { textAlign: 'right' } }
            },
            {
                tags: ['img'],
                attr: {
                    style: {
                        'float': 'right',
                        display: '',
                        marginLeft: '',
                        marginRight: ''
                    }
                }
            },
            {
                tags: ['immutable'],
                attr: {
                    style: {
                        'float': 'right',
                        display: '',
                        marginLeft: '',
                        marginRight: ''
                    }
                }
            },
            {
                tags: listElements,
                attr: {
                    style: {
                        textAlign: 'right',
                        listStylePosition: 'inside'
                    }
                }
            }
        ]);
        registerTool('justifyRight', new BlockFormatTool({
            format: formats.justifyRight,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Justify Right'
            })
        }));
        registerFormat('justifyFull', [
            {
                tags: dom.nonListBlockElements,
                attr: { style: { textAlign: 'justify' } }
            },
            {
                tags: ['img'],
                attr: {
                    style: {
                        display: 'block',
                        marginLeft: 'auto',
                        marginRight: 'auto',
                        'float': ''
                    }
                }
            },
            {
                tags: ['immutable'],
                attr: {
                    style: {
                        display: 'block',
                        marginLeft: 'auto',
                        marginRight: 'auto',
                        'float': ''
                    }
                }
            },
            {
                tags: listElements,
                attr: {
                    style: {
                        textAlign: 'justify',
                        listStylePosition: ''
                    }
                }
            }
        ]);
        registerTool('justifyFull', new BlockFormatTool({
            format: formats.justifyFull,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Justify Full'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/linebreak', ['editor/formatblock'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, extend = $.extend, editorNS = kendo.ui.editor, dom = editorNS.Dom, Command = editorNS.Command, Tool = editorNS.Tool, BlockFormatter = editorNS.BlockFormatter, normalize = dom.normalize, RangeUtils = editorNS.RangeUtils, registerTool = editorNS.EditorUtils.registerTool;
        var ParagraphCommand = Command.extend({
            init: function (options) {
                this.options = options;
                Command.fn.init.call(this, options);
            },
            _insertMarker: function (doc, range) {
                var marker = dom.create(doc, 'a'), container;
                marker.className = 'k-marker';
                range.insertNode(marker);
                if (!marker.parentNode) {
                    container = range.commonAncestorContainer;
                    container.innerHTML = '';
                    container.appendChild(marker);
                }
                normalize(marker.parentNode);
                return marker;
            },
            _moveFocus: function (range, candidate) {
                if (dom.isEmpty(candidate)) {
                    range.setStartBefore(candidate);
                } else {
                    range.selectNodeContents(candidate);
                    var focusNode = RangeUtils.textNodes(range)[0];
                    if (!focusNode) {
                        while (candidate.childNodes.length && !dom.is(candidate.firstChild, 'br')) {
                            candidate = candidate.firstChild;
                        }
                        focusNode = candidate;
                    }
                    if (dom.isEmpty(focusNode)) {
                        range.setStartBefore(focusNode);
                    } else {
                        if (dom.emptyNode(focusNode)) {
                            focusNode.innerHTML = '\uFEFF';
                        }
                        range.setStartBefore(focusNode.firstChild || focusNode);
                    }
                }
            },
            shouldTrim: function (range) {
                var blocks = 'p,h1,h2,h3,h4,h5,h6'.split(','), startInBlock = dom.parentOfType(range.startContainer, blocks), endInBlock = dom.parentOfType(range.endContainer, blocks);
                return startInBlock && !endInBlock || !startInBlock && endInBlock;
            },
            _blankAfter: function (node) {
                while (node && (dom.isMarker(node) || dom.stripBom(node.nodeValue) === '')) {
                    node = node.nextSibling;
                }
                return !node;
            },
            exec: function () {
                var range = this.getRange(), doc = RangeUtils.documentFromRange(range), parent, previous, next, emptyParagraphContent = editorNS.emptyElementContent, paragraph, marker, li, heading, rng, shouldTrim;
                this.expandImmutablesIn(range);
                shouldTrim = this.shouldTrim(range);
                range.deleteContents();
                marker = this._insertMarker(doc, range);
                dom.stripBomNode(marker.previousSibling);
                dom.stripBomNode(marker.nextSibling);
                li = dom.closestEditableOfType(marker, ['li']);
                heading = dom.closestEditableOfType(marker, 'h1,h2,h3,h4,h5,h6'.split(','));
                if (li) {
                    if (dom.emptyNode(li)) {
                        paragraph = dom.create(doc, 'p');
                        if (dom.next(li)) {
                            rng = range.cloneRange();
                            rng.selectNode(li);
                            RangeUtils.split(rng, li.parentNode);
                        }
                        var br = $('br', li);
                        if (br.length == 1) {
                            br.remove();
                        }
                        var parentNode = li.parentNode;
                        var parentChildrenLength = li.parentNode.children.length;
                        var firstChild = parentChildrenLength > 1 && li.childNodes.length == 1 && li.children[0];
                        dom.insertAfter(paragraph, parentNode);
                        dom.remove(parentChildrenLength == 1 ? li.parentNode : li);
                        if (firstChild && firstChild !== marker) {
                            paragraph.appendChild(firstChild);
                            paragraph.appendChild(marker);
                        } else {
                            paragraph.innerHTML = emptyParagraphContent;
                        }
                        next = paragraph;
                    }
                } else if (heading && this._blankAfter(marker)) {
                    paragraph = dom.create(doc, 'p');
                    dom.insertAfter(paragraph, heading);
                    paragraph.innerHTML = emptyParagraphContent;
                    dom.remove(marker);
                    next = paragraph;
                }
                if (!next) {
                    if (!(li || heading)) {
                        new BlockFormatter([{ tags: ['p'] }]).apply([marker]);
                    }
                    range.selectNode(marker);
                    parent = dom.parentOfType(marker, [li ? 'li' : heading ? dom.name(heading) : 'p']);
                    RangeUtils.split(range, parent, shouldTrim);
                    previous = parent.previousSibling;
                    if (dom.is(previous, 'li') && previous.firstChild && !dom.is(previous.firstChild, 'br')) {
                        previous = previous.firstChild;
                    }
                    next = parent.nextSibling;
                    this.clean(previous);
                    this.clean(next, { links: true });
                    if (dom.is(next, 'li') && next.firstChild && !dom.is(next.firstChild, 'br')) {
                        next = next.firstChild;
                    }
                    dom.remove(parent);
                    normalize(previous);
                }
                normalize(next);
                this._moveFocus(range, next);
                range.collapse(true);
                dom.scrollTo(next);
                RangeUtils.selectRange(range);
            },
            clean: function (node, options) {
                var root = node;
                if (node.firstChild && dom.is(node.firstChild, 'br')) {
                    dom.remove(node.firstChild);
                }
                if (dom.isDataNode(node) && !node.nodeValue) {
                    node = node.parentNode;
                }
                if (node) {
                    var siblings = false;
                    while (node.firstChild && node.firstChild.nodeType == 1) {
                        siblings = siblings || dom.significantNodes(node.childNodes).length > 1;
                        node = node.firstChild;
                    }
                    if (!dom.isEmpty(node) && /^\s*$/.test(node.innerHTML) && !siblings) {
                        $(root).find('.k-br').remove();
                        node.innerHTML = editorNS.emptyElementContent;
                    }
                    if (options && options.links) {
                        while (node != root) {
                            if (dom.is(node, 'a') && dom.emptyNode(node)) {
                                dom.unwrap(node);
                                break;
                            }
                            node = node.parentNode;
                        }
                    }
                }
            }
        });
        var NewLineCommand = Command.extend({
            init: function (options) {
                this.options = options;
                Command.fn.init.call(this, options);
            },
            exec: function () {
                var range = this.getRange();
                this.expandImmutablesIn(range);
                var br = dom.create(RangeUtils.documentFromRange(range), 'br');
                var filler;
                var browser = kendo.support.browser;
                var oldIE = browser.msie && browser.version < 11;
                range.deleteContents();
                range.insertNode(br);
                normalize(br.parentNode);
                if (!oldIE && (!br.nextSibling || dom.isWhitespace(br.nextSibling))) {
                    filler = br.cloneNode(true);
                    filler.className = 'k-br';
                    dom.insertAfter(filler, br);
                }
                range.setStartAfter(br);
                range.collapse(true);
                dom.scrollTo(br.nextSibling || br);
                RangeUtils.selectRange(range);
            }
        });
        extend(editorNS, {
            ParagraphCommand: ParagraphCommand,
            NewLineCommand: NewLineCommand
        });
        registerTool('insertLineBreak', new Tool({
            key: 13,
            shift: true,
            command: NewLineCommand
        }));
        registerTool('insertParagraph', new Tool({
            key: 13,
            command: ParagraphCommand
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/lists', ['editor/linebreak'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, EditorUtils = Editor.EditorUtils, Command = Editor.Command, ToolTemplate = Editor.ToolTemplate, FormatTool = Editor.FormatTool, BlockFormatFinder = Editor.BlockFormatFinder, textNodes = RangeUtils.textNodes, registerTool = Editor.EditorUtils.registerTool;
        var ListFormatFinder = BlockFormatFinder.extend({
            init: function (tag) {
                this.tag = tag;
                var tags = this.tags = [
                    tag == 'ul' ? 'ol' : 'ul',
                    tag
                ];
                BlockFormatFinder.fn.init.call(this, [{ tags: tags }]);
            },
            isFormatted: function (nodes) {
                var formatNodes = [];
                var formatNode, i;
                for (i = 0; i < nodes.length; i++) {
                    formatNode = this.findFormat(nodes[i]);
                    if (formatNode && dom.name(formatNode) == this.tag) {
                        formatNodes.push(formatNode);
                    }
                }
                if (formatNodes.length < 1) {
                    return false;
                }
                if (formatNodes.length != nodes.length) {
                    return false;
                }
                for (i = 0; i < formatNodes.length; i++) {
                    if (formatNodes[i].parentNode != formatNode.parentNode) {
                        break;
                    }
                    if (formatNodes[i] != formatNode) {
                        return false;
                    }
                }
                return true;
            },
            findSuitable: function (nodes) {
                var candidate = this.findFormat(nodes[0]);
                if (candidate && dom.name(candidate) == this.tag) {
                    return candidate;
                }
                return null;
            }
        });
        var ListFormatter = Class.extend({
            init: function (tag, unwrapTag) {
                var that = this;
                that.finder = new ListFormatFinder(tag);
                that.tag = tag;
                that.unwrapTag = unwrapTag;
            },
            isList: function (node) {
                return dom.list(node);
            },
            immutables: function () {
                return this.editor && !!this.editor.options.immutables;
            },
            wrap: function (list, nodes) {
                var li = dom.create(list.ownerDocument, 'li'), i, node, isImmutable = this.immutables() ? Editor.Immutables.immutable : $.noop;
                for (i = 0; i < nodes.length; i++) {
                    node = nodes[i];
                    if (dom.is(node, 'li')) {
                        list.appendChild(node);
                        continue;
                    }
                    if (this.isList(node)) {
                        while (node.firstChild) {
                            list.appendChild(node.firstChild);
                        }
                        continue;
                    }
                    if (dom.is(node, 'td')) {
                        while (node.firstChild) {
                            li.appendChild(node.firstChild);
                        }
                        list.appendChild(li);
                        node.appendChild(list);
                        list = list.cloneNode(false);
                        li = li.cloneNode(false);
                        continue;
                    }
                    li.appendChild(node);
                    if (dom.isBlock(node)) {
                        list.appendChild(li);
                        if (!isImmutable(node)) {
                            dom.unwrap(node);
                        }
                        li = li.cloneNode(false);
                    }
                }
                if (li.firstChild) {
                    list.appendChild(li);
                }
            },
            containsAny: function (parent, nodes) {
                for (var i = 0; i < nodes.length; i++) {
                    if (dom.isAncestorOrSelf(parent, nodes[i])) {
                        return true;
                    }
                }
                return false;
            },
            suitable: function (candidate, nodes) {
                if (candidate.className == 'k-marker') {
                    var sibling = candidate.nextSibling;
                    if (sibling && dom.isBlock(sibling)) {
                        return false;
                    }
                    sibling = candidate.previousSibling;
                    if (sibling && dom.isBlock(sibling)) {
                        return false;
                    }
                }
                return this.containsAny(candidate, nodes) || dom.isInline(candidate) || candidate.nodeType == 3;
            },
            _parentLists: function (node) {
                var editable = dom.closestEditable(node);
                return $(node).parentsUntil(editable, 'ul,ol');
            },
            split: function (range) {
                var nodes = textNodes(range);
                var start, end, parents;
                if (nodes.length) {
                    start = dom.parentOfType(nodes[0], ['li']);
                    end = dom.parentOfType(nodes[nodes.length - 1], ['li']);
                    range.setStartBefore(start);
                    range.setEndAfter(end);
                    for (var i = 0, l = nodes.length; i < l; i++) {
                        var formatNode = this.finder.findFormat(nodes[i]);
                        if (formatNode) {
                            parents = this._parentLists(formatNode);
                            if (parents.length) {
                                RangeUtils.split(range, parents.last()[0], true);
                            } else {
                                RangeUtils.split(range, formatNode, true);
                            }
                        }
                    }
                }
            },
            merge: function (tag, formatNode) {
                var prev = formatNode.previousSibling, next;
                while (prev && (prev.className == 'k-marker' || prev.nodeType == 3 && dom.isWhitespace(prev))) {
                    prev = prev.previousSibling;
                }
                if (prev && dom.name(prev) == tag) {
                    while (formatNode.firstChild) {
                        prev.appendChild(formatNode.firstChild);
                    }
                    dom.remove(formatNode);
                    formatNode = prev;
                }
                next = formatNode.nextSibling;
                while (next && (next.className == 'k-marker' || next.nodeType == 3 && dom.isWhitespace(next))) {
                    next = next.nextSibling;
                }
                if (next && dom.name(next) == tag) {
                    while (formatNode.lastChild) {
                        next.insertBefore(formatNode.lastChild, next.firstChild);
                    }
                    dom.remove(formatNode);
                }
            },
            breakable: function (node) {
                return node != node.ownerDocument.body && !/table|tbody|tr|td/.test(dom.name(node)) && !node.attributes.contentEditable;
            },
            applyOnSection: function (section, nodes) {
                var tag = this.tag;
                var commonAncestor = dom.closestSplittableParent(nodes);
                var ancestors = [];
                var formatNode = this.finder.findSuitable(nodes);
                if (!formatNode) {
                    formatNode = new ListFormatFinder(tag == 'ul' ? 'ol' : 'ul').findSuitable(nodes);
                }
                var childNodes;
                if (/table|tbody/.test(dom.name(commonAncestor))) {
                    childNodes = $.map(nodes, function (node) {
                        return dom.parentOfType(node, ['td']);
                    });
                } else {
                    childNodes = dom.significantChildNodes(commonAncestor);
                    if ($.grep(childNodes, dom.isBlock).length) {
                        childNodes = $.grep(childNodes, $.proxy(function (node) {
                            return this.containsAny(node, nodes);
                        }, this));
                    }
                    if (!childNodes.length) {
                        childNodes = nodes;
                    }
                }
                function pushAncestor() {
                    ancestors.push(this);
                }
                for (var i = 0; i < childNodes.length; i++) {
                    var child = childNodes[i];
                    var suitable = (!formatNode || !dom.isAncestorOrSelf(formatNode, child)) && this.suitable(child, nodes);
                    if (!suitable) {
                        continue;
                    }
                    if (formatNode && this.isList(child)) {
                        $.each(child.children, pushAncestor);
                        dom.remove(child);
                    } else {
                        ancestors.push(child);
                    }
                }
                if (ancestors.length == childNodes.length && this.breakable(commonAncestor)) {
                    ancestors = [commonAncestor];
                }
                if (!formatNode) {
                    formatNode = dom.create(commonAncestor.ownerDocument, tag);
                    dom.insertBefore(formatNode, ancestors[0]);
                }
                this.wrap(formatNode, ancestors);
                while (dom.isBom(formatNode.nextSibling)) {
                    dom.remove(formatNode.nextSibling);
                }
                if (!dom.is(formatNode, tag)) {
                    dom.changeTag(formatNode, tag);
                }
                this.merge(tag, formatNode);
            },
            apply: function (nodes) {
                var i = 0, sections = [], lastSection, lastNodes, section, node, l = nodes.length, immutableParent = this.immutables() ? Editor.Immutables.immutableParent : $.noop;
                function addLastSection() {
                    if (lastSection) {
                        sections.push({
                            section: lastSection,
                            nodes: lastNodes
                        });
                    }
                }
                for (i = 0; i < l; i++) {
                    node = immutableParent(nodes[i]) || nodes[i];
                    section = dom.closestEditable(node, [
                        'td',
                        'body'
                    ]);
                    if (!lastSection || section != lastSection) {
                        addLastSection();
                        lastNodes = [node];
                        lastSection = section;
                    } else {
                        lastNodes.push(node);
                    }
                }
                addLastSection();
                for (i = 0; i < sections.length; i++) {
                    this.applyOnSection(sections[i].section, sections[i].nodes);
                }
            },
            unwrap: function (ul) {
                var fragment = ul.ownerDocument.createDocumentFragment(), unwrapTag = this.unwrapTag, parents, li, p, child;
                for (li = ul.firstChild; li; li = li.nextSibling) {
                    p = dom.create(ul.ownerDocument, unwrapTag || 'p');
                    while (li.firstChild) {
                        child = li.firstChild;
                        if (dom.isBlock(child)) {
                            if (p.firstChild) {
                                fragment.appendChild(p);
                                p = dom.create(ul.ownerDocument, unwrapTag || 'p');
                            }
                            fragment.appendChild(child);
                        } else {
                            p.appendChild(child);
                        }
                    }
                    if (p.firstChild) {
                        fragment.appendChild(p);
                    }
                }
                parents = this._parentLists(ul);
                if (parents[0]) {
                    dom.insertAfter(fragment, parents.last()[0]);
                    parents.last().remove();
                } else {
                    dom.insertAfter(fragment, ul);
                }
                dom.remove(ul);
            },
            remove: function (nodes) {
                var formatNode;
                for (var i = 0, l = nodes.length; i < l; i++) {
                    formatNode = this.finder.findFormat(nodes[i]);
                    if (formatNode) {
                        this.unwrap(formatNode);
                    }
                }
            },
            toggle: function (range) {
                var that = this, nodes = textNodes(range), ancestor = range.commonAncestorContainer;
                if (!nodes.length) {
                    range.selectNodeContents(ancestor);
                    nodes = textNodes(range);
                    if (!nodes.length) {
                        var text = ancestor.ownerDocument.createTextNode('');
                        range.startContainer.appendChild(text);
                        nodes = [text];
                        range.selectNode(text.parentNode);
                    }
                }
                nodes = dom.filterBy(nodes, dom.htmlIndentSpace, true);
                if (that.finder.isFormatted(nodes)) {
                    that.split(range);
                    that.remove(nodes);
                } else {
                    that.apply(nodes);
                }
            }
        });
        var ListCommand = Command.extend({
            init: function (options) {
                options.formatter = new ListFormatter(options.tag);
                Command.fn.init.call(this, options);
            }
        });
        var ListTool = FormatTool.extend({
            init: function (options) {
                this.options = options;
                FormatTool.fn.init.call(this, extend(options, { finder: new ListFormatFinder(options.tag) }));
            },
            command: function (commandArguments) {
                return new ListCommand(extend(commandArguments, { tag: this.options.tag }));
            }
        });
        extend(Editor, {
            ListFormatFinder: ListFormatFinder,
            ListFormatter: ListFormatter,
            ListCommand: ListCommand,
            ListTool: ListTool
        });
        registerTool('insertUnorderedList', new ListTool({
            tag: 'ul',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Insert unordered list'
            })
        }));
        registerTool('insertOrderedList', new ListTool({
            tag: 'ol',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Insert ordered list'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/link', ['editor/lists'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, dom = Editor.Dom, RangeUtils = Editor.RangeUtils, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, InlineFormatter = Editor.InlineFormatter, InlineFormatFinder = Editor.InlineFormatFinder, textNodes = RangeUtils.textNodes, editableTextNodes = RangeUtils.editableTextNodes, registerTool = Editor.EditorUtils.registerTool, keys = kendo.keys;
        var HTTP_PROTOCOL = 'http://';
        var protocolRegExp = /^\w*:\/\//;
        var endLinkCharsRegExp = /[\w\/\$\-_\*\?]/i;
        var LinkFormatFinder = Class.extend({
            findSuitable: function (sourceNode) {
                return dom.parentOfType(sourceNode, ['a']);
            }
        });
        var LinkFormatter = Class.extend({
            init: function () {
                this.finder = new LinkFormatFinder();
            },
            apply: function (range, attributes) {
                var nodes = this.immutables ? editableTextNodes(range) : textNodes(range);
                var markers, doc, formatter, a, parent;
                if (attributes.innerHTML) {
                    doc = RangeUtils.documentFromRange(range);
                    markers = RangeUtils.getMarkers(range);
                    range.deleteContents();
                    a = dom.create(doc, 'a', attributes);
                    range.insertNode(a);
                    parent = a.parentNode;
                    if (dom.name(parent) == 'a') {
                        dom.insertAfter(a, parent);
                    }
                    if (dom.emptyNode(parent)) {
                        dom.remove(parent);
                    }
                    var ref = a;
                    for (var i = 0; i < markers.length; i++) {
                        dom.insertAfter(markers[i], ref);
                        ref = markers[i];
                    }
                    if (markers.length) {
                        dom.insertBefore(doc.createTextNode('\uFEFF'), markers[1]);
                        dom.insertAfter(doc.createTextNode('\uFEFF'), markers[1]);
                        range.setStartBefore(markers[0]);
                        range.setEndAfter(markers[markers.length - 1]);
                    }
                } else {
                    formatter = new InlineFormatter([{ tags: ['a'] }], attributes);
                    formatter.finder = this.finder;
                    formatter.apply(nodes);
                }
            }
        });
        var UnlinkCommand = Command.extend({
            init: function (options) {
                var that = this;
                options.formatter = {
                    toggle: function (range) {
                        var nodes = that.immutables() ? editableTextNodes(range) : textNodes(range);
                        new InlineFormatter([{ tags: ['a'] }]).remove(nodes);
                    }
                };
                this.options = options;
                Command.fn.init.call(this, options);
            }
        });
        var LinkCommand = Command.extend({
            init: function (options) {
                var that;
                this.options = options;
                Command.fn.init.call(this, options);
                this.formatter = new LinkFormatter();
                if (!options.url) {
                    this.attributes = null;
                    this.async = true;
                } else {
                    this.exec = function () {
                        this.formatter.immutables = that && that.immutables();
                        this.formatter.apply(options.range, {
                            href: options.url,
                            innerHTML: options.text || options.url,
                            target: options.target
                        });
                    };
                }
            },
            _dialogTemplate: function () {
                return kendo.template('<div class="k-editor-dialog k-popup-edit-form">' + '<div class="k-edit-form-container">' + '<div class=\'k-edit-label\'>' + '<label for=\'k-editor-link-url\'>#: messages.linkWebAddress #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type=\'text\' class=\'k-input k-textbox\' id=\'k-editor-link-url\'>' + '</div>' + '<div class=\'k-edit-label k-editor-link-text-row\'>' + '<label for=\'k-editor-link-text\'>#: messages.linkText #</label>' + '</div>' + '<div class=\'k-edit-field k-editor-link-text-row\'>' + '<input type=\'text\' class=\'k-input k-textbox\' id=\'k-editor-link-text\'>' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for=\'k-editor-link-title\'>#: messages.linkToolTip #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type=\'text\' class=\'k-input k-textbox\' id=\'k-editor-link-title\'>' + '</div>' + '<div class=\'k-edit-label\'></div>' + '<div class=\'k-edit-field\'>' + '<input type=\'checkbox\' class=\'k-checkbox\' id=\'k-editor-link-target\'>' + '<label for=\'k-editor-link-target\' class=\'k-checkbox-label\'>#: messages.linkOpenInNewWindow #</label>' + '</div>' + '<div class=\'k-edit-buttons k-state-default\'>' + '<button class="k-dialog-insert k-button k-primary">#: messages.dialogInsert #</button>' + '<button class="k-dialog-close k-button">#: messages.dialogCancel #</button>' + '</div>' + '</div>' + '</div>')({ messages: this.editor.options.messages });
            },
            exec: function () {
                var messages = this.editor.options.messages;
                this._initialText = '';
                this._range = this.lockRange(true);
                this.formatter.immutables = this.immutables();
                var nodes = textNodes(this._range);
                var a = nodes.length ? this.formatter.finder.findSuitable(nodes[0]) : null;
                var img = nodes.length && dom.name(nodes[0]) == 'img';
                var dialog = this.createDialog(this._dialogTemplate(), {
                    title: messages.createLink,
                    close: proxy(this._close, this),
                    visible: false
                });
                if (a) {
                    this._range.selectNodeContents(a);
                    nodes = textNodes(this._range);
                }
                this._initialText = this.linkText(nodes);
                dialog.find('.k-dialog-insert').click(proxy(this._apply, this)).end().find('.k-dialog-close').click(proxy(this._close, this)).end().find('.k-edit-field input').keydown(proxy(this._keydown, this)).end().find('#k-editor-link-url').val(this.linkUrl(a)).end().find('#k-editor-link-text').val(this._initialText).end().find('#k-editor-link-title').val(a ? a.title : '').end().find('#k-editor-link-target').attr('checked', a ? a.target == '_blank' : false).end().find('.k-editor-link-text-row').toggle(!img);
                this._dialog = dialog.data('kendoWindow').center().open();
                $('#k-editor-link-url', dialog).focus().select();
            },
            _keydown: function (e) {
                var keys = kendo.keys;
                if (e.keyCode == keys.ENTER) {
                    this._apply(e);
                } else if (e.keyCode == keys.ESC) {
                    this._close(e);
                }
            },
            _apply: function (e) {
                var element = this._dialog.element;
                var href = $('#k-editor-link-url', element).val();
                var title, text, target;
                var textInput = $('#k-editor-link-text', element);
                if (href && href != HTTP_PROTOCOL) {
                    if (href.indexOf('@') > 0 && !/^(\w+:)|(\/\/)/i.test(href)) {
                        href = 'mailto:' + href;
                    }
                    this.attributes = { href: href };
                    title = $('#k-editor-link-title', element).val();
                    if (title) {
                        this.attributes.title = title;
                    }
                    if (textInput.is(':visible')) {
                        text = textInput.val();
                        if (!text && !this._initialText) {
                            this.attributes.innerHTML = href;
                        } else if (text && text !== this._initialText) {
                            this.attributes.innerHTML = dom.stripBom(text);
                        }
                    }
                    target = $('#k-editor-link-target', element).is(':checked');
                    this.attributes.target = target ? '_blank' : null;
                    this.formatter.apply(this._range, this.attributes);
                }
                this._close(e);
                if (this.change) {
                    this.change();
                }
            },
            _close: function (e) {
                e.preventDefault();
                this._dialog.destroy();
                dom.windowFromDocument(RangeUtils.documentFromRange(this._range)).focus();
                this.releaseRange(this._range);
            },
            linkUrl: function (anchor) {
                if (anchor) {
                    return anchor.getAttribute('href', 2);
                }
                return HTTP_PROTOCOL;
            },
            linkText: function (nodes) {
                var text = '';
                var i;
                for (i = 0; i < nodes.length; i++) {
                    text += nodes[i].nodeValue;
                }
                return dom.stripBom(text || '');
            },
            redo: function () {
                var range = this.lockRange(true);
                this.formatter.apply(range, this.attributes);
                this.releaseRange(range);
            }
        });
        var AutoLinkCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this.formatter = new LinkFormatter();
            },
            exec: function () {
                var detectedLink = this.detectLink();
                if (!detectedLink) {
                    return;
                }
                var range = this.getRange();
                var linkMarker = new kendo.ui.editor.Marker();
                var linkRange = range.cloneRange();
                linkRange.setStart(detectedLink.start.node, detectedLink.start.offset);
                linkRange.setEnd(detectedLink.end.node, detectedLink.end.offset);
                range = this.lockRange();
                linkMarker.add(linkRange);
                this.formatter.apply(linkRange, { href: this._ensureWebProtocol(detectedLink.text) });
                linkMarker.remove(linkRange);
                this.releaseRange(range);
            },
            detectLink: function () {
                var range = this.getRange();
                var traverser = new LeftDomTextTraverser({
                    node: range.startContainer,
                    offset: range.startOffset,
                    cancelAtNode: function (node) {
                        return node && dom.name(node) === 'a';
                    }
                });
                var detection = new DomTextLinkDetection(traverser);
                return detection.detectLink();
            },
            changesContent: function () {
                return !!this.detectLink();
            },
            _ensureWebProtocol: function (linkText) {
                var hasProtocol = this._hasProtocolPrefix(linkText);
                return hasProtocol ? linkText : this._prefixWithWebProtocol(linkText);
            },
            _hasProtocolPrefix: function (linkText) {
                return protocolRegExp.test(linkText);
            },
            _prefixWithWebProtocol: function (linkText) {
                return HTTP_PROTOCOL + linkText;
            }
        });
        var UnlinkTool = Tool.extend({
            init: function (options) {
                this.options = options;
                this.finder = new InlineFormatFinder([{ tags: ['a'] }]);
                Tool.fn.init.call(this, $.extend(options, { command: UnlinkCommand }));
            },
            initialize: function (ui, options) {
                Tool.fn.initialize.call(this, ui, options);
                ui.addClass('k-state-disabled');
            },
            update: function (ui, nodes) {
                ui.toggleClass('k-state-disabled', !this.finder.isFormatted(nodes)).removeClass('k-state-hover');
            }
        });
        var DomTextLinkDetection = Class.extend({
            init: function (traverser) {
                this.traverser = traverser;
                this.start = DomPos();
                this.end = DomPos();
                this.text = '';
            },
            detectLink: function () {
                var node = this.traverser.node;
                var offset = this.traverser.offset;
                if (dom.isDataNode(node)) {
                    var text = node.data.substring(0, offset);
                    if (/\s{2}$/.test(dom.stripBom(text))) {
                        return;
                    }
                } else if (offset === 0) {
                    var p = dom.closestEditableOfType(node, dom.blockElements);
                    if (p && p.previousSibling) {
                        this.traverser.init({ node: p.previousSibling });
                    }
                }
                this.traverser.traverse($.proxy(this._detectEnd, this));
                if (!this.end.blank()) {
                    this.traverser = this.traverser.clone(this.end);
                    this.traverser.traverse($.proxy(this._detectStart, this));
                    if (!this._isLinkDetected()) {
                        var puntuationOptions = this.traverser.extendOptions(this.start);
                        var puntuationTraverser = new RightDomTextTraverser(puntuationOptions);
                        puntuationTraverser.traverse($.proxy(this._skipStartPuntuation, this));
                        if (!this._isLinkDetected()) {
                            this.start = DomPos();
                        }
                    }
                }
                if (this.start.blank()) {
                    return null;
                } else {
                    return {
                        start: this.start,
                        end: this.end,
                        text: this.text
                    };
                }
            },
            _isLinkDetected: function () {
                return protocolRegExp.test(this.text) || /^w{3}\./i.test(this.text);
            },
            _detectEnd: function (text, node) {
                var i = lastIndexOfRegExp(text, endLinkCharsRegExp);
                if (i > -1) {
                    this.end.node = node;
                    this.end.offset = i + 1;
                    return false;
                }
            },
            _detectStart: function (text, node) {
                var i = lastIndexOfRegExp(text, /\s/);
                var ii = i + 1;
                this.text = text.substring(ii) + this.text;
                this.start.node = node;
                this.start.offset = ii;
                if (i > -1) {
                    return false;
                }
            },
            _skipStartPuntuation: function (text, node, offset) {
                var i = indexOfRegExp(text, /\w/);
                var ii = i;
                if (i === -1) {
                    ii = text.length;
                }
                this.text = this.text.substring(ii);
                this.start.node = node;
                this.start.offset = ii + (offset | 0);
                if (i > -1) {
                    return false;
                }
            }
        });
        function lastIndexOfRegExp(str, search) {
            var i = str.length;
            while (i-- && !search.test(str[i])) {
            }
            return i;
        }
        function indexOfRegExp(str, search) {
            var r = search.exec(str);
            return r ? r.index : -1;
        }
        var DomPos = function () {
            return {
                node: null,
                offset: null,
                blank: function () {
                    return this.node === null && this.offset === null;
                }
            };
        };
        var DomTextTraverser = Class.extend({
            init: function (options) {
                this.node = options.node;
                this.offset = options.offset === undefined ? dom.isDataNode(this.node) && this.node.length || 0 : options.offset;
                this.cancelAtNode = options.cancelAtNode || this.cancelAtNode || $.noop;
            },
            traverse: function (callback) {
                if (!callback) {
                    return;
                }
                this.cancel = false;
                this._traverse(callback, this.node, this.offset);
            },
            _traverse: function (callback, node, offset) {
                if (!node || this.cancel) {
                    return;
                }
                if (node.nodeType === 3) {
                    var text = node.data;
                    if (offset !== undefined) {
                        text = this.subText(text, offset);
                    }
                    this.cancel = callback(text, node, offset) === false;
                } else {
                    var edgeNode = this.edgeNode(node);
                    this.cancel = this.cancel || this.cancelAtNode(edgeNode);
                    return this._traverse(callback, edgeNode);
                }
                var next = this.next(node);
                if (!next) {
                    var parent = node.parentNode;
                    while (!next && dom.isInline(parent)) {
                        next = this.next(parent);
                        parent = parent.parentNode;
                    }
                }
                this.cancel = this.cancel || this.cancelAtNode(next);
                this._traverse(callback, next);
            },
            extendOptions: function (o) {
                return $.extend({
                    node: this.node,
                    offset: this.offset,
                    cancelAtNode: this.cancelAtNode
                }, o || {});
            },
            edgeNode: function (node) {
            },
            next: function (node) {
            },
            subText: function (text, offset) {
            }
        });
        var LeftDomTextTraverser = DomTextTraverser.extend({
            subText: function (text, splitIndex) {
                return text.substring(0, splitIndex);
            },
            next: function (node) {
                return node.previousSibling;
            },
            edgeNode: function (node) {
                return node.lastChild;
            },
            clone: function (options) {
                var o = this.extendOptions(options);
                return new LeftDomTextTraverser(o);
            }
        });
        var RightDomTextTraverser = DomTextTraverser.extend({
            subText: function (text, splitIndex) {
                return text.substring(splitIndex);
            },
            next: function (node) {
                return node.nextSibling;
            },
            edgeNode: function (node) {
                return node.firstChild;
            },
            clone: function (options) {
                var o = this.extendOptions(options);
                return new RightDomTextTraverser(o);
            }
        });
        extend(kendo.ui.editor, {
            LinkFormatFinder: LinkFormatFinder,
            LinkFormatter: LinkFormatter,
            UnlinkCommand: UnlinkCommand,
            LinkCommand: LinkCommand,
            AutoLinkCommand: AutoLinkCommand,
            UnlinkTool: UnlinkTool,
            DomTextLinkDetection: DomTextLinkDetection,
            LeftDomTextTraverser: LeftDomTextTraverser,
            RightDomTextTraverser: RightDomTextTraverser
        });
        registerTool('createLink', new Tool({
            key: 'K',
            ctrl: true,
            command: LinkCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Create Link'
            })
        }));
        registerTool('unlink', new UnlinkTool({
            key: 'K',
            ctrl: true,
            shift: true,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Remove Link'
            })
        }));
        registerTool('autoLink', new Tool({
            key: [
                keys.ENTER,
                keys.SPACEBAR
            ],
            keyPressCommand: true,
            command: AutoLinkCommand
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/file', [
        'kendo.filebrowser',
        'editor/link'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, RangeUtils = Editor.RangeUtils, Command = Editor.Command, LinkFormatter = Editor.LinkFormatter, textNodes = RangeUtils.textNodes, keys = kendo.keys, KEDITORFILEURL = '#k-editor-file-url', KEDITORFILETEXT = '#k-editor-file-text', KEDITORFILETITLE = '#k-editor-file-title';
        var FileCommand = Command.extend({
            init: function (options) {
                var that = this;
                Command.fn.init.call(that, options);
                that.formatter = new LinkFormatter();
                that.async = true;
                that.attributes = {};
            },
            insertFile: function (file, range) {
                var attributes = this.attributes;
                var doc = RangeUtils.documentFromRange(range);
                if (attributes.href && attributes.href != 'http://') {
                    if (!file) {
                        file = dom.create(doc, 'a', { href: attributes.href });
                        file.innerHTML = attributes.innerHTML;
                        file.title = attributes.title;
                        range.deleteContents();
                        range.insertNode(file);
                        if (!file.nextSibling) {
                            dom.insertAfter(doc.createTextNode('\uFEFF'), file);
                        }
                        range.setStartAfter(file);
                        range.setEndAfter(file);
                        RangeUtils.selectRange(range);
                        return true;
                    } else {
                        dom.attr(file, attributes);
                    }
                }
                return false;
            },
            _dialogTemplate: function (showBrowser) {
                return kendo.template('<div class="k-editor-dialog k-popup-edit-form">' + '<div class="k-edit-form-container">' + '# if (showBrowser) { #' + '<div class="k-filebrowser"></div>' + '# } #' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-file-url">#: messages.fileWebAddress #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-file-url">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-file-text">#: messages.fileText #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-file-text">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-file-title">#: messages.fileTitle #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-file-title">' + '</div>' + '<div class="k-edit-buttons k-state-default">' + '<button class="k-dialog-insert k-button k-primary">#: messages.dialogInsert #</button>' + '<button class="k-dialog-close k-button">#: messages.dialogCancel #</button>' + '</div>' + '</div>' + '</div>')({
                    messages: this.editor.options.messages,
                    showBrowser: showBrowser
                });
            },
            redo: function () {
                var that = this, range = that.lockRange();
                this.formatter.apply(range, this.attributes);
                that.releaseRange(range);
            },
            exec: function () {
                var that = this, range = that.lockRange(), nodes = textNodes(range), applied = false, file = nodes.length ? this.formatter.finder.findSuitable(nodes[0]) : null, dialog, options = that.editor.options, messages = options.messages, fileBrowser = options.fileBrowser, showBrowser = !!(kendo.ui.FileBrowser && fileBrowser && fileBrowser.transport && fileBrowser.transport.read !== undefined), dialogOptions = {
                        title: messages.insertFile,
                        visible: false,
                        resizable: showBrowser
                    };
                this.expandImmutablesIn(range);
                function apply(e) {
                    var element = dialog.element, href = element.find(KEDITORFILEURL).val().replace(/ /g, '%20'), innerHTML = element.find(KEDITORFILETEXT).val(), title = element.find(KEDITORFILETITLE).val();
                    that.attributes = {
                        href: href,
                        innerHTML: innerHTML !== '' ? innerHTML : href,
                        title: title
                    };
                    applied = that.insertFile(file, range);
                    close(e);
                    if (that.change) {
                        that.change();
                    }
                }
                function close(e) {
                    e.preventDefault();
                    dialog.destroy();
                    dom.windowFromDocument(RangeUtils.documentFromRange(range)).focus();
                    if (!applied) {
                        that.releaseRange(range);
                    }
                }
                function keyDown(e) {
                    if (e.keyCode == keys.ENTER) {
                        apply(e);
                    } else if (e.keyCode == keys.ESC) {
                        close(e);
                    }
                }
                dialogOptions.close = close;
                if (showBrowser) {
                    dialogOptions.width = 750;
                }
                dialog = this.createDialog(that._dialogTemplate(showBrowser), dialogOptions).toggleClass('k-filebrowser-dialog', showBrowser).find('.k-dialog-insert').click(apply).end().find('.k-dialog-close').click(close).end().find('.k-edit-field input').keydown(keyDown).end().find(KEDITORFILEURL).val(file ? file.getAttribute('href', 2) : 'http://').end().find(KEDITORFILETEXT).val(file ? file.innerText : '').end().find(KEDITORFILETITLE).val(file ? file.title : '').end().data('kendoWindow');
                if (showBrowser) {
                    that._fileBrowser = new kendo.ui.FileBrowser(dialog.element.find('.k-filebrowser'), extend({}, fileBrowser));
                    that._fileBrowser.bind('change', function (ev) {
                        if (ev.selected.get('type') === 'f') {
                            dialog.element.find(KEDITORFILEURL).val(this.value());
                        }
                    });
                    that._fileBrowser.bind('apply', apply);
                }
                dialog.center().open();
                dialog.element.find(KEDITORFILEURL).focus().select();
            }
        });
        kendo.ui.editor.FileCommand = FileCommand;
        registerTool('insertFile', new Editor.Tool({
            command: FileCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Insert File'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/image', [
        'kendo.imagebrowser',
        'editor/link'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, RangeUtils = Editor.RangeUtils, Command = Editor.Command, keys = kendo.keys, KEDITORIMAGEURL = '#k-editor-image-url', KEDITORIMAGETITLE = '#k-editor-image-title', KEDITORIMAGEWIDTH = '#k-editor-image-width', KEDITORIMAGEHEIGHT = '#k-editor-image-height';
        var ImageCommand = Command.extend({
            init: function (options) {
                var that = this;
                Command.fn.init.call(that, options);
                that.async = true;
                that.attributes = {};
            },
            insertImage: function (img, range) {
                var attributes = this.attributes;
                var doc = RangeUtils.documentFromRange(range);
                if (attributes.src && attributes.src != 'http://') {
                    var removeIEAttributes = function () {
                        setTimeout(function () {
                            if (!attributes.width) {
                                img.removeAttribute('width');
                            }
                            if (!attributes.height) {
                                img.removeAttribute('height');
                            }
                            img.removeAttribute('complete');
                        });
                    };
                    if (!img) {
                        img = dom.create(doc, 'img', attributes);
                        img.onload = img.onerror = removeIEAttributes;
                        range.deleteContents();
                        range.insertNode(img);
                        if (!img.nextSibling) {
                            dom.insertAfter(doc.createTextNode('\uFEFF'), img);
                        }
                        removeIEAttributes();
                        range.setStartAfter(img);
                        range.setEndAfter(img);
                        RangeUtils.selectRange(range);
                        return true;
                    } else {
                        img.onload = img.onerror = removeIEAttributes;
                        dom.attr(img, attributes);
                        removeIEAttributes();
                    }
                }
                return false;
            },
            _dialogTemplate: function (showBrowser) {
                return kendo.template('<div class="k-editor-dialog k-popup-edit-form">' + '<div class="k-edit-form-container">' + '# if (showBrowser) { #' + '<div class="k-filebrowser k-imagebrowser"></div>' + '# } #' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-url">#: messages.imageWebAddress #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-image-url">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-title">#: messages.imageAltText #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-image-title">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-width">#: messages.imageWidth #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-image-width">' + '</div>' + '<div class=\'k-edit-label\'>' + '<label for="k-editor-image-height">#: messages.imageHeight #</label>' + '</div>' + '<div class=\'k-edit-field\'>' + '<input type="text" class="k-input k-textbox" id="k-editor-image-height">' + '</div>' + '<div class="k-edit-buttons k-state-default">' + '<button class="k-dialog-insert k-button k-primary">#: messages.dialogInsert #</button>' + '<button class="k-dialog-close k-button">#: messages.dialogCancel #</button>' + '</div>' + '</div>' + '</div>')({
                    messages: this.editor.options.messages,
                    showBrowser: showBrowser
                });
            },
            redo: function () {
                var that = this, range = that.lockRange();
                if (!that.insertImage(RangeUtils.image(range), range)) {
                    that.releaseRange(range);
                }
            },
            exec: function () {
                var that = this, range = that.lockRange(), applied = false, img = RangeUtils.image(range), imageWidth = img && img.getAttribute('width') || '', imageHeight = img && img.getAttribute('height') || '', dialog, options = that.editor.options, messages = options.messages, imageBrowser = options.imageBrowser, showBrowser = !!(kendo.ui.ImageBrowser && imageBrowser && imageBrowser.transport && imageBrowser.transport.read !== undefined), dialogOptions = {
                        title: messages.insertImage,
                        visible: false,
                        resizable: showBrowser
                    };
                this.expandImmutablesIn(range);
                function apply(e) {
                    var element = dialog.element, w = parseInt(element.find(KEDITORIMAGEWIDTH).val(), 10), h = parseInt(element.find(KEDITORIMAGEHEIGHT).val(), 10);
                    that.attributes = {
                        src: element.find(KEDITORIMAGEURL).val().replace(/ /g, '%20'),
                        alt: element.find(KEDITORIMAGETITLE).val()
                    };
                    that.attributes.width = null;
                    that.attributes.height = null;
                    if (!isNaN(w) && w > 0) {
                        that.attributes.width = w;
                    }
                    if (!isNaN(h) && h > 0) {
                        that.attributes.height = h;
                    }
                    applied = that.insertImage(img, range);
                    close(e);
                    if (that.change) {
                        that.change();
                    }
                }
                function close(e) {
                    e.preventDefault();
                    dialog.destroy();
                    dom.windowFromDocument(RangeUtils.documentFromRange(range)).focus();
                    if (!applied) {
                        that.releaseRange(range);
                    }
                }
                function keyDown(e) {
                    if (e.keyCode == keys.ENTER) {
                        apply(e);
                    } else if (e.keyCode == keys.ESC) {
                        close(e);
                    }
                }
                dialogOptions.close = close;
                if (showBrowser) {
                    dialogOptions.width = 750;
                }
                dialog = this.createDialog(that._dialogTemplate(showBrowser), dialogOptions).toggleClass('k-filebrowser-dialog', showBrowser).find('.k-dialog-insert').click(apply).end().find('.k-dialog-close').click(close).end().find('.k-edit-field input').keydown(keyDown).end().find(KEDITORIMAGEURL).val(img ? img.getAttribute('src', 2) : 'http://').end().find(KEDITORIMAGETITLE).val(img ? img.alt : '').end().find(KEDITORIMAGEWIDTH).val(imageWidth).end().find(KEDITORIMAGEHEIGHT).val(imageHeight).end().data('kendoWindow');
                if (showBrowser) {
                    this._imageBrowser = new kendo.ui.ImageBrowser(dialog.element.find('.k-imagebrowser'), extend({}, imageBrowser));
                    this._imageBrowser.bind('change', function (ev) {
                        if (ev.selected.get('type') === 'f') {
                            dialog.element.find(KEDITORIMAGEURL).val(this.value());
                        }
                    });
                    this._imageBrowser.bind('apply', apply);
                }
                dialog.center().open();
                dialog.element.find(KEDITORIMAGEURL).focus().select();
            }
        });
        kendo.ui.editor.ImageCommand = ImageCommand;
        registerTool('insertImage', new Editor.Tool({
            command: ImageCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Insert Image'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/components', ['editor/image'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, DropDownList = kendo.ui.DropDownList, dom = kendo.ui.editor.Dom;
        var SelectBox = DropDownList.extend({
            init: function (element, options) {
                var that = this;
                DropDownList.fn.init.call(that, element, options);
                if (kendo.support.mobileOS.ios) {
                    this._initSelectOverlay();
                    this.bind('dataBound', $.proxy(this._initSelectOverlay, this));
                }
                that.text(that.options.title);
                that.bind('open', function () {
                    if (that.options.autoSize) {
                        var list = that.list, listWidth;
                        list.css({
                            whiteSpace: 'nowrap',
                            width: 'auto'
                        });
                        listWidth = list.width();
                        if (listWidth) {
                            listWidth += 20;
                        } else {
                            listWidth = that._listWidth;
                        }
                        list.css('width', listWidth + kendo.support.scrollbar());
                        that._listWidth = listWidth;
                    }
                });
            },
            options: {
                name: 'SelectBox',
                index: -1
            },
            _initSelectOverlay: function () {
                var selectBox = this;
                var value = selectBox.value();
                var view = this.dataSource.view();
                var item;
                var html = '';
                var encode = kendo.htmlEncode;
                for (var i = 0; i < view.length; i++) {
                    item = view[i];
                    html += '<option value=\'' + encode(item.value) + '\'';
                    if (item.value == value) {
                        html += ' selected';
                    }
                    html += '>' + encode(item.text) + '</option>';
                }
                var select = $('<select class=\'k-select-overlay\'>' + html + '</select>');
                var wrapper = $(this.element).closest('.k-widget');
                wrapper.next('.k-select-overlay').remove();
                select.insertAfter(wrapper);
                select.on('change', function () {
                    selectBox.value(this.value);
                    selectBox.trigger('change');
                });
            },
            value: function (value) {
                var that = this, result = DropDownList.fn.value.call(that, value);
                if (value === undefined) {
                    return result;
                }
                if (!DropDownList.fn.value.call(that)) {
                    that.text(that.options.title);
                }
            },
            decorate: function (body) {
                var that = this, dataSource = that.dataSource, items = dataSource.data(), i, tag, className, style;
                if (body) {
                    that.list.css('background-color', dom.getEffectiveBackground($(body)));
                }
                for (i = 0; i < items.length; i++) {
                    tag = items[i].tag || 'span';
                    className = items[i].className;
                    style = dom.inlineStyle(body, tag, { className: className });
                    style = style.replace(/"/g, '\'');
                    items[i].style = style + ';display:inline-block';
                }
                dataSource.trigger('change');
            }
        });
        kendo.ui.plugin(SelectBox);
        kendo.ui.editor.SelectBox = SelectBox;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/indent', ['editor/components'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, extend = $.extend, Editor = kendo.ui.editor, dom = Editor.Dom, EditorUtils = Editor.EditorUtils, registerTool = EditorUtils.registerTool, Command = Editor.Command, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, RangeUtils = Editor.RangeUtils, blockElements = dom.blockElements, BlockFormatFinder = Editor.BlockFormatFinder, BlockFormatter = Editor.BlockFormatter;
        function indent(node, value) {
            var isRtl = $(node).css('direction') == 'rtl', indentDirection = isRtl ? 'Right' : 'Left', property = dom.name(node) != 'td' ? 'margin' + indentDirection : 'padding' + indentDirection;
            if (value === undefined) {
                return node.style[property] || 0;
            } else {
                if (value > 0) {
                    node.style[property] = value + 'px';
                } else {
                    node.style[property] = '';
                    if (!node.style.cssText) {
                        node.removeAttribute('style');
                    }
                }
            }
        }
        var IndentFormatter = Class.extend({
            init: function () {
                this.finder = new BlockFormatFinder([{ tags: dom.blockElements }]);
            },
            apply: function (nodes) {
                nodes = dom.filterBy(nodes, dom.htmlIndentSpace, true);
                var formatNodes = this.finder.findSuitable(nodes), targets = [], i, len, formatNode, parentList, sibling;
                formatNodes = this.mapImmutables(formatNodes);
                if (formatNodes.length) {
                    for (i = 0, len = formatNodes.length; i < len; i++) {
                        if (dom.is(formatNodes[i], 'li')) {
                            if (!$(formatNodes[i]).index()) {
                                targets.push(formatNodes[i].parentNode);
                            } else if ($.inArray(formatNodes[i].parentNode, targets) < 0) {
                                targets.push(formatNodes[i]);
                            }
                        } else {
                            targets.push(formatNodes[i]);
                        }
                    }
                    while (targets.length) {
                        formatNode = targets.shift();
                        if (dom.is(formatNode, 'li')) {
                            parentList = formatNode.parentNode;
                            sibling = $(formatNode).prev('li');
                            var siblingList = sibling.find('ul,ol').last();
                            var nestedList = $(formatNode).children('ul,ol')[0];
                            if (nestedList && sibling[0]) {
                                if (siblingList[0]) {
                                    siblingList.append(formatNode);
                                    siblingList.append($(nestedList).children());
                                    dom.remove(nestedList);
                                } else {
                                    sibling.append(nestedList);
                                    nestedList.insertBefore(formatNode, nestedList.firstChild);
                                }
                            } else {
                                nestedList = sibling.children('ul,ol')[0];
                                if (!nestedList) {
                                    nestedList = dom.create(formatNode.ownerDocument, dom.name(parentList));
                                    sibling.append(nestedList);
                                }
                                while (formatNode && formatNode.parentNode == parentList) {
                                    nestedList.appendChild(formatNode);
                                    formatNode = targets.shift();
                                }
                            }
                        } else {
                            var marginLeft = parseInt(indent(formatNode), 10) + 30;
                            indent(formatNode, marginLeft);
                            for (var targetIndex = 0; targetIndex < targets.length; targetIndex++) {
                                if ($.contains(formatNode, targets[targetIndex])) {
                                    targets.splice(targetIndex, 1);
                                }
                            }
                        }
                    }
                } else {
                    var formatter = new BlockFormatter([{ tags: ['p'] }], { style: { marginLeft: 30 } });
                    formatter.apply(nodes);
                }
            },
            mapImmutables: function (nodes) {
                if (!this.immutables) {
                    return nodes;
                } else {
                    var immutables = [];
                    return $.map(nodes, function (node) {
                        var immutable = Editor.Immutables.immutableParent(node);
                        if (immutable) {
                            if ($.inArray(immutable, immutables) === -1) {
                                immutables.push(immutable);
                            } else {
                                return null;
                            }
                        }
                        return immutable || node;
                    });
                }
            },
            remove: function (nodes) {
                nodes = dom.filterBy(nodes, dom.htmlIndentSpace, true);
                var formatNodes = this.finder.findSuitable(nodes), targetNode, i, len, list, listParent, siblings, formatNode, marginLeft;
                formatNodes = this.mapImmutables(formatNodes);
                for (i = 0, len = formatNodes.length; i < len; i++) {
                    formatNode = $(formatNodes[i]);
                    if (formatNode.is('li')) {
                        list = formatNode.parent();
                        listParent = list.parent();
                        if (listParent.is('li,ul,ol') && !indent(list[0])) {
                            if (targetNode && $.contains(targetNode, listParent[0])) {
                                continue;
                            }
                            siblings = formatNode.nextAll('li');
                            if (siblings.length) {
                                $(list[0].cloneNode(false)).appendTo(formatNode).append(siblings);
                            }
                            if (listParent.is('li')) {
                                formatNode.insertAfter(listParent);
                            } else {
                                formatNode.appendTo(listParent);
                            }
                            if (!list.children('li').length) {
                                list.remove();
                            }
                            continue;
                        } else {
                            if (targetNode == list[0]) {
                                continue;
                            }
                            targetNode = list[0];
                        }
                    } else {
                        targetNode = formatNodes[i];
                    }
                    marginLeft = parseInt(indent(targetNode), 10) - 30;
                    indent(targetNode, marginLeft);
                }
            }
        });
        var IndentCommand = Command.extend({
            init: function (options) {
                var that = this;
                options.formatter = {
                    toggle: $.proxy(function (range) {
                        var indentFormatter = new IndentFormatter();
                        indentFormatter.immutables = this.editor && this.editor.options.immutables;
                        indentFormatter.apply(RangeUtils.nodes(range));
                    }, that)
                };
                Command.fn.init.call(this, options);
            }
        });
        var OutdentCommand = Command.extend({
            init: function (options) {
                var that = this;
                options.formatter = {
                    toggle: $.proxy(function (range) {
                        var indentFormatter = new IndentFormatter();
                        indentFormatter.immutables = this.editor && this.editor.options.immutables;
                        indentFormatter.remove(RangeUtils.nodes(range));
                    }, that)
                };
                Command.fn.init.call(this, options);
            }
        });
        var OutdentTool = Tool.extend({
            init: function (options) {
                Tool.fn.init.call(this, options);
                this.finder = new BlockFormatFinder([{ tags: blockElements }]);
            },
            initialize: function (ui, options) {
                Tool.fn.initialize.call(this, ui, options);
                $.extend(this.options, { immutables: options.editor && options.editor.options.immutables });
                ui.addClass('k-state-disabled');
            },
            update: function (ui, nodes) {
                var suitableNodes = this.finder.findSuitable(nodes), isOutdentable, listParentsCount, i, len, suitable, immutableParent;
                for (i = 0, len = suitableNodes.length; i < len; i++) {
                    suitable = suitableNodes[i];
                    if (this.options.immutables) {
                        immutableParent = Editor.Immutables.immutableParent(suitable);
                        if (immutableParent) {
                            suitable = immutableParent;
                        }
                    }
                    isOutdentable = indent(suitable);
                    if (!isOutdentable) {
                        listParentsCount = $(suitable).parents('ul,ol').length;
                        isOutdentable = dom.is(suitable, 'li') && (listParentsCount > 1 || indent(suitable.parentNode)) || dom.ofType(suitable, [
                            'ul',
                            'ol'
                        ]) && listParentsCount > 0;
                    }
                    if (isOutdentable) {
                        ui.removeClass('k-state-disabled');
                        return;
                    }
                }
                ui.addClass('k-state-disabled').removeClass('k-state-hover');
            }
        });
        extend(Editor, {
            IndentFormatter: IndentFormatter,
            IndentCommand: IndentCommand,
            OutdentCommand: OutdentCommand,
            OutdentTool: OutdentTool
        });
        registerTool('indent', new Tool({
            command: IndentCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Indent'
            })
        }));
        registerTool('outdent', new OutdentTool({
            command: OutdentCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Outdent'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/viewhtml', ['editor/indent'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate;
        var ViewHtmlCommand = Command.extend({
            init: function (options) {
                var cmd = this;
                cmd.options = options;
                Command.fn.init.call(cmd, options);
                cmd.attributes = null;
                cmd.async = true;
            },
            exec: function () {
                var that = this, editor = that.editor, options = editor.options, messages = editor.options.messages, dialog = $(kendo.template(ViewHtmlCommand.template)(messages)).appendTo(document.body), textarea = '.k-editor-textarea', content;
                options.serialization.immutables = editor.immutables;
                content = ViewHtmlCommand.indent(editor.value());
                options.serialization.immutables = undefined;
                function apply(e) {
                    options.deserialization.immutables = editor.immutables;
                    editor.value(dialog.find(textarea).val());
                    options.deserialization.immutables = undefined;
                    close(e);
                    if (that.change) {
                        that.change();
                    }
                    editor.trigger('change');
                }
                function close(e) {
                    e.preventDefault();
                    dialog.data('kendoWindow').destroy();
                    if (editor.immutables) {
                        editor.immutables.serializedImmutables = {};
                    }
                    editor.focus();
                }
                this.createDialog(dialog, {
                    title: messages.viewHtml,
                    close: close,
                    visible: false
                }).find(textarea).val(content).end().find('.k-dialog-update').click(apply).end().find('.k-dialog-close').click(close).end().data('kendoWindow').center().open();
                dialog.find(textarea).focus();
            }
        });
        extend(ViewHtmlCommand, {
            template: '<div class=\'k-editor-dialog k-popup-edit-form k-viewhtml-dialog\'>' + '<div class=\'k-edit-form-container\'></div>' + '<textarea class=\'k-editor-textarea k-input\'></textarea>' + '<div class=\'k-edit-buttons k-state-default\'>' + '<button class=\'k-dialog-update k-button k-primary\'>#: dialogUpdate #</button>' + '<button class=\'k-dialog-close k-button\'>#: dialogCancel #</button>' + '</div>' + '</div>' + '</div>',
            indent: function (content) {
                return content.replace(/<\/(p|li|ul|ol|h[1-6]|table|tr|td|th)>/gi, '</$1>\n').replace(/<(ul|ol)([^>]*)><li/gi, '<$1$2>\n<li').replace(/<br \/>/gi, '<br />\n').replace(/\n$/, '');
            }
        });
        kendo.ui.editor.ViewHtmlCommand = ViewHtmlCommand;
        Editor.EditorUtils.registerTool('viewHtml', new Tool({
            command: ViewHtmlCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'View HTML'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/formatting', ['editor/viewhtml'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, Editor = kendo.ui.editor, Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, DelayedExecutionTool = Editor.DelayedExecutionTool, Command = Editor.Command, dom = Editor.Dom, EditorUtils = Editor.EditorUtils, RangeUtils = Editor.RangeUtils, registerTool = EditorUtils.registerTool;
        var FormattingTool = DelayedExecutionTool.extend({
            init: function (options) {
                var that = this;
                Tool.fn.init.call(that, kendo.deepExtend({}, that.options, options));
                that.type = 'kendoSelectBox';
                that.finder = {
                    getFormat: function () {
                        return '';
                    }
                };
            },
            options: {
                items: [
                    {
                        text: 'Paragraph',
                        value: 'p'
                    },
                    {
                        text: 'Quotation',
                        value: 'blockquote'
                    },
                    {
                        text: 'Heading 1',
                        value: 'h1'
                    },
                    {
                        text: 'Heading 2',
                        value: 'h2'
                    },
                    {
                        text: 'Heading 3',
                        value: 'h3'
                    },
                    {
                        text: 'Heading 4',
                        value: 'h4'
                    },
                    {
                        text: 'Heading 5',
                        value: 'h5'
                    },
                    {
                        text: 'Heading 6',
                        value: 'h6'
                    }
                ],
                width: 110
            },
            toFormattingItem: function (item) {
                var value = item.value;
                if (!value) {
                    return item;
                }
                if (item.tag || item.className) {
                    return item;
                }
                var dot = value.indexOf('.');
                if (dot === 0) {
                    item.className = value.substring(1);
                } else if (dot == -1) {
                    item.tag = value;
                } else {
                    item.tag = value.substring(0, dot);
                    item.className = value.substring(dot + 1);
                }
                return item;
            },
            command: function (args) {
                var that = this;
                var item = args.value;
                item = this.toFormattingItem(item);
                return new Editor.FormatCommand({
                    range: args.range,
                    formatter: function () {
                        var formatter, tags = (item.tag || item.context || 'span').split(','), format = [{
                                    tags: tags,
                                    attr: { className: item.className || '' }
                                }];
                        if ($.inArray(tags[0], dom.inlineElements) >= 0) {
                            formatter = new Editor.GreedyInlineFormatter(format);
                        } else {
                            formatter = new Editor.GreedyBlockFormatter(format);
                        }
                        formatter.editor = that.editor;
                        return formatter;
                    }
                });
            },
            initialize: function (ui, initOptions) {
                var editor = initOptions.editor;
                var options = this.options;
                var toolName = options.name;
                var that = this;
                that.editor = editor;
                ui.width(options.width);
                ui.kendoSelectBox({
                    dataTextField: 'text',
                    dataValueField: 'value',
                    dataSource: options.items || editor.options[toolName],
                    title: editor.options.messages[toolName],
                    autoSize: true,
                    change: function () {
                        var dataItem = this.dataItem();
                        if (dataItem) {
                            Tool.exec(editor, toolName, dataItem.toJSON());
                        }
                    },
                    dataBound: function () {
                        var i, items = this.dataSource.data();
                        for (i = 0; i < items.length; i++) {
                            items[i] = that.toFormattingItem(items[i]);
                        }
                    },
                    highlightFirst: false,
                    template: kendo.template('<span unselectable="on" style="display:block;#=(data.style||"")#">#:data.text#</span>')
                });
                ui.addClass('k-decorated').closest('.k-widget').removeClass('k-' + toolName).find('*').addBack().attr('unselectable', 'on');
            },
            getFormattingValue: function (items, nodes) {
                for (var i = 0; i < items.length; i++) {
                    var item = items[i];
                    var tag = item.tag || item.context || '';
                    var className = item.className ? '.' + item.className : '';
                    var selector = tag + className;
                    var element = $(nodes[0]).closest(selector)[0];
                    if (!element) {
                        continue;
                    }
                    if (nodes.length == 1) {
                        return item.value;
                    }
                    for (var n = 1; n < nodes.length; n++) {
                        if (!$(nodes[n]).closest(selector)[0]) {
                            break;
                        } else if (n == nodes.length - 1) {
                            return item.value;
                        }
                    }
                }
                return '';
            },
            update: function (ui, nodes) {
                var selectBox = $(ui).data(this.type);
                if (!selectBox) {
                    return;
                }
                var dataSource = selectBox.dataSource, items = dataSource.data(), i, context, ancestor = dom.commonAncestor.apply(null, nodes);
                if (ancestor != dom.closestEditable(ancestor) && this._ancestor == ancestor) {
                    return;
                } else {
                    this._ancestor = ancestor;
                }
                for (i = 0; i < items.length; i++) {
                    context = items[i].context;
                    items[i].visible = !context || !!$(ancestor).closest(context).length;
                }
                dataSource.filter([{
                        field: 'visible',
                        operator: 'eq',
                        value: true
                    }]);
                DelayedExecutionTool.fn.update.call(this, ui, nodes);
                selectBox.value(this.getFormattingValue(dataSource.view(), nodes));
                selectBox.wrapper.toggleClass('k-state-disabled', !dataSource.view().length);
            },
            destroy: function () {
                this._ancestor = null;
            }
        });
        var CleanFormatCommand = Command.extend({
            exec: function () {
                var range = this.lockRange(true);
                this.tagsToClean = this.options.remove || 'strong,em,span,sup,sub,del,b,i,u,font'.split(',');
                RangeUtils.wrapSelectedElements(range);
                var nodes = RangeUtils.mapAll(range, function (node) {
                    return node;
                });
                for (var c = nodes.length - 1; c >= 0; c--) {
                    var node = nodes[c];
                    if (!this.immutableParent(node)) {
                        this.clean(node);
                    }
                }
                this.releaseRange(range);
            },
            clean: function (node) {
                if (!node || dom.isMarker(node)) {
                    return;
                }
                var name = dom.name(node);
                if (name == 'ul' || name == 'ol') {
                    var listFormatter = new Editor.ListFormatter(name);
                    var prev = node.previousSibling;
                    var next = node.nextSibling;
                    listFormatter.unwrap(node);
                    for (; prev && prev != next; prev = prev.nextSibling) {
                        this.clean(prev);
                    }
                } else if (name == 'blockquote') {
                    dom.changeTag(node, 'p');
                } else if (node.nodeType == 1 && !dom.insignificant(node)) {
                    for (var i = node.childNodes.length - 1; i >= 0; i--) {
                        this.clean(node.childNodes[i]);
                    }
                    node.removeAttribute('style');
                    node.removeAttribute('class');
                } else {
                    unwrapListItem(node);
                }
                if ($.inArray(name, this.tagsToClean) > -1) {
                    dom.unwrap(node);
                }
            },
            immutableParent: function (node) {
                return this.immutables() && Editor.Immutables.immutableParent(node);
            }
        });
        function unwrapListItem(node) {
            var li = dom.closestEditableOfType(node, ['li']);
            if (li) {
                var listFormatter = new Editor.ListFormatter(dom.name(li.parentNode));
                var range = kendo.ui.editor.W3CRange.fromNode(node);
                range.selectNode(li);
                listFormatter.toggle(range);
            }
        }
        $.extend(Editor, {
            FormattingTool: FormattingTool,
            CleanFormatCommand: CleanFormatCommand
        });
        registerTool('formatting', new FormattingTool({
            template: new ToolTemplate({
                template: EditorUtils.dropDownListTemplate,
                title: 'Format'
            })
        }));
        registerTool('cleanFormatting', new Tool({
            command: CleanFormatCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Clean formatting'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/toolbar', ['editor/formatting'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo;
        var ui = kendo.ui;
        var editorNS = ui.editor;
        var Widget = ui.Widget;
        var extend = $.extend;
        var proxy = $.proxy;
        var keys = kendo.keys;
        var NS = '.kendoEditor';
        var EditorUtils = kendo.ui.editor.EditorUtils;
        var ToolTemplate = kendo.ui.editor.ToolTemplate;
        var Tool = kendo.ui.editor.Tool;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var OVERFLOWANCHOR = 'overflowAnchor';
        var focusable = '.k-tool-group:visible a.k-tool:not(.k-state-disabled),' + '.k-tool.k-overflow-anchor,' + '.k-tool-group:visible .k-widget.k-colorpicker,' + '.k-tool-group:visible .k-selectbox,' + '.k-tool-group:visible .k-dropdown,' + '.k-tool-group:visible .k-combobox .k-input';
        var toolNamesByCssClass = {
            'k-i-sup-script': 'superscript',
            'k-i-sub-script': 'subscript',
            'k-i-align-left': 'justifyLeft',
            'k-i-align-center': 'justifyCenter',
            'k-i-align-right': 'justifyRight',
            'k-i-align-justify': 'justifyFull',
            'k-i-list-unordered': 'insertUnorderedList',
            'k-i-list-ordered': 'insertOrderedList',
            'k-i-login': 'import',
            'k-i-indent-increase': 'indent',
            'k-i-indent-decrease': 'outdent',
            'k-i-link-horizontal': 'createLink',
            'k-i-unlink-horizontal': 'unlink',
            'k-i-image': 'insertImage',
            'k-i-file-add': 'insertFile',
            'k-i-html': 'viewHtml',
            'k-i-foreground-color': 'foreColor',
            'k-i-paint': 'backColor',
            'k-i-table-insert': 'createTable',
            'k-i-table-column-insert-left': 'addColumnLeft',
            'k-i-table-column-insert-right': 'addColumnRight',
            'k-i-table-row-insert-above': 'addRowAbove',
            'k-i-table-row-insert-below': 'addRowBelow',
            'k-i-table-row-delete': 'deleteRow',
            'k-i-table-column-delete': 'deleteColumn',
            'k-i-table-properties': 'tableWizard',
            'k-i-table-wizard': 'tableWizardInsert',
            'k-i-clear-css': 'cleanFormatting'
        };
        var OverflowAnchorTool = Tool.extend({
            initialize: function (ui, options) {
                ui.attr({ unselectable: 'on' });
                var toolbar = options.editor.toolbar;
                ui.attr('aria-controls', options.editor.element.attr('id')).on('click', $.proxy(function () {
                    this.overflowPopup.toggle();
                }, toolbar));
            },
            options: { name: OVERFLOWANCHOR },
            command: $.noop,
            update: $.noop,
            destroy: $.noop
        });
        EditorUtils.registerTool(OVERFLOWANCHOR, new OverflowAnchorTool({
            key: '',
            ctrl: true,
            template: new ToolTemplate({ template: EditorUtils.overflowAnchorTemplate })
        }));
        var Toolbar = Widget.extend({
            init: function (element, options) {
                var that = this;
                options = extend({}, options, { name: 'EditorToolbar' });
                Widget.fn.init.call(that, element, options);
                if (options.popup) {
                    that._initPopup();
                }
                if (options.resizable && options.resizable.toolbar) {
                    that._resizeHandler = kendo.onResize(function () {
                        that.resize();
                    });
                    that.element.addClass('k-toolbar-resizable');
                }
            },
            events: ['execute'],
            groups: {
                basic: [
                    'bold',
                    'italic',
                    'underline',
                    'strikethrough'
                ],
                scripts: [
                    'subscript',
                    'superscript'
                ],
                alignment: [
                    'justifyLeft',
                    'justifyCenter',
                    'justifyRight',
                    'justifyFull'
                ],
                links: [
                    'insertImage',
                    'insertFile',
                    'createLink',
                    'unlink'
                ],
                lists: [
                    'insertUnorderedList',
                    'insertOrderedList',
                    'indent',
                    'outdent'
                ],
                tables: [
                    'createTable',
                    'addColumnLeft',
                    'addColumnRight',
                    'addRowAbove',
                    'addRowBelow',
                    'deleteRow',
                    'deleteColumn'
                ],
                advanced: [
                    'viewHtml',
                    'cleanFormatting',
                    'print',
                    'pdf',
                    'exportAs',
                    'import'
                ],
                fonts: [
                    'fontName',
                    'fontSize'
                ],
                colors: [
                    'foreColor',
                    'backColor'
                ]
            },
            overflowFlaseTools: [
                'formatting',
                'fontName',
                'fontSize',
                'foreColor',
                'backColor',
                'insertHtml'
            ],
            _initPopup: function () {
                var that = this;
                this.window = $(this.element).wrap('<div class=\'editorToolbarWindow k-header\' />').parent().prepend('<button class=\'k-button k-bare k-editortoolbar-dragHandle\'><span class=\'k-icon k-i-handler-drag\' /></button>').kendoWindow({
                    title: false,
                    resizable: false,
                    draggable: { dragHandle: '.k-editortoolbar-dragHandle' },
                    animation: {
                        open: { effects: 'fade:in' },
                        close: { effects: 'fade:out' }
                    },
                    minHeight: 42,
                    visible: false,
                    autoFocus: false,
                    actions: [],
                    dragend: function () {
                        this._moved = true;
                    }
                }).on('mousedown', function (e) {
                    if (!$(e.target).is('.k-icon')) {
                        that.preventPopupHide = true;
                    }
                }).on('focusout', function () {
                    that.options.editor.element.focusout();
                }).data('kendoWindow');
            },
            _toggleOverflowStyles: function (element, show) {
                element.find('li').toggleClass('k-item k-state-default', show).find('.k-tool:not(.k-state-disabled),.k-overflow-button').toggleClass('k-overflow-button k-button', show);
            },
            _initOverflowPopup: function (ui) {
                var that = this;
                var popupTemplate = '<ul class=\'k-editor-overflow-popup k-overflow-container k-list-container\'></ul>';
                that.overflowPopup = $(popupTemplate).appendTo('body').kendoPopup({
                    anchor: ui,
                    origin: 'bottom right',
                    position: 'top right',
                    copyAnchorStyles: false,
                    open: function (e) {
                        if (this.element.is(':empty')) {
                            e.preventDefault();
                        }
                        that._toggleOverflowStyles(this.element, true);
                        ui.attr('aria-expanded', true);
                    },
                    close: function () {
                        ui.attr('aria-expanded', false);
                    },
                    activate: proxy(that.focusOverflowPopup, that)
                }).data('kendoPopup');
            },
            items: function () {
                var isResizable = this.options.resizable && this.options.resizable.toolbar, popup, result;
                result = this.element.children().find('> *, select');
                if (isResizable) {
                    popup = this.overflowPopup;
                    result = result.add(popup.element.children().find('> *'));
                }
                return result;
            },
            focused: function () {
                return this.element.find('.k-state-focused').length > 0 || this.preventPopupHide || this.overflowPopup && this.overflowPopup.visible();
            },
            toolById: function (name) {
                var id, tools = this.tools;
                for (id in tools) {
                    if (id.toLowerCase() == name) {
                        return tools[id];
                    }
                }
            },
            toolGroupFor: function (toolName) {
                var i, groups = this.groups;
                if (this.isCustomTool(toolName)) {
                    return 'custom';
                }
                for (i in groups) {
                    if ($.inArray(toolName, groups[i]) >= 0) {
                        return i;
                    }
                }
            },
            bindTo: function (editor) {
                var that = this, window = that.window;
                if (that._editor) {
                    that._editor.unbind('select', proxy(that.resize, that));
                }
                that._editor = editor;
                if (that.options.resizable && that.options.resizable.toolbar) {
                    editor.options.tools.push(OVERFLOWANCHOR);
                }
                that.tools = that.expandTools(editor.options.tools);
                that.render();
                that.element.find('.k-combobox .k-input').keydown(function (e) {
                    var combobox = $(this).closest('.k-combobox').data('kendoComboBox'), key = e.keyCode;
                    if (key == keys.RIGHT || key == keys.LEFT) {
                        combobox.close();
                    } else if (key == keys.DOWN) {
                        if (!combobox.dropDown.isOpened()) {
                            e.stopImmediatePropagation();
                            combobox.open();
                        }
                    }
                });
                that._attachEvents();
                that.items().each(function initializeTool() {
                    var toolName = that._toolName(this), tool = toolName !== 'moreVertical' ? that.tools[toolName] : that.tools.overflowAnchor, options = tool && tool.options, messages = editor.options.messages, description = options && options.tooltip || messages[toolName], ui = $(this);
                    if (!tool || !tool.initialize) {
                        return;
                    }
                    if (toolName == 'fontSize' || toolName == 'fontName') {
                        var inheritText = messages[toolName + 'Inherit'];
                        ui.find('input').val(inheritText).end().find('span.k-input').text(inheritText).end();
                    }
                    tool.initialize(ui, {
                        title: that._appendShortcutSequence(description, tool),
                        editor: that._editor
                    });
                    ui.closest('.k-widget', that.element).addClass('k-editor-widget');
                    ui.closest('.k-colorpicker', that.element).next('.k-colorpicker').addClass('k-editor-widget');
                });
                editor.bind('select', proxy(that.resize, that));
                that.update();
                if (window) {
                    window.wrapper.css({
                        top: '',
                        left: '',
                        width: ''
                    });
                }
            },
            show: function () {
                var that = this, window = that.window, editorOptions = that.options.editor, wrapper, editorElement, editorOffset, browser = kendo.support.browser;
                if (window) {
                    wrapper = window.wrapper;
                    editorElement = editorOptions.element;
                    if (!wrapper.is(':visible') || !that.window.options.visible) {
                        if (!wrapper[0].style.width) {
                            wrapper.width(outerWidth(editorElement) - parseInt(wrapper.css('border-left-width'), 10) - parseInt(wrapper.css('border-right-width'), 10));
                        }
                        if (!window._moved) {
                            editorOffset = editorElement.offset();
                            wrapper.css({
                                top: Math.max(0, parseInt(editorOffset.top, 10) - outerHeight(wrapper) - parseInt(that.window.element.css('padding-bottom'), 10)),
                                left: Math.max(0, parseInt(editorOffset.left, 10))
                            });
                        }
                        if ((browser.msie || browser.edge) && that._overlaps(editorElement)) {
                            setTimeout(function () {
                                window.open();
                            }, 0);
                        } else {
                            window.open();
                        }
                    }
                }
            },
            _overlaps: function (box) {
                var toolbarWrapper = this.window.wrapper, toolbarWrapperOffset = toolbarWrapper.offset(), toolbarWrapperLeft = toolbarWrapperOffset.left, toolbarWrapperTop = toolbarWrapperOffset.top, boxOffset = box.offset(), boxOffsetLeft = boxOffset.left, boxOffsetTop = boxOffset.top;
                return !(boxOffsetLeft + box.width() < toolbarWrapperLeft || boxOffsetLeft > toolbarWrapperLeft + toolbarWrapper.width() || boxOffsetTop + box.height() < toolbarWrapperTop || boxOffsetTop > toolbarWrapperTop + toolbarWrapper.height());
            },
            hide: function () {
                if (this.window) {
                    this.window.close();
                }
            },
            focus: function () {
                var TABINDEX = 'tabIndex';
                var element = this.element;
                var tabIndex = this._editor.element.attr(TABINDEX);
                element.attr(TABINDEX, tabIndex || 0).focus().find(focusable).first().focus();
                if (!tabIndex && tabIndex !== 0) {
                    element.removeAttr(TABINDEX);
                }
            },
            focusOverflowPopup: function () {
                var TABINDEX = 'tabIndex';
                var element = this.overflowPopup.element;
                var tabIndex = this._editor.element.attr(TABINDEX);
                element.closest('.k-animation-container').addClass('k-overflow-wrapper');
                element.attr(TABINDEX, tabIndex || 0).find(focusable).first().focus();
                if (!tabIndex && tabIndex !== 0) {
                    element.removeAttr(TABINDEX);
                }
            },
            _appendShortcutSequence: function (localizedText, tool) {
                if (!tool.key) {
                    return localizedText;
                }
                var res = localizedText + ' (';
                if (tool.ctrl) {
                    res += 'Ctrl + ';
                }
                if (tool.shift) {
                    res += 'Shift + ';
                }
                if (tool.alt) {
                    res += 'Alt + ';
                }
                res += tool.key + ')';
                return res;
            },
            _nativeTools: [
                'insertLineBreak',
                'insertParagraph',
                'redo',
                'undo',
                'autoLink'
            ],
            tools: {},
            isCustomTool: function (toolName) {
                return !(toolName in kendo.ui.Editor.defaultTools);
            },
            expandTools: function (tools) {
                var currentTool, i, nativeTools = this._nativeTools, options, defaultTools = kendo.deepExtend({}, kendo.ui.Editor.defaultTools), result = {}, name;
                for (i = 0; i < tools.length; i++) {
                    currentTool = tools[i];
                    name = currentTool.name;
                    if ($.isPlainObject(currentTool)) {
                        if (name && defaultTools[name]) {
                            result[name] = extend({}, defaultTools[name]);
                            extend(result[name].options, currentTool);
                        } else {
                            options = extend({
                                cssClass: 'k-i-gear',
                                type: 'button',
                                title: ''
                            }, currentTool);
                            if (!options.name) {
                                options.name = 'custom';
                            }
                            options.cssClass = 'k-' + options.name;
                            if (!options.template && options.type == 'button') {
                                options.template = editorNS.EditorUtils.buttonTemplate;
                                options.title = options.title || options.tooltip;
                            }
                            result[name] = { options: options };
                        }
                    } else if (defaultTools[currentTool]) {
                        result[currentTool] = defaultTools[currentTool];
                    }
                }
                for (i = 0; i < nativeTools.length; i++) {
                    if (!result[nativeTools[i]]) {
                        result[nativeTools[i]] = defaultTools[nativeTools[i]];
                    }
                }
                return result;
            },
            render: function () {
                var that = this, tools = that.tools, options, template, toolElement, toolName, editorElement = that._editor.element, element = that.element.empty(), groupName, newGroupName, toolConfig = that._editor.options.tools, browser = kendo.support.browser, group, i, groupPosition = 0, resizable = that.options.resizable && that.options.resizable.toolbar, overflowFlaseTools = this.overflowFlaseTools;
                function stringify(template) {
                    var result;
                    if (template.getHtml) {
                        result = template.getHtml();
                    } else {
                        if (!$.isFunction(template)) {
                            template = kendo.template(template);
                        }
                        result = template(options);
                    }
                    return $.trim(result);
                }
                function endGroup() {
                    if (group.children().length) {
                        if (resizable) {
                            group.data('position', groupPosition);
                            groupPosition++;
                        }
                        group.appendTo(element);
                    }
                }
                function startGroup(toolName) {
                    if (toolName !== OVERFLOWANCHOR) {
                        group = $('<li class=\'k-tool-group\' role=\'presentation\' />');
                        group.data('overflow', $.inArray(toolName, overflowFlaseTools) === -1 ? true : false);
                    } else {
                        group = $('<li class=\'k-overflow-tools\' />');
                    }
                }
                element.empty();
                if (toolConfig.length) {
                    toolName = toolConfig[0].name || toolConfig[0];
                }
                startGroup(toolName, overflowFlaseTools);
                for (i = 0; i < toolConfig.length; i++) {
                    toolName = toolConfig[i].name || toolConfig[i];
                    options = tools[toolName] && tools[toolName].options;
                    if (!options && $.isPlainObject(toolName)) {
                        options = toolName;
                    }
                    template = options && options.template;
                    if (toolName == 'break') {
                        endGroup();
                        $('<li class=\'k-row-break\' />').appendTo(that.element);
                        startGroup(toolName, overflowFlaseTools);
                    }
                    if (!template) {
                        continue;
                    }
                    newGroupName = that.toolGroupFor(toolName);
                    if (groupName != newGroupName || toolName == OVERFLOWANCHOR) {
                        endGroup();
                        startGroup(toolName, overflowFlaseTools);
                        groupName = newGroupName;
                    }
                    if (toolName == OVERFLOWANCHOR) {
                        template.options.title = that.options.messages.overflowAnchor;
                    }
                    template = stringify(template);
                    toolElement = $(template).appendTo(group);
                    if (newGroupName == 'custom') {
                        endGroup();
                        startGroup(toolName, overflowFlaseTools);
                    }
                    if (options.exec && toolElement.hasClass('k-tool')) {
                        toolElement.click(proxy(options.exec, editorElement[0]));
                    }
                }
                endGroup();
                $(that.element).children(':has(> .k-tool)').addClass('k-button-group');
                if (that.options.popup && browser.msie && browser.version < 9) {
                    that.window.wrapper.find('*').attr('unselectable', 'on');
                }
                that.updateGroups();
                if (resizable) {
                    that._initOverflowPopup(that.element.find('.k-overflow-anchor'));
                }
                that.angular('compile', function () {
                    return { elements: that.element };
                });
            },
            updateGroups: function () {
                $(this.element).children().each(function () {
                    $(this).children().filter(function () {
                        return !$(this).hasClass('k-state-disabled');
                    }).removeClass('k-group-end').first().addClass('k-group-start').end().last().addClass('k-group-end').end();
                });
            },
            decorateFrom: function (body) {
                this.items().filter('.k-decorated').each(function () {
                    var selectBox = $(this).data('kendoSelectBox');
                    if (selectBox) {
                        selectBox.decorate(body);
                    }
                });
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                var id, tools = this.tools;
                for (id in tools) {
                    if (tools[id].destroy) {
                        tools[id].destroy();
                    }
                }
                if (this.window) {
                    this.window.destroy();
                }
                if (this._resizeHandler) {
                    kendo.unbindResize(this._resizeHandler);
                }
                if (this.overflowPopup) {
                    this.overflowPopup.destroy();
                }
            },
            _attachEvents: function () {
                var that = this, popupElement = that.overflowPopup ? that.overflowPopup.element : $([]);
                that.attachToolsEvents(that.element.add(popupElement));
            },
            attachToolsEvents: function (element) {
                var that = this, buttons = '[role=button].k-tool', enabledButtons = buttons + ':not(.k-state-disabled)', disabledButtons = buttons + '.k-state-disabled', dropdown = '.k-dropdown', colorpicker = '.k-colorpicker', editorTools = [
                        buttons,
                        dropdown,
                        colorpicker
                    ].join(',');
                element.off(NS).on('mouseenter' + NS, enabledButtons, function () {
                    $(this).addClass('k-state-hover');
                }).on('mouseleave' + NS, enabledButtons, function () {
                    $(this).removeClass('k-state-hover');
                }).on('mousedown' + NS, editorTools, function (e) {
                    e.preventDefault();
                }).on('keydown' + NS, focusable, function (e) {
                    var current = this;
                    var resizable = that.options.resizable && that.options.resizable.toolbar;
                    var focusElement, currentContainer, keyCode = e.keyCode;
                    function move(direction, container, constrain) {
                        var tools = container.find(focusable);
                        var index = tools.index(current) + direction;
                        if (constrain) {
                            index = Math.max(0, Math.min(tools.length - 1, index));
                        }
                        return tools[index];
                    }
                    if (keyCode == keys.RIGHT || keyCode == keys.LEFT) {
                        if (!$(current).hasClass('.k-dropdown')) {
                            focusElement = move(keyCode == keys.RIGHT ? 1 : -1, that.element, true);
                        }
                    } else if (resizable && (keyCode == keys.UP || keyCode == keys.DOWN)) {
                        focusElement = move(keyCode == keys.DOWN ? 1 : -1, that.overflowPopup.element, true);
                    } else if (keyCode == keys.ESC) {
                        if (that.overflowPopup && that.overflowPopup.visible()) {
                            that.overflowPopup.close();
                        }
                        focusElement = that._editor;
                    } else if (keyCode == keys.TAB && !(e.ctrlKey || e.altKey)) {
                        if (resizable) {
                            currentContainer = $(current.parentElement).hasClass('k-overflow-tool-group') ? that.overflowPopup.element : that.element;
                        } else {
                            currentContainer = that.element;
                        }
                        if (e.shiftKey) {
                            focusElement = move(-1, currentContainer);
                        } else {
                            focusElement = move(1, currentContainer);
                            if (!focusElement) {
                                focusElement = that._editor;
                            }
                        }
                    }
                    if (focusElement) {
                        e.preventDefault();
                        focusElement.focus();
                    }
                    if (keyCode === keys.ENTER && $(current).is('a') && !$(current).attr('href')) {
                        that._executeToolCommand(current, e);
                    }
                }).on('click' + NS, enabledButtons, function (e) {
                    that._executeToolCommand(this, e);
                }).on('click' + NS, disabledButtons, function (e) {
                    e.preventDefault();
                });
            },
            _executeToolCommand: function (toolElement, e) {
                var that = this;
                var button = $(toolElement);
                e.preventDefault();
                e.stopPropagation();
                button.removeClass('k-state-hover');
                if (!button.is('[data-popup]')) {
                    that._editor.exec(that._toolName(toolElement));
                }
            },
            _toolName: function (element) {
                if (!element) {
                    return;
                }
                var className = element.className;
                if (/k-tool\b/i.test(className)) {
                    className = element.firstChild.className;
                }
                var tool = $.grep(className.split(' '), function (x) {
                    return !/^k-(widget|tool|tool-icon|icon|state-hover|header|combobox|dropdown|selectbox|colorpicker)$/i.test(x);
                });
                if (tool[0]) {
                    var toolname = tool[0];
                    if (toolNamesByCssClass[toolname]) {
                        toolname = toolNamesByCssClass[toolname];
                    }
                    if (toolname.indexOf('k-i-') >= 0) {
                        return kendo.toCamelCase(toolname.substring(toolname.indexOf('k-i-') + 4));
                    } else {
                        return toolname.substring(toolname.lastIndexOf('-') + 1);
                    }
                }
                return 'custom';
            },
            refreshTools: function () {
                var that = this, editorNS = kendo.ui.editor, editor = that._editor, range = editor.getRange(), nodes = editorNS.RangeUtils.textNodes(range), immutables = editor.options.immutables, immutablesContext = that._immutablesContext(range);
                nodes = editorNS.Dom.filterBy(nodes, editorNS.Dom.htmlIndentSpace, true);
                if (!nodes.length) {
                    nodes = [range.startContainer];
                }
                that.items().each(function () {
                    var tool = that.tools[that._toolName(this)];
                    if (tool) {
                        var ui = $(this);
                        if (tool.update) {
                            tool.update(ui, nodes);
                        }
                        if (immutables) {
                            that._updateImmutablesState(tool, ui, immutablesContext);
                        }
                    }
                });
                this.update();
            },
            _immutablesContext: function (range) {
                if (this._editor.options.immutables) {
                    var editorNS = kendo.ui.editor;
                    if (range.collapsed) {
                        return editorNS.Immutables.immutablesContext(range);
                    } else {
                        return editorNS.RangeUtils.editableTextNodes(range).length === 0;
                    }
                }
            },
            _updateImmutablesState: function (tool, ui, immutablesContext) {
                var name = tool.name;
                var uiElement = ui;
                var trackImmutables = tool.options.trackImmutables;
                if (trackImmutables === undefined) {
                    trackImmutables = $.inArray(name, editorNS.Immutables.toolsToBeUpdated) > -1;
                }
                if (trackImmutables) {
                    var display = immutablesContext ? 'none' : '';
                    if (!ui.is('.k-tool')) {
                        var uiData = ui.data();
                        for (var key in uiData) {
                            if (key.match(/^kendo[A-Z][a-zA-Z]*/)) {
                                var widget = uiData[key];
                                uiElement = widget.wrapper;
                                break;
                            }
                        }
                    }
                    uiElement.css('display', display);
                    var groupUi = uiElement.closest('li');
                    if (groupUi.children(':visible').length === 0) {
                        groupUi.css('display', display);
                    }
                }
            },
            update: function () {
                this.updateGroups();
            },
            _resize: function (e) {
                var containerWidth = e.width;
                var resizable = this.options.resizable && this.options.resizable.toolbar;
                var popup = this.overflowPopup;
                this.refreshTools();
                if (!resizable) {
                    return;
                }
                if (popup.visible()) {
                    popup.close(true);
                }
                this._refreshWidths();
                this._shrink(containerWidth);
                this._stretch(containerWidth);
                this._toggleOverflowStyles(this.element, false);
                this._toggleOverflowStyles(this.overflowPopup.element, true);
                this.element.children('li.k-overflow-tools').css('visibility', popup.element.is(':empty') ? 'hidden' : 'visible');
            },
            _refreshWidths: function () {
                this.element.children('li').each(function (idx, element) {
                    var group = $(element);
                    group.data('outerWidth', outerWidth(group, true));
                });
            },
            _shrink: function (width) {
                var group, visibleGroups;
                if (width < this._groupsWidth()) {
                    visibleGroups = this._visibleGroups().filter(':not(.k-overflow-tools)');
                    for (var i = visibleGroups.length - 1; i >= 0; i--) {
                        group = visibleGroups.eq(i);
                        if (width > this._groupsWidth()) {
                            break;
                        } else {
                            this._hideGroup(group);
                        }
                    }
                }
            },
            _stretch: function (width) {
                var group, hiddenGroups;
                if (width > this._groupsWidth()) {
                    hiddenGroups = this._hiddenGroups();
                    for (var i = 0; i < hiddenGroups.length; i++) {
                        group = hiddenGroups.eq(i);
                        if (width < this._groupsWidth() || !this._showGroup(group, width)) {
                            break;
                        }
                    }
                }
            },
            _hiddenGroups: function () {
                var popup = this.overflowPopup;
                var hiddenGroups = this.element.children('li.k-tool-group').filter(':hidden');
                hiddenGroups = hiddenGroups.add(popup.element.children('li'));
                hiddenGroups.sort(function (a, b) {
                    return $(a).data('position') > $(b).data('position') ? 1 : -1;
                });
                return hiddenGroups;
            },
            _visibleGroups: function () {
                return this.element.children('li.k-tool-group, li.k-overflow-tools').filter(':visible');
            },
            _groupsWidth: function () {
                var width = 0;
                this._visibleGroups().each(function () {
                    width += $(this).data('outerWidth');
                });
                return Math.ceil(width);
            },
            _hideGroup: function (group) {
                if (group.data('overflow')) {
                    var popup = this.overflowPopup;
                    group.detach().prependTo(popup.element).addClass('k-overflow-tool-group');
                } else {
                    group.hide();
                }
            },
            _showGroup: function (group, width) {
                var position, previous;
                if (group.length && width > this._groupsWidth() + group.data('outerWidth')) {
                    if (group.hasClass('k-overflow-tool-group')) {
                        position = group.data('position');
                        if (position === 0) {
                            group.detach().prependTo(this.element);
                        } else {
                            previous = this.element.children().filter(function (idx, element) {
                                return $(element).data('position') === position - 1;
                            });
                            group.detach().insertAfter(previous);
                        }
                        group.removeClass('k-overflow-tool-group');
                    } else {
                        group.show();
                    }
                    return true;
                }
                return false;
            }
        });
        $.extend(editorNS, { Toolbar: Toolbar });
    }(window.jQuery || window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/tables', ['editor/toolbar'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, dom = Editor.Dom, EditorUtils = Editor.EditorUtils, RangeUtils = Editor.RangeUtils, Command = Editor.Command, NS = 'kendoEditor', ACTIVESTATE = 'k-state-active', SELECTEDSTATE = 'k-state-selected', Tool = Editor.Tool, ToolTemplate = Editor.ToolTemplate, InsertHtmlCommand = Editor.InsertHtmlCommand, BlockFormatFinder = Editor.BlockFormatFinder, registerTool = Editor.EditorUtils.registerTool, getTouches = kendo.getTouches;
        var template = kendo.template;
        var columnTemplate = '<td style=\'width:#=width#%;\'>#=content#</td>';
        var tableFormatFinder = new BlockFormatFinder([{ tags: ['table'] }]);
        var TableCommand = InsertHtmlCommand.extend({
            init: function (options) {
                var o = $.extend({
                    postProcess: this.postProcess,
                    skipCleaners: true
                }, options || {});
                InsertHtmlCommand.fn.init.call(this, o);
            },
            _tableHtml: function (rows, columns) {
                rows = rows || 1;
                columns = columns || 1;
                var columnHtml = template(columnTemplate)({
                    width: 100 / columns,
                    content: Editor.emptyTableCellContent
                });
                var rowHeight = 100 / rows;
                return '<table class=\'k-table\' data-last>' + new Array(rows + 1).join('<tr style=\'height:' + rowHeight + '%;\'>' + new Array(columns + 1).join(columnHtml) + '</tr>') + '</table>';
            },
            postProcess: function (editor, range) {
                var insertedTable = $('table[data-last]', editor.document).removeAttr('data-last');
                range.setStart(insertedTable.find('td')[0], 0);
                range.collapse(true);
                editor.selectRange(range);
            },
            exec: function () {
                var options = this.options;
                options.html = this._tableHtml(options.rows, options.columns);
                InsertHtmlCommand.fn.exec.call(this);
            }
        });
        var PopupTool = Tool.extend({
            initialize: function (ui, options) {
                Tool.fn.initialize.call(this, ui, options);
                var popup = $(this.options.popupTemplate).appendTo('body').kendoPopup({
                    anchor: ui,
                    copyAnchorStyles: false,
                    open: proxy(this._open, this),
                    activate: proxy(this._activate, this),
                    close: proxy(this._close, this)
                }).data('kendoPopup');
                ui.click(proxy(this._toggle, this)).keydown(proxy(this._keydown, this));
                var editor = this._editor = options.editor;
                this._popup = popup;
                var tableWizard = new Editor.TableWizardTool({
                    template: new ToolTemplate({
                        template: EditorUtils.buttonTemplate,
                        title: editor.options.messages.tableWizard
                    }),
                    command: Editor.TableWizardCommand,
                    insertNewTable: true
                });
                registerTool('tableWizardInsert', tableWizard);
                var twTool = $('<div class=\'k-editor-toolbar\'>' + tableWizard.options.template.getHtml() + '</div>');
                twTool.appendTo(popup.element);
                if (editor.toolbar) {
                    editor.toolbar.attachToolsEvents(twTool);
                }
            },
            popup: function () {
                return this._popup;
            },
            _activate: $.noop,
            _open: function () {
                this._popup.options.anchor.addClass(ACTIVESTATE);
            },
            _close: function () {
                this._popup.options.anchor.removeClass(ACTIVESTATE);
            },
            _keydown: function (e) {
                var keys = kendo.keys;
                var key = e.keyCode;
                if (key == keys.DOWN && e.altKey) {
                    this._popup.open();
                } else if (key == keys.ESC) {
                    this._popup.close();
                }
            },
            _toggle: function (e) {
                var button = $(e.target).closest('.k-tool');
                if (!button.hasClass('k-state-disabled')) {
                    this.popup().toggle();
                }
            },
            update: function (ui) {
                var popup = this.popup();
                if (popup.wrapper && popup.wrapper.css('display') == 'block') {
                    popup.close();
                }
                ui.removeClass('k-state-hover');
            },
            destroy: function () {
                this._popup.destroy();
            }
        });
        var InsertTableTool = PopupTool.extend({
            init: function (options) {
                this.cols = 8;
                this.rows = 6;
                PopupTool.fn.init.call(this, $.extend(options, {
                    command: TableCommand,
                    popupTemplate: '<div class=\'k-ct-popup\'>' + new Array(this.cols * this.rows + 1).join('<span class=\'k-ct-cell k-state-disabled\' />') + '<div class=\'k-status\'></div>' + '</div>'
                }));
            },
            _activate: function () {
                var that = this, element = that._popup.element, cells = element.find('.k-ct-cell'), firstCell = cells.eq(0), lastCell = cells.eq(cells.length - 1), start = kendo.getOffset(firstCell), end = kendo.getOffset(lastCell), cols = that.cols, rows = that.rows, cellWidth, cellHeight;
                element.find('*').addBack().attr('unselectable', 'on');
                end.left += lastCell[0].offsetWidth;
                end.top += lastCell[0].offsetHeight;
                cellWidth = (end.left - start.left) / cols;
                cellHeight = (end.top - start.top) / rows;
                function tableFromLocation(e) {
                    var w = $(window);
                    return {
                        row: Math.floor((e.clientY + w.scrollTop() - start.top) / cellHeight) + 1,
                        col: Math.floor((e.clientX + w.scrollLeft() - start.left) / cellWidth) + 1
                    };
                }
                element.autoApplyNS(NS).on('mousemove', function (e) {
                    that._setTableSize(tableFromLocation(e));
                }).on('mouseleave', function () {
                    that._setTableSize();
                }).on('down', function (e) {
                    e.preventDefault();
                    var touch = getTouches(e)[0];
                    that._exec(tableFromLocation(touch.location));
                });
            },
            _valid: function (size) {
                return size && size.row > 0 && size.col > 0 && size.row <= this.rows && size.col <= this.cols;
            },
            _exec: function (size) {
                if (this._valid(size)) {
                    this._editor.exec('createTable', {
                        rows: size.row,
                        columns: size.col
                    });
                    this._popup.close();
                }
            },
            _setTableSize: function (size) {
                var element = this._popup.element;
                var status = element.find('.k-status');
                var cells = element.find('.k-ct-cell');
                var cols = this.cols;
                var messages = this._editor.options.messages;
                if (this._valid(size)) {
                    status.text(kendo.format(messages.createTableHint, size.row, size.col));
                    cells.each(function (i) {
                        $(this).toggleClass(SELECTEDSTATE, i % cols < size.col && i / cols < size.row);
                    });
                } else {
                    status.text(messages.createTable);
                    cells.removeClass(SELECTEDSTATE);
                }
            },
            _keydown: function (e) {
                PopupTool.fn._keydown.call(this, e);
                if (!this._popup.visible()) {
                    return;
                }
                var keys = kendo.keys;
                var key = e.keyCode;
                var cells = this._popup.element.find('.k-ct-cell');
                var focus = Math.max(cells.filter('.k-state-selected').last().index(), 0);
                var selectedRows = Math.floor(focus / this.cols);
                var selectedColumns = focus % this.cols;
                var changed = false;
                if (key == keys.DOWN && !e.altKey) {
                    changed = true;
                    selectedRows++;
                } else if (key == keys.UP) {
                    changed = true;
                    selectedRows--;
                } else if (key == keys.RIGHT) {
                    changed = true;
                    selectedColumns++;
                } else if (key == keys.LEFT) {
                    changed = true;
                    selectedColumns--;
                }
                var tableSize = {
                    row: Math.max(1, Math.min(this.rows, selectedRows + 1)),
                    col: Math.max(1, Math.min(this.cols, selectedColumns + 1))
                };
                if (key == keys.ENTER) {
                    this._exec(tableSize);
                } else {
                    this._setTableSize(tableSize);
                }
                if (changed) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                }
            },
            _open: function () {
                var messages = this._editor.options.messages;
                PopupTool.fn._open.call(this);
                this.popup().element.find('.k-status').text(messages.createTable).end().find('.k-ct-cell').removeClass(SELECTEDSTATE);
            },
            _close: function () {
                PopupTool.fn._close.call(this);
                this.popup().element.off('.' + NS);
            }
        });
        var InsertRowCommand = Command.extend({
            exec: function () {
                var range = this.lockRange(true), td = range.endContainer, cellCount, row, newRow;
                while (dom.name(td) != 'td') {
                    td = td.parentNode;
                }
                if (this.immutables() && Editor.Immutables.immutableParent(td)) {
                    return;
                }
                row = td.parentNode;
                cellCount = row.children.length;
                newRow = row.cloneNode(true);
                for (var i = 0; i < row.cells.length; i++) {
                    newRow.cells[i].innerHTML = Editor.emptyTableCellContent;
                }
                if (this.options.position == 'before') {
                    dom.insertBefore(newRow, row);
                } else {
                    dom.insertAfter(newRow, row);
                }
                this.releaseRange(range);
            }
        });
        var InsertColumnCommand = Command.extend({
            exec: function () {
                var range = this.lockRange(true), td = dom.closest(range.endContainer, 'td'), table = dom.closest(td, 'table'), columnIndex, i, rows = table.rows, cell, newCell, position = this.options.position;
                if (this.immutables() && Editor.Immutables.immutableParent(td)) {
                    return;
                }
                columnIndex = dom.findNodeIndex(td, true);
                for (i = 0; i < rows.length; i++) {
                    cell = rows[i].cells[columnIndex];
                    newCell = cell.cloneNode();
                    newCell.innerHTML = Editor.emptyTableCellContent;
                    if (position == 'before') {
                        dom.insertBefore(newCell, cell);
                    } else {
                        dom.insertAfter(newCell, cell);
                    }
                }
                this.releaseRange(range);
            }
        });
        var DeleteRowCommand = Command.extend({
            exec: function () {
                var range = this.lockRange();
                var rows = RangeUtils.mapAll(range, function (node) {
                    return $(node).closest('tr')[0];
                });
                var row = rows[0];
                if (this.immutables() && Editor.Immutables.immutableParent(row)) {
                    return;
                }
                var table = dom.closest(row, 'table');
                var focusElement;
                if (table.rows.length <= rows.length) {
                    focusElement = dom.next(table);
                    if (!focusElement || dom.insignificant(focusElement)) {
                        focusElement = dom.prev(table);
                    }
                    dom.remove(table);
                } else {
                    for (var i = 0; i < rows.length; i++) {
                        row = rows[i];
                        dom.removeTextSiblings(row);
                        focusElement = dom.next(row) || dom.prev(row);
                        focusElement = focusElement.cells[0];
                        dom.remove(row);
                    }
                }
                if (focusElement) {
                    range.setStart(focusElement, 0);
                    range.collapse(true);
                    this.editor.selectRange(range);
                }
            }
        });
        var DeleteColumnCommand = Command.extend({
            exec: function () {
                var range = this.lockRange(), td = dom.closest(range.endContainer, 'td'), table = dom.closest(td, 'table'), rows = table.rows, columnIndex = dom.findNodeIndex(td, true), columnCount = rows[0].cells.length, focusElement, i;
                if (this.immutables() && Editor.Immutables.immutableParent(td)) {
                    return;
                }
                if (columnCount == 1) {
                    focusElement = dom.next(table);
                    if (!focusElement || dom.insignificant(focusElement)) {
                        focusElement = dom.prev(table);
                    }
                    dom.remove(table);
                } else {
                    dom.removeTextSiblings(td);
                    focusElement = dom.next(td) || dom.prev(td);
                    for (i = 0; i < rows.length; i++) {
                        dom.remove(rows[i].cells[columnIndex]);
                    }
                }
                if (focusElement) {
                    range.setStart(focusElement, 0);
                    range.collapse(true);
                    this.editor.selectRange(range);
                }
            }
        });
        var TableModificationTool = Tool.extend({
            command: function (options) {
                options = extend(options, this.options);
                if (options.action == 'delete') {
                    if (options.type == 'row') {
                        return new DeleteRowCommand(options);
                    } else {
                        return new DeleteColumnCommand(options);
                    }
                } else {
                    if (options.type == 'row') {
                        return new InsertRowCommand(options);
                    } else {
                        return new InsertColumnCommand(options);
                    }
                }
            },
            initialize: function (ui, options) {
                Tool.fn.initialize.call(this, ui, options);
                ui.addClass('k-state-disabled');
            },
            update: function (ui, nodes) {
                var isFormatted = !tableFormatFinder.isFormatted(nodes);
                ui.toggleClass('k-state-disabled', isFormatted);
            }
        });
        extend(kendo.ui.editor, {
            PopupTool: PopupTool,
            TableCommand: TableCommand,
            InsertTableTool: InsertTableTool,
            TableModificationTool: TableModificationTool,
            InsertRowCommand: InsertRowCommand,
            InsertColumnCommand: InsertColumnCommand,
            DeleteRowCommand: DeleteRowCommand,
            DeleteColumnCommand: DeleteColumnCommand
        });
        registerTool('createTable', new InsertTableTool({
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                popup: true,
                title: 'Create table'
            })
        }));
        registerTool('addColumnLeft', new TableModificationTool({
            type: 'column',
            position: 'before',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Add column on the left'
            })
        }));
        registerTool('addColumnRight', new TableModificationTool({
            type: 'column',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Add column on the right'
            })
        }));
        registerTool('addRowAbove', new TableModificationTool({
            type: 'row',
            position: 'before',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Add row above'
            })
        }));
        registerTool('addRowBelow', new TableModificationTool({
            type: 'row',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Add row below'
            })
        }));
        registerTool('deleteRow', new TableModificationTool({
            type: 'row',
            action: 'delete',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Delete row'
            })
        }));
        registerTool('deleteColumn', new TableModificationTool({
            type: 'column',
            action: 'delete',
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Delete column'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/export', ['editor/main'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, defaultExportAsItems = [
                {
                    text: 'Docx',
                    value: 'docx'
                },
                {
                    text: 'Rtf',
                    value: 'rtf'
                },
                {
                    text: 'Pdf',
                    value: 'pdf'
                },
                {
                    text: 'Html',
                    value: 'html'
                },
                {
                    text: 'Plain Text',
                    value: 'txt'
                }
            ];
        var ExportAsCommand = Command.extend({
            init: function (options) {
                var cmd = this;
                cmd.options = options;
                Command.fn.init.call(cmd, options);
                cmd.attributes = null;
                cmd.exportType = options.exportType;
            },
            exec: function () {
                var cmd = this;
                var range = this.lockRange(true);
                cmd.postToProxy();
                cmd.releaseRange(range);
            },
            postToProxy: function () {
                this.generateForm().appendTo('body').submit().remove();
            },
            generateForm: function () {
                var cmd = this;
                var exportAsOptions = cmd.editor.options.exportAs;
                var form = $('<form>').attr({
                    action: exportAsOptions && exportAsOptions.proxyURL || '',
                    method: 'POST'
                });
                form.append([
                    cmd.valueInput(),
                    cmd.exportTypeInput(),
                    cmd.fileNameInput()
                ]);
                return form;
            },
            valueInput: function () {
                var editor = this.editor;
                return $('<input>').attr({
                    value: editor.encodedValue(),
                    name: 'value',
                    type: 'hidden'
                });
            },
            exportTypeInput: function () {
                var cmd = this;
                return $('<input>').attr({
                    value: cmd.exportType,
                    name: 'exportType',
                    type: 'hidden'
                });
            },
            fileNameInput: function () {
                var editor = this.editor;
                var exportAsOptions = editor.options.exportAs;
                var fileName = exportAsOptions && exportAsOptions.fileName || editor.element.attr('id') || 'editor';
                return $('<input>').attr({
                    value: fileName,
                    name: 'fileName',
                    type: 'hidden'
                });
            }
        });
        var ExportAsTool = Tool.extend({
            init: function (options) {
                var tool = this;
                Tool.fn.init.call(tool, kendo.deepExtend({}, tool.options, options));
                tool.type = 'kendoSelectBox';
            },
            options: {
                items: defaultExportAsItems,
                width: 115
            },
            command: function (args) {
                var value = args.value;
                return new Editor.ExportAsCommand({
                    range: args.range,
                    exportType: value.exportType
                });
            },
            initialize: function (ui, initOptions) {
                var tool = this;
                var editor = initOptions.editor;
                var options = tool.options;
                var toolName = options.name;
                var changeHandler = proxy(tool.changeHandler, tool);
                var dataSource = options.items || editor.options[toolName];
                dataSource.unshift({
                    text: editor.options.messages[toolName],
                    value: ''
                });
                tool.editor = editor;
                ui.width(options.width);
                ui.kendoSelectBox({
                    dataTextField: 'text',
                    dataValueField: 'value',
                    dataSource: dataSource,
                    autoSize: true,
                    change: changeHandler,
                    open: function (e) {
                        var sender = e.sender;
                        sender.items()[0].style.display = 'none';
                        sender.unbind('open');
                    },
                    highlightFirst: false,
                    template: kendo.template('<span unselectable="on" style="display:block;#=(data.style||"")#">#:data.text#</span>')
                });
                ui.addClass('k-decorated').closest('.k-widget').removeClass('k-' + toolName).find('*').addBack().attr('unselectable', 'on');
            },
            changeHandler: function (e) {
                var sender = e.sender;
                var dataItem = sender.dataItem();
                var value = dataItem && dataItem.value;
                this._exec(value);
                sender.value('');
            },
            _exec: function (value) {
                if (value) {
                    Tool.exec(this.editor, this.options.name, { exportType: value });
                }
            },
            destroy: function () {
                this._ancestor = null;
            }
        });
        extend(Editor, {
            ExportAsTool: ExportAsTool,
            ExportAsCommand: ExportAsCommand
        });
        registerTool('exportAs', new ExportAsTool({
            template: new ToolTemplate({
                template: EditorUtils.dropDownListTemplate,
                title: 'Export As'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/import', ['editor/main'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, proxy = $.proxy, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, Command = Editor.Command, Tool = Editor.Tool, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, loadingOverlay = '<div contenteditable="false" class="k-loading-mask" style="width: 100%; height: 100%; position: absolute; top: 0px; left: 0px;"><div class="k-loading-image"></div><div class="k-loading-color"></div></div>';
        var ImportCommand = Command.extend({
            exec: function () {
                (this.editor._uploadWidget || this._initializeUploadWidget()).element.click();
            },
            _initializeUploadWidget: function () {
                var cmd = this;
                var editor = cmd.editor;
                var importOptions = editor.options['import'];
                var upload = $('<input id="editorImport" name="files" type="file" />').kendoUpload({
                    success: proxy(cmd._onUploadSuccess, cmd),
                    progress: proxy(cmd._onUploadProgress, cmd),
                    select: proxy(cmd._onUploadSelect, cmd),
                    error: proxy(cmd._onUploadError, cmd),
                    complete: proxy(cmd._onUploadComplete, cmd),
                    showFileList: false,
                    multiple: false,
                    async: {
                        saveUrl: importOptions.proxyUrl,
                        autoUpload: true,
                        saveField: 'file'
                    },
                    validation: {
                        allowedExtensions: importOptions.allowedExtensions,
                        maxFileSize: importOptions.maxFileSize
                    }
                }).getKendoUpload();
                editor._uploadWidget = upload;
                return upload;
            },
            _onUploadComplete: function (ev) {
                this._trigger('complete', ev);
                ev.sender.clearAllFiles();
                this._removeLoadingOverlay();
            },
            _onUploadSuccess: function (ev) {
                this.editor.value(ev.response.html.replace(/<\/?body>/gi, ''));
                this._trigger('success', ev);
            },
            _onUploadProgress: function (ev) {
                this._trigger('progress', ev);
            },
            _onUploadSelect: function (ev) {
                this._trigger('select', ev);
                if (!ev.files[0].validationErrors) {
                    this._initLoadingOverlay();
                }
            },
            _onUploadError: function (ev) {
                this._trigger('error', ev);
            },
            _trigger: function (eventType, uploadEvent) {
                var editor = this.editor;
                var importOptions = editor.options['import'];
                if (typeof importOptions[eventType] === 'function') {
                    importOptions[eventType].call(editor, uploadEvent);
                }
            },
            _initLoadingOverlay: function () {
                var editable = this.editor.body;
                if (Editor.Dom.is(editable, 'body')) {
                    this._iframeWrapper = this._container = this.editor.wrapper.find('iframe').parent().css({ position: 'relative' }).append(loadingOverlay);
                } else {
                    this._container = $(editable).append(loadingOverlay);
                }
                kendo.ui.progress(this._container, true);
            },
            _removeLoadingOverlay: function () {
                kendo.ui.progress(this._container, false);
                $(this._iframeWrapper).css({ position: '' });
                delete this._container;
                delete this._iframeWrapper;
            }
        });
        extend(Editor, { ImportCommand: ImportCommand });
        registerTool('import', new Tool({
            command: ImportCommand,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Import'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/resizing-utils', ['editor/main'], f);
}(function () {
    (function (kendo, undefined) {
        var global = window;
        var math = global.Math;
        var min = math.min;
        var max = math.max;
        var parseFloat = global.parseFloat;
        var $ = kendo.jQuery;
        var extend = $.extend;
        var Editor = kendo.ui.editor;
        var PERCENTAGE = '%';
        var PIXEL = 'px';
        var REGEX_NUMBER_IN_PERCENTAGES = /(\d+)(\.?)(\d*)%/;
        var REGEX_NUMBER_IN_PIXELS = /(\d+)(\.?)(\d*)px/;
        var STRING = 'string';
        function constrain(options) {
            var value = options.value;
            var lowerBound = options.min;
            var upperBound = options.max;
            return max(min(parseFloat(value), parseFloat(upperBound)), parseFloat(lowerBound));
        }
        function getScrollBarWidth(element) {
            if (element && !$(element).is('body') && element.scrollHeight > element.clientHeight) {
                return kendo.support.scrollbar();
            }
            return 0;
        }
        function calculatePercentageRatio(value, total) {
            if (inPercentages(value)) {
                return parseFloat(value);
            } else {
                return parseFloat(value) / total * 100;
            }
        }
        function inPercentages(value) {
            return typeof value === STRING && REGEX_NUMBER_IN_PERCENTAGES.test(value);
        }
        function inPixels(value) {
            return typeof value === STRING && REGEX_NUMBER_IN_PIXELS.test(value);
        }
        function toPercentages(value) {
            return parseFloat(value) + PERCENTAGE;
        }
        function toPixels(value) {
            return parseFloat(value) + PIXEL;
        }
        var ResizingUtils = {
            constrain: constrain,
            getScrollBarWidth: getScrollBarWidth,
            calculatePercentageRatio: calculatePercentageRatio,
            inPercentages: inPercentages,
            inPixels: inPixels,
            toPercentages: toPercentages,
            toPixels: toPixels
        };
        extend(Editor, { ResizingUtils: ResizingUtils });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/table-element-resizing', [
        'editor/main',
        'kendo.resizable',
        'editor/resizing/resizing-utils'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var $ = kendo.jQuery;
        var extend = $.extend;
        var noop = $.noop;
        var proxy = $.proxy;
        var Editor = kendo.ui.editor;
        var Class = kendo.Class;
        var KEY_DOWN = 'keydown';
        var MOUSE_DOWN = 'mousedown';
        var MOUSE_ENTER = 'mouseenter';
        var MOUSE_LEAVE = 'mouseleave';
        var MOUSE_MOVE = 'mousemove';
        var MOUSE_UP = 'mouseup';
        var COMMA = ',';
        var DOT = '.';
        var LAST_CHILD = ':last-child';
        var TABLE = 'table';
        var TableElementResizing = Class.extend({
            init: function (element, options) {
                var that = this;
                that.options = extend({}, that.options, options);
                that.options.tags = $.isArray(that.options.tags) ? that.options.tags : [that.options.tags];
                if ($(element).is(TABLE)) {
                    that.element = element;
                    that._attachEventHandlers();
                }
            },
            destroy: function () {
                var that = this;
                var eventNamespace = that.options.eventNamespace;
                if (that.element) {
                    $(that.element).off(eventNamespace);
                    that.element = null;
                }
                $(that.options.rootElement).off(KEY_DOWN + eventNamespace);
                that._destroyResizeHandle();
            },
            options: {
                tags: [],
                min: 0,
                rootElement: null,
                eventNamespace: '',
                rtl: false,
                handle: {
                    dataAttribute: '',
                    height: 0,
                    width: 0,
                    classNames: {},
                    template: ''
                }
            },
            _attachEventHandlers: function () {
                var that = this;
                var options = that.options;
                $(that.element).on(MOUSE_MOVE + options.eventNamespace, options.tags.join(COMMA), proxy(that.detectElementBorderHovering, that));
            },
            resizingInProgress: function () {
                var that = this;
                var resizable = that._resizable;
                if (resizable) {
                    return !!resizable.resizing;
                }
                return false;
            },
            resize: noop,
            detectElementBorderHovering: function (e) {
                var that = this;
                var options = that.options;
                var handleOptions = options.handle;
                var tableElement = $(e.currentTarget);
                var resizeHandle = that.resizeHandle;
                var dataAttribute = handleOptions.dataAttribute;
                if (!that.resizingInProgress()) {
                    if (!tableElement.is(LAST_CHILD) && that.elementBorderHovered(tableElement, e)) {
                        if (resizeHandle) {
                            if (resizeHandle.data(dataAttribute) && resizeHandle.data(dataAttribute) !== tableElement[0]) {
                                that.showResizeHandle(tableElement, e);
                            }
                        } else {
                            that.showResizeHandle(tableElement, e);
                        }
                    } else {
                        if (resizeHandle) {
                            that._destroyResizeHandle();
                        }
                    }
                }
            },
            elementBorderHovered: noop,
            showResizeHandle: function (tableElement, e) {
                var that = this;
                if (e.buttons !== 0) {
                    return;
                }
                that._initResizeHandle();
                that.setResizeHandlePosition(tableElement);
                that.setResizeHandleDimensions();
                that.setResizeHandleDataAttributes(tableElement[0]);
                that._attachResizeHandleEventHandlers();
                that._initResizable(tableElement);
                that._hideResizeMarker();
                that.resizeHandle.show();
            },
            _initResizeHandle: function () {
                var that = this;
                var options = that.options;
                that._destroyResizeHandle();
                that.resizeHandle = $(options.handle.template).appendTo(options.rootElement);
            },
            setResizeHandlePosition: noop,
            setResizeHandleDimensions: noop,
            setResizeHandleDataAttributes: function (tableElement) {
                var that = this;
                that.resizeHandle.data(that.options.handle.dataAttribute, tableElement);
            },
            _attachResizeHandleEventHandlers: function () {
                var that = this;
                var options = that.options;
                var eventNamespace = options.eventNamespace;
                var markerClass = options.handle.classNames.marker;
                var resizeHandle = that.resizeHandle;
                that.resizeHandle.on(MOUSE_DOWN + eventNamespace, function () {
                    resizeHandle.find(DOT + markerClass).show();
                }).on(MOUSE_UP + eventNamespace, function () {
                    resizeHandle.find(DOT + markerClass).hide();
                });
            },
            _hideResizeMarker: function () {
                var that = this;
                that.resizeHandle.find(DOT + that.options.handle.classNames.marker).hide();
            },
            _destroyResizeHandle: function () {
                var that = this;
                if (that.resizeHandle) {
                    that._destroyResizable();
                    that.resizeHandle.off(that.options.eventNamespace).remove();
                    that.resizeHandle = null;
                }
            },
            _initResizable: function (tableElement) {
                var that = this;
                if (!that.resizeHandle) {
                    return;
                }
                that._destroyResizable();
                that._resizable = new kendo.ui.Resizable(tableElement, {
                    draggableElement: that.resizeHandle[0],
                    start: proxy(that.onResizeStart, that),
                    resize: proxy(that.onResize, that),
                    resizeend: proxy(that.onResizeEnd, that)
                });
            },
            _destroyResizable: function () {
                var that = this;
                if (that._resizable) {
                    that._resizable.destroy();
                    that._resizable = null;
                }
            },
            onResizeStart: function () {
                this._disableKeyboard();
            },
            onResize: function (e) {
                this.setResizeHandleDragPosition(e);
            },
            setResizeHandleDragPosition: noop,
            onResizeEnd: function (e) {
                var that = this;
                that.resize(e);
                that._destroyResizeHandle();
                that._enableKeyboard();
            },
            _enableKeyboard: function () {
                var options = this.options;
                $(options.rootElement).off(KEY_DOWN + options.eventNamespace);
            },
            _disableKeyboard: function () {
                var options = this.options;
                $(options.rootElement).on(KEY_DOWN + options.eventNamespace, function (e) {
                    e.preventDefault();
                });
            },
            _forceResizing: function (e) {
                var resizable = this._resizable;
                if (resizable && resizable.userEvents) {
                    resizable.userEvents._end(e);
                }
            }
        });
        var ResizingFactory = Class.extend({
            create: function (editor, options) {
                var that = this;
                var resizingName = options.name;
                var NS = options.eventNamespace;
                $(editor.body).on(MOUSE_ENTER + NS, TABLE, function (e) {
                    var table = e.currentTarget;
                    var resizing = editor[resizingName];
                    e.stopPropagation();
                    if (resizing) {
                        if (resizing.element !== table && !resizing.resizingInProgress()) {
                            that._destroyResizing(editor, options);
                            that._initResizing(editor, table, options);
                        }
                    } else {
                        that._initResizing(editor, table, options);
                    }
                }).on(MOUSE_LEAVE + NS, TABLE, function (e) {
                    var parentTable;
                    var resizing = editor[resizingName];
                    e.stopPropagation();
                    if (resizing && !resizing.resizingInProgress() && !resizing.resizeHandle) {
                        parentTable = $(resizing.element).parents(TABLE)[0];
                        if (parentTable) {
                            that._destroyResizing(editor, options);
                            that._initResizing(editor, parentTable, options);
                        }
                    }
                }).on(MOUSE_LEAVE + NS, function () {
                    var resizing = editor[resizingName];
                    if (resizing && !resizing.resizingInProgress()) {
                        that._destroyResizing(editor, options);
                    }
                }).on(MOUSE_UP + NS, function (e) {
                    var resizing = editor[resizingName];
                    var parentTable;
                    if (resizing && resizing.resizingInProgress()) {
                        parentTable = $(e.target).parents(TABLE)[0];
                        if (parentTable) {
                            resizing._forceResizing(e);
                            that._destroyResizing(editor, options);
                            that._initResizing(editor, parentTable, options);
                        }
                    }
                });
            },
            dispose: function (editor, options) {
                $(editor.body).off(options.eventNamespace);
            },
            _initResizing: function (editor, tableElement, options) {
                var resizingName = options.name;
                var resizingType = options.type;
                editor[resizingName] = new resizingType(tableElement, {
                    rtl: kendo.support.isRtl(editor.element),
                    rootElement: editor.body
                });
            },
            _destroyResizing: function (editor, options) {
                var resizingName = options.name;
                if (editor[resizingName]) {
                    editor[resizingName].destroy();
                    editor[resizingName] = null;
                }
            }
        });
        ResizingFactory.current = new ResizingFactory();
        TableElementResizing.create = function (editor, options) {
            ResizingFactory.current.create(editor, options);
        };
        TableElementResizing.dispose = function (editor, options) {
            ResizingFactory.current.dispose(editor, options);
        };
        extend(Editor, { TableElementResizing: TableElementResizing });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/column-resizing', [
        'editor/main',
        'editor/resizing/resizing-utils',
        'editor/resizing/table-element-resizing'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var global = window;
        var math = global.Math;
        var abs = math.abs;
        var $ = kendo.jQuery;
        var extend = $.extend;
        var Editor = kendo.ui.editor;
        var TableElementResizing = Editor.TableElementResizing;
        var ResizingUtils = Editor.ResizingUtils;
        var constrain = ResizingUtils.constrain;
        var calculatePercentageRatio = ResizingUtils.calculatePercentageRatio;
        var getScrollBarWidth = ResizingUtils.getScrollBarWidth;
        var inPercentages = ResizingUtils.inPercentages;
        var toPercentages = ResizingUtils.toPercentages;
        var toPixels = ResizingUtils.toPixels;
        var outerWidth = kendo._outerWidth;
        var NS = '.kendoEditorColumnResizing';
        var RESIZE_HANDLE_CLASS = 'k-column-resize-handle';
        var RESIZE_MARKER_CLASS = 'k-column-resize-marker';
        var BODY = 'body';
        var TBODY = 'tbody';
        var TD = 'td';
        var TH = 'th';
        var TR = 'tr';
        var COMMA = ',';
        var WIDTH = 'width';
        var ColumnResizing = TableElementResizing.extend({
            options: {
                tags: [
                    TD,
                    TH
                ],
                min: 20,
                rootElement: null,
                eventNamespace: NS,
                rtl: false,
                handle: {
                    dataAttribute: 'column',
                    width: 10,
                    height: 0,
                    classNames: {
                        handle: RESIZE_HANDLE_CLASS,
                        marker: RESIZE_MARKER_CLASS
                    },
                    template: '<div class="k-column-resize-handle-wrapper" unselectable="on" contenteditable="false">' + '<div class="' + RESIZE_HANDLE_CLASS + '">' + '<div class="' + RESIZE_MARKER_CLASS + '"></div>' + '</div>' + '</div>'
                }
            },
            elementBorderHovered: function (column, e) {
                var that = this;
                var options = that.options;
                var handleWidth = options.handle.width;
                var borderOffset = column.offset().left + (options.rtl ? 0 : outerWidth(column));
                var mousePosition = e.clientX + $(column[0].ownerDocument).scrollLeft();
                if (mousePosition > borderOffset - handleWidth && mousePosition < borderOffset + handleWidth) {
                    return true;
                } else {
                    return false;
                }
            },
            setResizeHandlePosition: function (column) {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                var options = that.options;
                var rtl = options.rtl;
                var handleWidth = options.handle.width;
                var rootElement = $(options.rootElement);
                var scrollTopOffset = rootElement.is(BODY) ? 0 : rootElement.scrollTop();
                var scrollLeftOffset = rootElement.is(BODY) ? 0 : rootElement.scrollLeft();
                var columnWidthOffset = rtl ? 0 : outerWidth(column);
                var scrollBarWidth = rtl ? getScrollBarWidth(rootElement[0]) : 0;
                that.resizeHandle.css({
                    top: tableBody.position().top + scrollTopOffset,
                    left: column.position().left + columnWidthOffset + (scrollLeftOffset - scrollBarWidth) - handleWidth / 2,
                    position: 'absolute'
                });
            },
            setResizeHandleDimensions: function () {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                that.resizeHandle.css({
                    width: that.options.handle.width,
                    height: tableBody.height()
                });
            },
            setResizeHandleDragPosition: function (e) {
                var that = this;
                var column = $($(e.currentTarget).data(that.options.handle.dataAttribute));
                var options = that.options;
                var handleWidth = options.handle ? options.handle.width : 0;
                var min = options.min;
                var rtl = options.rtl;
                var columnWidth = outerWidth(column);
                var columnLeftOffset = column.position().left;
                var adjacentColumnWidth = outerWidth(column.next());
                var resizeHandle = $(that.resizeHandle);
                var rootElement = $(options.rootElement);
                var scrollLeftOffset = rootElement.is(BODY) ? 0 : rootElement.scrollLeft();
                var scrollBarWidth = rtl ? getScrollBarWidth(rootElement[0]) : 0;
                var handleOffset = constrain({
                    value: resizeHandle.position().left + (scrollLeftOffset - scrollBarWidth) + e.x.delta,
                    min: columnLeftOffset + (scrollLeftOffset - scrollBarWidth) - (rtl ? adjacentColumnWidth : 0) + min,
                    max: columnLeftOffset + columnWidth + (scrollLeftOffset - scrollBarWidth) + (rtl ? 0 : adjacentColumnWidth) - handleWidth - min
                });
                resizeHandle.css({ left: handleOffset });
            },
            resize: function (e) {
                var that = this;
                var column = $($(e.currentTarget).data(that.options.handle.dataAttribute));
                var options = that.options;
                var rtlModifier = options.rtl ? -1 : 1;
                var min = options.min;
                var initialDeltaX = rtlModifier * e.x.initialDelta;
                var newWidth;
                var initialAdjacentColumnWidth;
                var initialColumnWidth;
                that._setTableComputedWidth();
                that._setColumnsComputedWidth();
                initialColumnWidth = outerWidth(column);
                initialAdjacentColumnWidth = outerWidth(column.next());
                newWidth = constrain({
                    value: initialColumnWidth + initialDeltaX,
                    min: min,
                    max: initialColumnWidth + initialAdjacentColumnWidth - min
                });
                that._resizeColumn(column[0], newWidth);
                that._resizeTopAndBottomColumns(column[0], newWidth);
                that._resizeAdjacentColumns(column.index(), initialAdjacentColumnWidth, initialColumnWidth, initialColumnWidth - newWidth);
            },
            _setTableComputedWidth: function () {
                var element = this.element;
                if (element.style[WIDTH] === '') {
                    element.style[WIDTH] = toPixels(outerWidth($(element)));
                }
            },
            _setColumnsComputedWidth: function () {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                var tableBodyWidth = outerWidth(tableBody);
                var columns = tableBody.children(TR).children(TD);
                var length = columns.length;
                var currentColumnsWidths = columns.map(function () {
                    return outerWidth($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    if (inPercentages(columns[i].style[WIDTH])) {
                        columns[i].style[WIDTH] = toPercentages(calculatePercentageRatio(currentColumnsWidths[i], tableBodyWidth));
                    } else {
                        columns[i].style[WIDTH] = toPixels(currentColumnsWidths[i]);
                    }
                }
            },
            _resizeTopAndBottomColumns: function (column, newWidth) {
                var that = this;
                var columnIndex = $(column).index();
                var topAndBottomColumns = $(that.element).children(TBODY).children(TR).children(that.options.tags.join(COMMA)).filter(function () {
                    var cell = this;
                    return $(cell).index() === columnIndex && cell !== column;
                });
                var length = topAndBottomColumns.length;
                var i;
                for (i = 0; i < length; i++) {
                    that._resizeColumn(topAndBottomColumns[i], newWidth);
                }
            },
            _resizeColumn: function (column, newWidth) {
                if (inPercentages(column.style[WIDTH])) {
                    column.style[WIDTH] = toPercentages(calculatePercentageRatio(newWidth, outerWidth($(this.element).children(TBODY))));
                } else {
                    column.style[WIDTH] = toPixels(newWidth);
                }
            },
            _resizeAdjacentColumns: function (columnIndex, initialAdjacentColumnWidth, initialColumnWidth, deltaWidth) {
                var that = this;
                var adjacentColumns = $(that.element).children(TBODY).children(TR).children(that.options.tags.join(COMMA)).filter(function () {
                    return $(this).index() === columnIndex + 1;
                });
                var length = adjacentColumns.length;
                var i;
                for (i = 0; i < length; i++) {
                    that._resizeAdjacentColumn(adjacentColumns[i], initialAdjacentColumnWidth, initialColumnWidth, deltaWidth);
                }
            },
            _resizeAdjacentColumn: function (adjacentColumn, initialAdjacentColumnWidth, initialColumnWidth, deltaWidth) {
                var that = this;
                var min = that.options.min;
                var newWidth;
                newWidth = constrain({
                    value: initialAdjacentColumnWidth + deltaWidth,
                    min: min,
                    max: abs(initialColumnWidth + initialAdjacentColumnWidth - min)
                });
                that._resizeColumn(adjacentColumn, newWidth);
            }
        });
        ColumnResizing.create = function (editor) {
            TableElementResizing.create(editor, {
                name: 'columnResizing',
                type: ColumnResizing,
                eventNamespace: NS
            });
        };
        ColumnResizing.dispose = function (editor) {
            TableElementResizing.dispose(editor, { eventNamespace: NS });
        };
        extend(Editor, { ColumnResizing: ColumnResizing });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/row-resizing', [
        'editor/main',
        'editor/resizing/resizing-utils',
        'editor/resizing/table-element-resizing'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var math = window.Math;
        var abs = math.abs;
        var $ = kendo.jQuery;
        var extend = $.extend;
        var Editor = kendo.ui.editor;
        var TableElementResizing = Editor.TableElementResizing;
        var ResizingUtils = Editor.ResizingUtils;
        var getScrollBarWidth = ResizingUtils.getScrollBarWidth;
        var constrain = ResizingUtils.constrain;
        var calculatePercentageRatio = ResizingUtils.calculatePercentageRatio;
        var inPercentages = ResizingUtils.inPercentages;
        var toPercentages = ResizingUtils.toPercentages;
        var toPixels = ResizingUtils.toPixels;
        var outerHeight = kendo._outerHeight;
        var NS = '.kendoEditorRowResizing';
        var RESIZE_HANDLE_CLASS = 'k-row-resize-handle';
        var RESIZE_HANDLE_MARKER_WRAPPER_CLASS = 'k-row-resize-marker-wrapper';
        var RESIZE_MARKER_CLASS = 'k-row-resize-marker';
        var BODY = 'body';
        var TR = 'tr';
        var TBODY = 'tbody';
        var HEIGHT = 'height';
        var RowResizing = TableElementResizing.extend({
            options: {
                tags: [TR],
                min: 20,
                rootElement: null,
                eventNamespace: NS,
                rtl: false,
                handle: {
                    dataAttribute: 'row',
                    width: 0,
                    height: 10,
                    classNames: {
                        handle: RESIZE_HANDLE_CLASS,
                        marker: RESIZE_MARKER_CLASS
                    },
                    template: '<div class="k-row-resize-handle-wrapper" unselectable="on" contenteditable="false">' + '<div class="' + RESIZE_HANDLE_CLASS + '">' + '<div class="' + RESIZE_HANDLE_MARKER_WRAPPER_CLASS + '">' + '<div class="' + RESIZE_MARKER_CLASS + '"></div>' + '</div>' + '</div>' + '</div>'
                }
            },
            elementBorderHovered: function (tableElement, e) {
                var that = this;
                var handleHeight = that.options.handle[HEIGHT];
                var borderOffset = tableElement.offset().top + outerHeight(tableElement);
                var mousePosition = e.clientY + $(tableElement[0].ownerDocument).scrollTop();
                if (mousePosition > borderOffset - handleHeight && mousePosition < borderOffset + handleHeight) {
                    return true;
                } else {
                    return false;
                }
            },
            setResizeHandlePosition: function (row) {
                var that = this;
                var options = that.options;
                var handleHeight = options.handle[HEIGHT];
                var rowPosition = row.position();
                var rootElement = $(options.rootElement);
                var scrollTopOffset = rootElement.is(BODY) ? 0 : rootElement.scrollTop();
                var scrollLeftOffset = rootElement.is(BODY) ? 0 : rootElement.scrollLeft();
                var scrollBarWidth = options.rtl ? getScrollBarWidth(rootElement[0]) : 0;
                that.resizeHandle.css({
                    top: rowPosition.top + outerHeight(row) + scrollTopOffset - handleHeight / 2,
                    left: rowPosition.left + (scrollLeftOffset - scrollBarWidth),
                    position: 'absolute'
                });
            },
            setResizeHandleDimensions: function () {
                var that = this;
                that.resizeHandle.css({
                    width: $(that.element).children(TBODY).width(),
                    height: that.options.handle[HEIGHT]
                });
            },
            setResizeHandleDragPosition: function (e) {
                var that = this;
                var options = that.options;
                var min = options.min;
                var tableBody = $(that.element).children(TBODY);
                var tableBodyTopOffset = tableBody.position().top;
                var resizeHandle = $(that.resizeHandle);
                var row = $(e.currentTarget).data(options.handle.dataAttribute);
                var rootElement = $(options.rootElement);
                var scrollTopOffset = rootElement.is(BODY) ? 0 : rootElement.scrollTop();
                var handleOffset = constrain({
                    value: resizeHandle.position().top + scrollTopOffset + e.y.delta,
                    min: $(row).position().top + scrollTopOffset + min,
                    max: tableBodyTopOffset + outerHeight(tableBody) + scrollTopOffset - options.handle[HEIGHT] - min
                });
                resizeHandle.css({ top: handleOffset });
            },
            resize: function (e) {
                var that = this;
                var options = that.options;
                var row = $(e.currentTarget).data(options.handle.dataAttribute);
                var currentRowHeight = outerHeight($(row));
                var element = $(that.element);
                var initialTableHeight = outerHeight(element);
                var tableBody = element.children(TBODY);
                var tableBodyHeight = tableBody.height();
                var initialStyleHeight = row.style[HEIGHT];
                var newRowHeight = constrain({
                    value: currentRowHeight + e.y.initialDelta,
                    min: options.min,
                    max: abs(tableBodyHeight - options.min)
                });
                that._setRowsHeightInPixels();
                row.style[HEIGHT] = toPixels(newRowHeight);
                that._setTableHeight(initialTableHeight + (newRowHeight - currentRowHeight));
                if (inPercentages(initialStyleHeight)) {
                    that._setRowsHeightInPercentages();
                }
            },
            _setRowsHeightInPixels: function () {
                var that = this;
                var rows = $(that.element).children(TBODY).children(TR);
                var length = rows.length;
                var currentRowsHeights = rows.map(function () {
                    return outerHeight($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    rows[i].style[HEIGHT] = toPixels(currentRowsHeights[i]);
                }
            },
            _setRowsHeightInPercentages: function () {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                var tableBodyHeight = tableBody.height();
                var rows = tableBody.children(TR);
                var length = rows.length;
                var currentRowsHeights = rows.map(function () {
                    return outerHeight($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    rows[i].style[HEIGHT] = toPercentages(calculatePercentageRatio(currentRowsHeights[i], tableBodyHeight));
                }
            },
            _setTableHeight: function (newHeight) {
                var element = this.element;
                if (inPercentages(element.style[HEIGHT])) {
                    element.style[HEIGHT] = toPercentages(calculatePercentageRatio(newHeight, $(element).parent().height()));
                } else {
                    element.style[HEIGHT] = toPixels(newHeight);
                }
            }
        });
        RowResizing.create = function (editor) {
            TableElementResizing.create(editor, {
                name: 'rowResizing',
                type: RowResizing,
                eventNamespace: NS
            });
        };
        RowResizing.dispose = function (editor) {
            TableElementResizing.dispose(editor, { eventNamespace: NS });
        };
        extend(Editor, { RowResizing: RowResizing });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/table-resize-handle', [
        'editor/main',
        'kendo.draganddrop',
        'editor/resizing/resizing-utils'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var $ = kendo.jQuery;
        var extend = $.extend;
        var noop = $.noop;
        var proxy = $.proxy;
        var Editor = kendo.ui.editor;
        var Class = kendo.Class;
        var Draggable = kendo.ui.Draggable;
        var Observable = kendo.Observable;
        var getScrollBarWidth = Editor.ResizingUtils.getScrollBarWidth;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var NS = '.kendoEditorTableResizeHandle';
        var RESIZE_HANDLE_CLASS = 'k-table-resize-handle';
        var DRAG_START = 'dragStart';
        var DRAG = 'drag';
        var DRAG_END = 'dragEnd';
        var HALF_INSIDE = 'halfInside';
        var MOUSE_OVER = 'mouseover';
        var MOUSE_OUT = 'mouseout';
        var BODY = 'body';
        var TABLE = 'table';
        var EAST = 'east';
        var NORTH = 'north';
        var NORTHEAST = 'northeast';
        var NORTHWEST = 'northwest';
        var SOUTH = 'south';
        var SOUTHEAST = 'southeast';
        var SOUTHWEST = 'southwest';
        var WEST = 'west';
        var DOT = '.';
        var TableResizeHandle = Observable.extend({
            init: function (options) {
                var that = this;
                Observable.fn.init.call(that);
                that.options = extend({}, that.options, options);
                that.element = $(that.options.template).appendTo(that.options.appendTo)[0];
                that._attachEventHandlers();
                that._addStyles();
                that._initDraggable();
                that._initPositioningStrategy();
                that._initDraggingStrategy();
                $(that.element).data(TABLE, that.options.resizableElement);
            },
            destroy: function () {
                var that = this;
                $(that.element).off(NS).remove();
                that.element = null;
                that._destroyDraggable();
                that.unbind();
            },
            options: {
                appendTo: null,
                direction: SOUTHEAST,
                resizableElement: null,
                rtl: false,
                template: '<div class=\'k-table-resize-handle-wrapper\' unselectable=\'on\' contenteditable=\'false\'>' + '<div class=\'' + RESIZE_HANDLE_CLASS + '\'></div>' + '</div>'
            },
            events: [
                DRAG_START,
                DRAG,
                DRAG_END,
                MOUSE_OVER,
                MOUSE_OUT
            ],
            show: function () {
                this._setPosition();
            },
            _setPosition: function () {
                var that = this;
                var position = that._positioningStrategy.getPosition();
                $(that.element).css({
                    top: position.top,
                    left: position.left,
                    position: 'absolute'
                });
            },
            _attachEventHandlers: function () {
                var that = this;
                $(that.element).on(MOUSE_OVER + NS, proxy(that._onMouseOver, that)).on(MOUSE_OUT + NS, proxy(that._onMouseOut, that));
            },
            _onMouseOver: function () {
                this.trigger(MOUSE_OVER);
            },
            _onMouseOut: function () {
                this.trigger(MOUSE_OUT);
            },
            _addStyles: function () {
                var that = this;
                $(that.element).children(DOT + RESIZE_HANDLE_CLASS).addClass('k-resize-' + that.options.direction);
            },
            _initPositioningStrategy: function () {
                var that = this;
                var options = that.options;
                that._positioningStrategy = HandlePositioningStrategy.create({
                    name: options.direction,
                    handle: that.element,
                    resizableElement: options.resizableElement,
                    rootElement: options.rootElement,
                    rtl: options.rtl
                });
            },
            _initDraggable: function () {
                var that = this;
                var element = that.element;
                if (that._draggable || !element) {
                    return;
                }
                that._draggable = new Draggable(element, {
                    dragstart: proxy(that._onDragStart, that),
                    drag: proxy(that._onDrag, that),
                    dragend: proxy(that._onDragEnd, that)
                });
            },
            _onDragStart: function () {
                this.trigger(DRAG_START);
            },
            _onDrag: function (e) {
                var that = this;
                that.trigger(DRAG, that._draggingStrategy.adjustDragDelta({
                    deltaX: e.x.delta,
                    deltaY: e.y.delta,
                    initialDeltaX: e.x.initialDelta,
                    initialDeltaY: e.y.initialDelta
                }));
            },
            _onDragEnd: function () {
                this.trigger(DRAG_END);
            },
            _destroyDraggable: function () {
                var that = this;
                if (that._draggable) {
                    that._draggable.destroy();
                    that._draggable = null;
                }
            },
            _initDraggingStrategy: function () {
                var that = this;
                that._draggingStrategy = HandleDraggingStrategy.create({ name: that.options.direction });
            }
        });
        var StrategyFactory = Class.extend({
            init: function () {
                this._items = [];
            },
            register: function (name, type) {
                this._items.push({
                    name: name,
                    type: type
                });
            },
            create: function (options) {
                var items = this._items;
                var itemsLength = items.length;
                var name = options.name ? options.name.toLowerCase() : '';
                var match;
                var item;
                var i;
                for (i = 0; i < itemsLength; i++) {
                    item = items[i];
                    if (item.name.toLowerCase() === name) {
                        match = item;
                        break;
                    }
                }
                if (match) {
                    return new match.type(options);
                }
            }
        });
        var PositioningStrategyFactory = StrategyFactory.extend({});
        PositioningStrategyFactory.current = new PositioningStrategyFactory();
        var HandlePositioningStrategy = Class.extend({
            init: function (options) {
                var that = this;
                that.options = extend({}, that.options, options);
            },
            options: {
                handle: null,
                offset: HALF_INSIDE,
                resizableElement: null,
                rootElement: null,
                rtl: false
            },
            getPosition: function () {
                var that = this;
                var position = that.calculatePosition();
                var handleOffsetPosition = that.applyHandleOffset(position);
                var scrollOffsetPosition = that.applyScrollOffset(handleOffsetPosition);
                return scrollOffsetPosition;
            },
            calculatePosition: noop,
            applyHandleOffset: function (position) {
                var options = this.options;
                var handle = $(options.handle);
                if (options.offset === HALF_INSIDE) {
                    return {
                        top: position.top - outerHeight(handle) / 2,
                        left: position.left - outerWidth(handle) / 2
                    };
                }
                return position;
            },
            applyScrollOffset: function (position) {
                var options = this.options;
                var rootElement = $(options.rootElement);
                var scrollBarWidth = options.rtl ? getScrollBarWidth(rootElement[0]) : 0;
                if (!rootElement.is(BODY)) {
                    return {
                        top: position.top + (rootElement.scrollTop() || 0),
                        left: position.left + (rootElement.scrollLeft() || 0) - scrollBarWidth
                    };
                }
                return position;
            }
        });
        HandlePositioningStrategy.create = function (options) {
            return PositioningStrategyFactory.current.create(options);
        };
        var EastPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement) / 2,
                    left: offset.left + outerWidth(resizableElement)
                };
            }
        });
        PositioningStrategyFactory.current.register(EAST, EastPositioningStrategy);
        var NorthPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top,
                    left: offset.left + outerWidth(resizableElement) / 2
                };
            }
        });
        PositioningStrategyFactory.current.register(NORTH, NorthPositioningStrategy);
        var NortheastPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top,
                    left: offset.left + outerWidth(resizableElement)
                };
            }
        });
        PositioningStrategyFactory.current.register(NORTHEAST, NortheastPositioningStrategy);
        var NorthwestPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top,
                    left: offset.left
                };
            }
        });
        PositioningStrategyFactory.current.register(NORTHWEST, NorthwestPositioningStrategy);
        var SouthPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement),
                    left: offset.left + outerWidth(resizableElement) / 2
                };
            }
        });
        PositioningStrategyFactory.current.register(SOUTH, SouthPositioningStrategy);
        var SoutheastPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement),
                    left: offset.left + outerWidth(resizableElement)
                };
            }
        });
        PositioningStrategyFactory.current.register(SOUTHEAST, SoutheastPositioningStrategy);
        var SouthwestPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement),
                    left: offset.left
                };
            }
        });
        PositioningStrategyFactory.current.register(SOUTHWEST, SouthwestPositioningStrategy);
        var WestPositioningStrategy = HandlePositioningStrategy.extend({
            calculatePosition: function () {
                var resizableElement = $(this.options.resizableElement);
                var offset = resizableElement.position();
                return {
                    top: offset.top + outerHeight(resizableElement) / 2,
                    left: offset.left
                };
            }
        });
        PositioningStrategyFactory.current.register(WEST, WestPositioningStrategy);
        var DraggingStrategyFactory = StrategyFactory.extend({});
        DraggingStrategyFactory.current = new DraggingStrategyFactory();
        var HandleDraggingStrategy = Class.extend({
            init: function (options) {
                var that = this;
                that.options = extend({}, that.options, options);
            },
            options: {
                deltaX: {
                    adjustment: null,
                    modifier: null
                },
                deltaY: {
                    adjustment: null,
                    modifier: null
                }
            },
            adjustDragDelta: function (deltas) {
                var options = this.options;
                var xAxisAdjustment = options.deltaX.adjustment * options.deltaX.modifier;
                var yAxisAdjustment = options.deltaY.adjustment * options.deltaY.modifier;
                return {
                    deltaX: deltas.deltaX * xAxisAdjustment,
                    deltaY: deltas.deltaY * yAxisAdjustment,
                    initialDeltaX: deltas.initialDeltaX * xAxisAdjustment,
                    initialDeltaY: deltas.initialDeltaY * yAxisAdjustment
                };
            }
        });
        HandleDraggingStrategy.create = function (options) {
            return DraggingStrategyFactory.current.create(options);
        };
        var HorizontalDraggingStrategy = HandleDraggingStrategy.extend({
            options: {
                deltaX: {
                    adjustment: 1,
                    modifier: 1
                },
                deltaY: {
                    adjustment: 0,
                    modifier: 0
                }
            }
        });
        var EastDraggingStrategy = HorizontalDraggingStrategy.extend({ options: { deltaX: { modifier: 1 } } });
        DraggingStrategyFactory.current.register(EAST, EastDraggingStrategy);
        var WestDraggingStrategy = HorizontalDraggingStrategy.extend({ options: { deltaX: { modifier: -1 } } });
        DraggingStrategyFactory.current.register(WEST, WestDraggingStrategy);
        var VerticalDraggingStrategy = HandleDraggingStrategy.extend({
            options: {
                deltaX: {
                    adjustment: 0,
                    modifier: 0
                },
                deltaY: {
                    adjustment: 1,
                    modifier: 1
                }
            }
        });
        var NorthDraggingStrategy = VerticalDraggingStrategy.extend({ options: { deltaY: { modifier: -1 } } });
        DraggingStrategyFactory.current.register(NORTH, NorthDraggingStrategy);
        var SouthDraggingStrategy = VerticalDraggingStrategy.extend({ options: { deltaY: { modifier: 1 } } });
        DraggingStrategyFactory.current.register(SOUTH, SouthDraggingStrategy);
        var HorizontalAndVerticalDraggingStrategy = HandleDraggingStrategy.extend({
            options: {
                deltaX: {
                    adjustment: 1,
                    modifier: 1
                },
                deltaY: {
                    adjustment: 1,
                    modifier: 1
                }
            }
        });
        var NorthEastDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({
            options: {
                deltaX: { modifier: 1 },
                deltaY: { modifier: -1 }
            }
        });
        DraggingStrategyFactory.current.register(NORTHEAST, NorthEastDraggingStrategy);
        var NorthWestDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({
            options: {
                deltaX: { modifier: -1 },
                deltaY: { modifier: -1 }
            }
        });
        DraggingStrategyFactory.current.register(NORTHWEST, NorthWestDraggingStrategy);
        var SouthEastDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({
            options: {
                deltaX: { modifier: 1 },
                deltaY: { modifier: 1 }
            }
        });
        DraggingStrategyFactory.current.register(SOUTHEAST, SouthEastDraggingStrategy);
        var SouthWestDraggingStrategy = HorizontalAndVerticalDraggingStrategy.extend({
            options: {
                deltaX: { modifier: -1 },
                deltaY: { modifier: 1 }
            }
        });
        DraggingStrategyFactory.current.register(SOUTHWEST, SouthWestDraggingStrategy);
        extend(Editor, { TableResizeHandle: TableResizeHandle });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/resizing/table-resizing', [
        'editor/main',
        'editor/resizing/table-resize-handle',
        'editor/resizing/resizing-utils'
    ], f);
}(function () {
    (function (kendo, undefined) {
        var global = window;
        var math = global.Math;
        var min = math.min;
        var max = math.max;
        var $ = kendo.jQuery;
        var contains = $.contains;
        var extend = $.extend;
        var proxy = $.proxy;
        var browser = kendo.support.browser;
        var Editor = kendo.ui.editor;
        var Class = kendo.Class;
        var TableResizeHandle = Editor.TableResizeHandle;
        var ResizingUtils = Editor.ResizingUtils;
        var calculatePercentageRatio = ResizingUtils.calculatePercentageRatio;
        var constrain = ResizingUtils.constrain;
        var inPercentages = ResizingUtils.inPercentages;
        var inPixels = ResizingUtils.inPixels;
        var toPercentages = ResizingUtils.toPercentages;
        var toPixels = ResizingUtils.toPixels;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var NS = '.kendoEditorTableResizing';
        var RESIZE_HANDLE_WRAPPER_CLASS = 'k-table-resize-handle-wrapper';
        var TABLE_CLASS = 'k-table';
        var TABLE_RESIZING_CLASS = 'k-table-resizing';
        var DRAG_START = 'dragStart';
        var DRAG = 'drag';
        var DRAG_END = 'dragEnd';
        var KEY_DOWN = 'keydown';
        var MOUSE_DOWN = 'mousedown';
        var MOUSE_OVER = 'mouseover';
        var MOUSE_OUT = 'mouseout';
        var COLUMN = 'td';
        var ROW = 'tr';
        var TBODY = 'tbody';
        var TABLE = 'table';
        var WIDTH = 'width';
        var HEIGHT = 'height';
        var EAST = 'east';
        var NORTH = 'north';
        var NORTHEAST = 'northeast';
        var NORTHWEST = 'northwest';
        var SOUTH = 'south';
        var SOUTHEAST = 'southeast';
        var SOUTHWEST = 'southwest';
        var WEST = 'west';
        var DOT = '.';
        function isUndefined(value) {
            return typeof value === 'undefined';
        }
        var TableResizing = Class.extend({
            init: function (element, options) {
                var that = this;
                that.options = extend({}, that.options, options);
                that.handles = [];
                if ($(element).is(TABLE)) {
                    that.element = element;
                }
            },
            destroy: function () {
                var that = this;
                $(that.element).off(NS);
                that.element = null;
                $(that.options.rootElement).off(KEY_DOWN + NS);
                that._destroyResizeHandles();
            },
            options: {
                appendHandlesTo: null,
                rtl: false,
                rootElement: null,
                minWidth: 10,
                minHeight: 10,
                handles: [
                    { direction: NORTHWEST },
                    { direction: NORTH },
                    { direction: NORTHEAST },
                    { direction: EAST },
                    { direction: SOUTHEAST },
                    { direction: SOUTH },
                    { direction: SOUTHWEST },
                    { direction: WEST }
                ]
            },
            resize: function (args) {
                var that = this;
                var deltas = extend({}, {
                    deltaX: 0,
                    deltaY: 0,
                    initialDeltaX: 0,
                    initialDeltaY: 0
                }, args);
                that._resizeWidth(deltas.deltaX, deltas.initialDeltaX);
                that._resizeHeight(deltas.deltaY, deltas.initialDeltaY);
                that.showResizeHandles();
            },
            _resizeWidth: function (delta, initialDelta) {
                var that = this;
                var element = $(that.element);
                var styleWidth = element[0].style[WIDTH];
                var currentWidth = outerWidth(element);
                var parentWidth = element.parent().width();
                var maxWidth = that._getMaxDimensionValue(WIDTH);
                var newWidth;
                var ratioValue;
                var ratioTotalValue;
                var constrainedWidth;
                if (delta === 0) {
                    return;
                }
                if (isUndefined(that._initialElementWidth)) {
                    that._initialElementWidth = currentWidth;
                }
                constrainedWidth = constrain({
                    value: that._initialElementWidth + initialDelta,
                    min: that.options.minWidth,
                    max: maxWidth
                });
                if (inPercentages(styleWidth)) {
                    if (currentWidth + delta > parentWidth) {
                        ratioValue = max(constrainedWidth, parentWidth);
                        ratioTotalValue = min(constrainedWidth, parentWidth);
                    } else {
                        ratioValue = min(constrainedWidth, parentWidth);
                        ratioTotalValue = max(constrainedWidth, parentWidth);
                    }
                    newWidth = toPercentages(calculatePercentageRatio(ratioValue, ratioTotalValue));
                } else {
                    newWidth = toPixels(constrainedWidth);
                }
                that._setColumnsWidth();
                element[0].style[WIDTH] = newWidth;
            },
            _resizeHeight: function (delta, initialDelta) {
                var that = this;
                var element = $(that.element);
                var styleHeight = element[0].style[HEIGHT];
                var currentHeight = outerHeight(element);
                var parent = element.parent();
                var parentHeight = parent.height();
                var maxHeight = that._getMaxDimensionValue(HEIGHT);
                var newHeight;
                var ratioValue;
                var ratioTotalValue;
                var constrainedHeight;
                var minHeight = that.options.minHeight;
                var hasRowsInPixels = that._hasRowsInPixels();
                if (delta === 0) {
                    return;
                }
                if (isUndefined(that._initialElementHeight)) {
                    that._initialElementHeight = currentHeight;
                }
                constrainedHeight = constrain({
                    value: that._initialElementHeight + initialDelta,
                    min: minHeight,
                    max: maxHeight
                });
                if (hasRowsInPixels && delta < 0) {
                    that._setRowsHeightInPercentages();
                }
                if (inPercentages(styleHeight)) {
                    if (currentHeight + delta > parentHeight) {
                        ratioValue = max(constrainedHeight, parentHeight);
                        ratioTotalValue = min(constrainedHeight, parentHeight);
                    } else {
                        ratioValue = min(constrainedHeight, parentHeight);
                        ratioTotalValue = max(constrainedHeight, parentHeight);
                    }
                    newHeight = toPercentages(calculatePercentageRatio(ratioValue, ratioTotalValue));
                } else {
                    newHeight = toPixels(constrainedHeight);
                }
                element[0].style[HEIGHT] = newHeight;
                if (hasRowsInPixels && delta < 0) {
                    that._setRowsHeightInPixels();
                }
            },
            _getMaxDimensionValue: function (dimension) {
                var that = this;
                var element = $(that.element);
                var dimensionLowercase = dimension.toLowerCase();
                var rtlModifier = that.options.rtl ? -1 : 1;
                var parent = $(that.element).parent();
                var parentElement = parent[0];
                var parentDimension = parent[dimensionLowercase]();
                var parentScrollOffset = rtlModifier * (dimension === WIDTH ? parent.scrollLeft() : parent.scrollTop());
                if (parentElement === element.closest(COLUMN)[0]) {
                    if (parentElement.style[dimensionLowercase] === '' && !inPercentages(that.element.style[dimensionLowercase])) {
                        return Infinity;
                    } else {
                        return parentDimension + parentScrollOffset;
                    }
                } else {
                    return parentDimension + parentScrollOffset;
                }
            },
            _setColumnsWidth: function () {
                var that = this;
                var element = $(that.element);
                var parentElement = element.parent()[0];
                var parentColumn = element.closest(COLUMN);
                var columns = parentColumn.closest(ROW).children();
                var columnsLength = columns.length;
                var i;
                function isWidthInPercentages(element) {
                    var styleWidth = element.style.width;
                    if (styleWidth !== '') {
                        return inPercentages(styleWidth) ? true : false;
                    } else {
                        return $(element).hasClass(TABLE_CLASS) ? true : false;
                    }
                }
                if (isWidthInPercentages(element[0]) && parentElement === parentColumn[0] && parentElement.style[WIDTH] === '') {
                    for (i = 0; i < columnsLength; i++) {
                        columns[i].style[WIDTH] = toPixels($(columns[i]).width());
                    }
                }
            },
            _hasRowsInPixels: function () {
                var that = this;
                var rows = $(that.element).children(TBODY).children(ROW);
                for (var i = 0; i < rows.length; i++) {
                    if (rows[i].style.height === '' || inPixels(rows[i].style.height)) {
                        return true;
                    }
                }
                return false;
            },
            _setRowsHeightInPercentages: function () {
                var that = this;
                var tableBody = $(that.element).children(TBODY);
                var tableBodyHeight = tableBody.height();
                var rows = tableBody.children(ROW);
                var length = rows.length;
                var currentRowsHeights = rows.map(function () {
                    return outerHeight($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    rows[i].style[HEIGHT] = toPercentages(calculatePercentageRatio(currentRowsHeights[i], tableBodyHeight));
                }
            },
            _setRowsHeightInPixels: function () {
                var that = this;
                var rows = $(that.element).children(TBODY).children(ROW);
                var length = rows.length;
                var currentRowsHeights = rows.map(function () {
                    return outerHeight($(this));
                });
                var i;
                for (i = 0; i < length; i++) {
                    rows[i].style[HEIGHT] = toPixels(currentRowsHeights[i]);
                }
            },
            showResizeHandles: function () {
                var that = this;
                that._initResizeHandles();
                that._showResizeHandles();
            },
            _initResizeHandles: function () {
                var that = this;
                var handles = that.handles;
                var options = that.options;
                var handleOptions = that.options.handles;
                var length = handleOptions.length;
                var i;
                if (handles && handles.length > 0) {
                    return;
                }
                for (i = 0; i < length; i++) {
                    that.handles.push(new TableResizeHandle(extend({
                        appendTo: options.appendHandlesTo,
                        resizableElement: that.element,
                        rootElement: options.rootElement,
                        rtl: options.rtl
                    }, handleOptions[i])));
                }
                that._bindToResizeHandlesEvents();
            },
            _destroyResizeHandles: function () {
                var that = this;
                var length = that.handles ? that.handles.length : 0;
                for (var i = 0; i < length; i++) {
                    that.handles[i].destroy();
                }
            },
            _showResizeHandles: function () {
                var that = this;
                var handles = that.handles || [];
                var length = handles.length;
                var i;
                for (i = 0; i < length; i++) {
                    that.handles[i].show();
                }
            },
            _bindToResizeHandlesEvents: function () {
                var that = this;
                var handles = that.handles || [];
                var length = handles.length;
                var i;
                var handle;
                for (i = 0; i < length; i++) {
                    handle = handles[i];
                    handle.bind(DRAG_START, proxy(that._onResizeHandleDragStart, that));
                    handle.bind(DRAG, proxy(that._onResizeHandleDrag, that));
                    handle.bind(DRAG_END, proxy(that._onResizeHandleDragEnd, that));
                    handle.bind(MOUSE_OVER, proxy(that._onResizeHandleMouseOver, that));
                    handle.bind(MOUSE_OUT, proxy(that._onResizeHandleMouseOut, that));
                }
            },
            _onResizeHandleDragStart: function () {
                var that = this;
                var element = $(that.element);
                element.addClass(TABLE_RESIZING_CLASS);
                that._initialElementHeight = outerHeight(element);
                that._initialElementWidth = outerWidth(element);
                that._disableKeyboard();
            },
            _onResizeHandleDrag: function (e) {
                this.resize(e);
            },
            _onResizeHandleDragEnd: function () {
                var that = this;
                $(that.element).removeClass(TABLE_RESIZING_CLASS);
                that._enableKeyboard();
            },
            _enableKeyboard: function () {
                $(this.options.rootElement).off(KEY_DOWN + NS);
            },
            _disableKeyboard: function () {
                $(this.options.rootElement).on(KEY_DOWN + NS, function (e) {
                    e.preventDefault();
                });
            }
        });
        var TableResizingFactory = Class.extend({
            create: function (editor) {
                var factory = this;
                $(editor.body).on(MOUSE_DOWN + NS, TABLE, function (e) {
                    var eventTarget = e.target;
                    var eventCurrentTarget = e.currentTarget;
                    var tableResizing = editor.tableResizing;
                    var element = tableResizing ? tableResizing.element : null;
                    if (tableResizing) {
                        if (element && eventCurrentTarget !== element) {
                            if (contains(eventCurrentTarget, element) && element !== eventTarget && contains(element, eventTarget)) {
                                return;
                            } else {
                                if (element !== eventTarget) {
                                    editor._destroyTableResizing();
                                    factory._initResizing(editor, eventCurrentTarget);
                                }
                            }
                        }
                    } else {
                        factory._initResizing(editor, eventCurrentTarget);
                    }
                    editor._showTableResizeHandles();
                }).on(MOUSE_DOWN + NS, function (e) {
                    var tableResizing = editor.tableResizing;
                    var element = tableResizing ? tableResizing.element : null;
                    var target = e.target;
                    var isResizeHandleOrChild = $(target).hasClass(RESIZE_HANDLE_WRAPPER_CLASS) || $(target).parents(DOT + RESIZE_HANDLE_WRAPPER_CLASS).length > 0;
                    if (tableResizing && element !== target && !contains(element, target) && !isResizeHandleOrChild) {
                        editor._destroyTableResizing();
                    }
                });
            },
            dispose: function (editor) {
                $(editor.body).off(NS);
            },
            _initResizing: function (editor, table) {
                if (!browser.msie && !browser.mozilla) {
                    editor.tableResizing = new TableResizing(table, {
                        appendHandlesTo: editor.body,
                        rtl: kendo.support.isRtl(editor.element),
                        rootElement: editor.body
                    });
                }
            }
        });
        TableResizingFactory.current = new TableResizingFactory();
        TableResizing.create = function (editor) {
            TableResizingFactory.current.create(editor);
        };
        TableResizing.dispose = function (editor) {
            TableResizingFactory.current.dispose(editor);
        };
        extend(Editor, { TableResizing: TableResizing });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/immutables', ['editor/tables'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, Editor = kendo.ui.editor, dom = Editor.Dom, template = kendo.template, RangeUtils = Editor.RangeUtils, complexBlocks = [
                'ul',
                'ol',
                'tbody',
                'thead',
                'table'
            ], toolsToBeUpdated = [
                'bold',
                'italic',
                'underline',
                'strikethrough',
                'superscript',
                'subscript',
                'forecolor',
                'backcolor',
                'fontname',
                'fontsize',
                'createlink',
                'unlink',
                'autolink',
                'addcolumnleft',
                'addcolumnright',
                'addrowabove',
                'addrowbelow',
                'deleterow',
                'deletecolumn',
                'mergecells',
                'formatting',
                'cleanformatting'
            ], IMMUTABALE = 'k-immutable', IMMUTABALE_MARKER_SELECTOR = '[' + IMMUTABALE + ']', IMMUTABLE_SELECTOR = '[contenteditable=\'false\']';
        var rootCondition = function (node) {
            return $(node).is('body,.k-editor');
        };
        var immutable = function (node) {
            return node.getAttribute && node.getAttribute('contenteditable') == 'false';
        };
        var immutableParent = function (node) {
            return dom.closestBy(node, immutable, rootCondition);
        };
        var expandImmutablesIn = function (range) {
            var startImmutableParent = immutableParent(range.startContainer);
            var endImmutableParent = immutableParent(range.endContainer);
            if (startImmutableParent || endImmutableParent) {
                if (startImmutableParent) {
                    range.setStartBefore(startImmutableParent);
                }
                if (endImmutableParent) {
                    range.setEndAfter(endImmutableParent);
                }
            }
        };
        var immutablesContext = function (range) {
            if (immutableParent(range.commonAncestorContainer)) {
                return true;
            } else if (immutableParent(range.startContainer) || immutableParent(range.endContainer)) {
                var editableNodes = RangeUtils.editableTextNodes(range);
                if (editableNodes.length === 0) {
                    return true;
                }
            }
            return false;
        };
        var randomId = function (length) {
            var result = '';
            var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
            for (var i = length || 10; i > 0; --i) {
                result += chars.charAt(Math.round(Math.random() * (chars.length - 1)));
            }
            return result;
        };
        var removeImmutables = function (root) {
            var serializedImmutables = { empty: true }, nodeName, id, serialized;
            $(root).find(IMMUTABLE_SELECTOR).each(function (i, node) {
                nodeName = dom.name(node);
                id = randomId();
                serialized = '<' + nodeName + ' ' + IMMUTABALE + '=\'' + id + '\'></' + nodeName + '>';
                serializedImmutables[id] = {
                    node: node,
                    style: $(node).attr('style')
                };
                serializedImmutables.empty = false;
                $(node).replaceWith(serialized);
            });
            return serializedImmutables;
        };
        var restoreImmutables = function (root, serializedImmutables) {
            var id, immutable;
            $(root).find(IMMUTABALE_MARKER_SELECTOR).each(function (i, node) {
                id = node.getAttribute(IMMUTABALE);
                immutable = serializedImmutables[id];
                $(node).replaceWith(immutable.node);
                if (immutable.style != $(immutable.node).attr('style')) {
                    $(immutable.node).removeAttr('style').attr('style', immutable.style);
                }
            });
        };
        var deletingKey = function (keyCode) {
            var keys = kendo.keys;
            return keyCode === keys.BACKSPACE || keyCode == keys.DELETE;
        };
        var updateToolOptions = function (tool) {
            var options = tool ? tool.options : undefined;
            if (options && options.finder) {
                options.finder._initOptions({ immutables: true });
            }
        };
        var Immutables = Class.extend({
            init: function (editor) {
                this.editor = editor;
                this.serializedImmutables = {};
                this.options = $.extend({}, editor && editor.options && editor.options.immutables);
                var tools = editor.toolbar.tools;
                updateToolOptions(tools.justifyLeft);
                updateToolOptions(tools.justifyCenter);
                updateToolOptions(tools.justifyRight);
                updateToolOptions(tools.justifyFull);
            },
            serialize: function (node) {
                var result = this._toHtml(node), id;
                if (result.indexOf(IMMUTABALE) === -1) {
                    id = this.randomId();
                    result = result.replace(/>/, ' ' + IMMUTABALE + '="' + id + '">');
                } else {
                    id = result.match(/k-immutable\s*=\s*['"](.*)['"]/)[1];
                }
                this.serializedImmutables[id] = node;
                return result;
            },
            _toHtml: function (node) {
                var serialization = this.options.serialization;
                var serializationType = typeof serialization;
                var nodeName;
                switch (serializationType) {
                case 'string':
                    return template(serialization)(node);
                case 'function':
                    return serialization(node);
                default:
                    nodeName = dom.name(node);
                    return '<' + nodeName + '></' + nodeName + '>';
                }
            },
            deserialize: function (node) {
                var that = this;
                var deserialization = this.options.deserialization;
                $(IMMUTABALE_MARKER_SELECTOR, node).each(function () {
                    var id = this.getAttribute(IMMUTABALE);
                    var immutable = that.serializedImmutables[id];
                    if (kendo.isFunction(deserialization)) {
                        deserialization(this, immutable);
                    }
                    $(this).replaceWith(immutable);
                });
                that.serializedImmutables = {};
            },
            randomId: function (length) {
                return randomId(length);
            },
            keydown: function (e, range) {
                var isDeleting = deletingKey(e.keyCode);
                var shouldCancelEvent = isDeleting && this._cancelDeleting(e, range) || !isDeleting && this._cancelTyping(e, range);
                if (shouldCancelEvent) {
                    e.preventDefault();
                    return true;
                }
            },
            _cancelTyping: function (e, range) {
                var editor = this.editor;
                var keyboard = editor.keyboard;
                return range.collapsed && !keyboard.typingInProgress && keyboard.isTypingKey(e) && immutablesContext(range);
            },
            _cancelDeleting: function (e, range) {
                var keys = kendo.keys;
                var backspace = e.keyCode === keys.BACKSPACE;
                var del = e.keyCode == keys.DELETE;
                if (!backspace && !del) {
                    return false;
                }
                var cancelDeleting = false;
                if (range.collapsed) {
                    if (immutablesContext(range)) {
                        return true;
                    }
                    var immutable = this.nextImmutable(range, del);
                    if (immutable && backspace) {
                        var closestSelectionLi = dom.closest(range.commonAncestorContainer, 'li');
                        if (closestSelectionLi) {
                            var closestImmutableLi = dom.closest(immutable, 'li');
                            if (closestImmutableLi && closestImmutableLi !== closestSelectionLi) {
                                return cancelDeleting;
                            }
                        }
                    }
                    if (immutable && !dom.tableCell(immutable)) {
                        if (dom.parentOfType(immutable, complexBlocks) === dom.parentOfType(range.commonAncestorContainer, complexBlocks)) {
                            while (immutable && immutable.parentNode.childNodes.length == 1) {
                                immutable = immutable.parentNode;
                            }
                            if (dom.tableCell(immutable)) {
                                return cancelDeleting;
                            }
                            this._removeImmutable(immutable, range);
                        }
                        cancelDeleting = true;
                    }
                }
                return cancelDeleting;
            },
            nextImmutable: function (range, forwards) {
                var commonContainer = range.commonAncestorContainer;
                if (dom.isBom(commonContainer) || (forwards && RangeUtils.isEndOf(range, commonContainer) || !forwards && RangeUtils.isStartOf(range, commonContainer))) {
                    var next = this._nextNode(commonContainer, forwards);
                    if (next && dom.isBlock(next) && !immutableParent(next)) {
                        while (next && next.children && next.children[forwards ? 0 : next.children.length - 1]) {
                            next = next.children[forwards ? 0 : next.children.length - 1];
                        }
                    }
                    return immutableParent(next);
                }
            },
            _removeImmutable: function (immutable, range) {
                var editor = this.editor;
                var startRestorePoint = new Editor.RestorePoint(range, editor.body);
                dom.remove(immutable);
                Editor._finishUpdate(editor, startRestorePoint);
            },
            _nextNode: function (node, forwards) {
                var sibling = forwards ? 'nextSibling' : 'previousSibling';
                var current = node, next;
                while (current && !next) {
                    next = current[sibling];
                    if (next && dom.isDataNode(next) && /^\s|[\ufeff]$/.test(next.nodeValue)) {
                        current = next;
                        next = current[sibling];
                    }
                    if (!next) {
                        current = current.parentNode;
                    }
                }
                return next;
            }
        });
        Immutables.immutable = immutable;
        Immutables.immutableParent = immutableParent;
        Immutables.expandImmutablesIn = expandImmutablesIn;
        Immutables.immutablesContext = immutablesContext;
        Immutables.toolsToBeUpdated = toolsToBeUpdated;
        Immutables.removeImmutables = removeImmutables;
        Immutables.restoreImmutables = restoreImmutables;
        Editor.Immutables = Immutables;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/table-wizard/table-wizard-command', ['editor/tables'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, Editor = kendo.ui.editor, EditorUtils = Editor.EditorUtils, RangeUtils = Editor.RangeUtils, dom = Editor.Dom, registerTool = EditorUtils.registerTool, ToolTemplate = Editor.ToolTemplate, Command = Editor.Command;
        var tableFormatFinder = new Editor.BlockFormatFinder([{ tags: ['table'] }]);
        var cellsFormatFinder = new Editor.BlockFormatFinder([{
                tags: [
                    'td',
                    'th'
                ]
            }]);
        var reUnit = /([a-z]+|%)$/i;
        var TableWizardCommand = Command.extend({
            exec: function () {
                var cmd = this;
                var editor = cmd.editor;
                var range = cmd.range = cmd.lockRange();
                var selectedTable = cmd._sourceTable = !cmd.options.insertNewTable ? cmd._selectedTable(range) : undefined;
                var selectedCells = cmd._selectedTableCells = selectedTable ? cmd._selectedCells(range) : undefined;
                var options = {
                    visible: false,
                    messages: editor.options.messages,
                    closeCallback: $.proxy(cmd.onDialogClose, cmd),
                    table: cmd.parseTable(selectedTable, selectedCells),
                    dialogOptions: editor.options.dialogOptions,
                    isRtl: kendo.support.isRtl(editor.wrapper)
                };
                var dialog = new Editor.TableWizardDialog(options);
                dialog.open();
            },
            onDialogClose: function (data) {
                var cmd = this;
                cmd.releaseRange(cmd.range);
                if (data) {
                    if (cmd.options.insertNewTable) {
                        cmd.insertTable(cmd.createNewTable(data));
                    } else {
                        cmd.updateTable(data, cmd._sourceTable, cmd._selectedTableCells);
                    }
                }
            },
            releaseRange: function (range) {
                var cmd = this;
                var doc = cmd.editor.document;
                dom.windowFromDocument(doc).focus();
                Command.fn.releaseRange.call(cmd, range);
            },
            insertTable: function (table) {
                var range = this.range;
                range.insertNode(table);
                range.collapse(true);
                this.editor.selectRange(range);
            },
            updateTable: function (data, table, selectedCells) {
                var cmd = this;
                var tableRows = $(table.rows).toArray();
                var tableProp = data.tableProperties;
                var rows = tableProp.rows;
                var columns = tableProp.columns;
                var last = function (collection) {
                    return collection[collection.length - 1];
                };
                while (selectedCells.length > 1) {
                    selectedCells.pop();
                }
                var lastSelectedRow = selectedCells.length ? last(selectedCells).parentNode : last(tableRows);
                var row, parent;
                cmd._deleteTableRows(tableRows, tableRows.length - rows);
                if (tableRows.length < rows) {
                    var rowIndex = $(lastSelectedRow).index();
                    var cellsLength = lastSelectedRow.cells.length;
                    var newRowsCount = rows - tableRows.length;
                    parent = lastSelectedRow.parentNode;
                    while (newRowsCount) {
                        row = parent.insertRow(rowIndex + 1);
                        cmd._insertCells(cellsLength - row.cells.length, row);
                        newRowsCount--;
                    }
                }
                if (tableRows[0].cells.length > columns) {
                    $(tableRows).each(function (i, row) {
                        while (row.cells.length > columns) {
                            row.deleteCell(-1);
                        }
                    });
                }
                if (tableRows[0].cells.length < columns) {
                    var cellIndex = $(last(selectedCells) || last(lastSelectedRow.cells)).index();
                    $(tableRows).each(function (i, row) {
                        cmd._insertCells(columns - row.cells.length, row, cellIndex + 1);
                    });
                }
                cmd._updateTableProperties(table, tableProp);
                var cellProp = data.cellProperties;
                if (selectedCells[0]) {
                    dom.attr(selectedCells[0], { id: cellProp.id || null });
                }
                (cellProp.selectAllCells ? $(tableRows).children() : $(selectedCells)).each(function (i, cell) {
                    cmd._updateCellProperties(cell, cellProp);
                });
                cmd._updateCaption(table, tableProp);
                tableProp.cellsWithHeaders = tableProp.cellsWithHeaders || false;
                if (cmd.cellsWithHeadersAssociated(table) != tableProp.cellsWithHeaders) {
                    cmd.associateCellsWithHeader(table, tableProp.cellsWithHeaders);
                }
            },
            _isHeadingRow: function (row) {
                return dom.is(row.parentNode, 'thead') || dom.is(row.cells[0], 'th');
            },
            associateCellsWithHeader: function (table, associate) {
                var timestamp = new Date().getTime();
                var ids = [];
                var columns = table.rows[0].cells.length;
                var index, nextRow, isDataRow;
                var generateIds = function () {
                    for (var i = 0; i < columns; i++) {
                        ids[i] = 'table' + ++timestamp;
                    }
                };
                var modifySellsIds = function (c, cell) {
                    $(cell)[associate ? 'attr' : 'removeAttr']('id', ids[c]);
                };
                var modifyCellsHeadings = function (c, cell) {
                    $(cell)[associate ? 'attr' : 'removeAttr']('headers', ids[c]);
                };
                var isHeadingRow = this._isHeadingRow;
                $(table.rows).each(function (r, row) {
                    if (isHeadingRow(row)) {
                        index = r;
                        nextRow = table.rows[++index];
                        isDataRow = nextRow && !isHeadingRow(nextRow);
                        if (isDataRow) {
                            generateIds();
                            $(row.cells).each(modifySellsIds);
                        }
                        while (isDataRow) {
                            $(nextRow.cells).each(modifyCellsHeadings);
                            nextRow = table.rows[++index];
                            isDataRow = nextRow && !isHeadingRow(nextRow);
                        }
                    }
                });
            },
            cellsWithHeadersAssociated: function (table) {
                var cells = $(table.rows).children();
                var isHeadingRow = this._isHeadingRow;
                var headingIds = [];
                cells.each(function (c, cell) {
                    if (cell.id && isHeadingRow(cell.parentNode)) {
                        headingIds.push(cell.id);
                    }
                });
                var associatedCells = cells.filter(function (c, cell) {
                    var headersAttr = cell.getAttribute('headers');
                    return headersAttr && !isHeadingRow(cell.parentNode) && $.inArray(headersAttr, headingIds) > -1;
                });
                return !!associatedCells.length;
            },
            _insertCells: function (count, row, index) {
                index = isNaN(index) ? -1 : index;
                for (var i = 0, cell; i < count; i++) {
                    cell = row.insertCell(index);
                    cell.innerHTML = '&nbsp;';
                }
            },
            _deleteTableRows: function (rows, count) {
                for (var i = 0, row, rowParent; i < count; i++) {
                    row = rows.pop();
                    rowParent = row.parentNode;
                    rowParent.removeChild(row);
                    if (!rowParent.rows.length) {
                        dom.remove(rowParent);
                    }
                }
            },
            createNewTable: function (data) {
                var cmd = this;
                var doc = cmd.editor.document;
                var tableProp = data.tableProperties;
                var cellProp = data.cellProperties;
                var cellPropToAll = cellProp.selectAllCells;
                var table = dom.create(doc, 'table');
                cmd._updateTableProperties(table, tableProp);
                cmd._updateCaption(table, tableProp);
                var tbody = table.createTBody();
                for (var r = 0, row; r < tableProp.rows; r++) {
                    row = tbody.insertRow();
                    for (var c = 0, cell; c < tableProp.columns; c++) {
                        cell = row.insertCell();
                        cell.innerHTML = '&nbsp;';
                        if (r === 0 && c === 0 && cellProp.id) {
                            cell.id = cellProp.id;
                        }
                        cmd._updateCellProperties(cell, cellPropToAll || r === 0 && c === 0 ? cellProp : {});
                    }
                }
                if (tableProp.cellsWithHeaders) {
                    cmd.associateCellsWithHeader(table, tableProp.cellsWithHeaders);
                }
                return table;
            },
            _updateTableProperties: function (table, data) {
                var style = this._getStylesData(data);
                dom.attr(table, {
                    cellSpacing: data.cellSpacing || null,
                    cellPadding: data.cellPadding || null,
                    className: data.className || null,
                    id: data.id || null,
                    summary: data.summary || null,
                    style: style || null
                });
                $(table).addClass('k-table');
            },
            _updateCellProperties: function (cell, data) {
                var style = this._getStylesData(data);
                style.padding = data.cellPadding || null;
                style.margin = data.cellMargin || null;
                dom.attr(cell, {
                    style: style || null,
                    className: data.className || null
                });
            },
            _updateCaption: function (table, data) {
                if (table.caption && !data.captionContent) {
                    table.deleteCaption();
                } else if (data.captionContent) {
                    var caption = table.createCaption();
                    caption.innerHTML = data.captionContent;
                    var alignment = this._getAlignmentData(data.captionAlignment);
                    dom.attr(caption, {
                        style: {
                            textAlign: alignment.textAlign,
                            verticalAlign: alignment.verticalAlign
                        }
                    });
                }
            },
            _getStylesData: function (data) {
                var alignment = this._getAlignmentData(data.alignment);
                var whiteSpace = 'wrapText' in data ? data.wrapText ? '' : 'nowrap' : null;
                return {
                    width: data.width ? data.width + data.widthUnit : null,
                    height: data.height ? data.height + data.heightUnit : null,
                    textAlign: alignment.textAlign,
                    verticalAlign: alignment.verticalAlign,
                    backgroundColor: data.bgColor || null,
                    borderWidth: data.borderWidth,
                    borderStyle: data.borderStyle,
                    borderColor: data.borderColor,
                    borderCollapse: data.collapseBorders ? 'collapse' : null,
                    whiteSpace: whiteSpace
                };
            },
            _getAlignmentData: function (alignment) {
                var textAlign = '';
                var verticalAlign = textAlign;
                if (alignment) {
                    if (alignment.indexOf(' ') != -1) {
                        var align = alignment.split(' ');
                        textAlign = align[0];
                        verticalAlign = align[1];
                    } else {
                        textAlign = alignment;
                    }
                }
                return {
                    textAlign: textAlign,
                    verticalAlign: verticalAlign
                };
            },
            parseTable: function (table, selectedCells) {
                if (!table) {
                    return {
                        tableProperties: {},
                        selectedCells: []
                    };
                }
                var cmd = this;
                var tStyle = table.style;
                var rows = table.rows;
                var caption = table.caption;
                var captionClone = $(caption ? caption.cloneNode(true) : undefined);
                captionClone.find('.k-marker').remove();
                var cssClass = table.className;
                cssClass = cssClass.replace(/^k-table\s|\sk-table$/, '');
                cssClass = cssClass.replace(/\sk-table\s/, ' ');
                cssClass = cssClass.replace(/^k-table$/, '');
                var tableAlignment = cmd._getAlignment(table, true);
                var captionAlignment = caption ? cmd._getAlignment(caption) : undefined;
                var cellsWithHeaders = cmd.cellsWithHeadersAssociated(table);
                var tableJson = {
                    tableProperties: {
                        width: tStyle.width || table.width ? parseFloat(tStyle.width || table.width) : null,
                        height: tStyle.height || table.height ? parseFloat(tStyle.height || table.height) : null,
                        columns: rows[0] ? rows[0].children.length : 0,
                        rows: rows.length,
                        widthUnit: cmd._getUnit(tStyle.width),
                        heightUnit: cmd._getUnit(tStyle.height),
                        cellSpacing: table.cellSpacing,
                        cellPadding: table.cellPadding,
                        alignment: tableAlignment.textAlign,
                        bgColor: tStyle.backgroundColor || table.bgColor,
                        className: cssClass,
                        id: table.id,
                        borderWidth: tStyle.borderWidth || table.border,
                        borderColor: tStyle.borderColor,
                        borderStyle: tStyle.borderStyle || '',
                        collapseBorders: !!tStyle.borderCollapse,
                        summary: table.summary,
                        captionContent: caption ? captionClone.html() : '',
                        captionAlignment: caption && captionAlignment.textAlign ? captionAlignment.textAlign + ' ' + captionAlignment.verticalAlign : '',
                        cellsWithHeaders: cellsWithHeaders
                    },
                    selectedCells: []
                };
                tableJson.rows = cmd.parseTableRows(rows, selectedCells, tableJson);
                return tableJson;
            },
            parseTableRows: function (rows, selectedCells, tableJson) {
                var cmd = this;
                var data = [], row, rowData, cells, cell, cellData;
                for (var i = 0; i < rows.length; i++) {
                    row = rows[i];
                    rowData = { cells: [] };
                    cells = row.cells;
                    data.push(rowData);
                    for (var j = 0; j < cells.length; j++) {
                        cell = cells[j];
                        cellData = cmd.parseCell(cell);
                        if ($.inArray(cell, selectedCells) != -1) {
                            tableJson.selectedCells.push(cellData);
                        }
                        rowData.cells.push(cellData);
                    }
                }
                return data;
            },
            parseCell: function (cell) {
                var cmd = this;
                var cStyle = cell.style;
                var alignment = cmd._getAlignment(cell);
                alignment = alignment.textAlign ? alignment.textAlign + ' ' + alignment.verticalAlign : '';
                var data = {
                    width: cStyle.width || cell.width ? parseFloat(cStyle.width || cell.width) : null,
                    height: cStyle.height || cell.height ? parseFloat(cStyle.height || cell.height) : null,
                    widthUnit: cmd._getUnit(cStyle.width),
                    heightUnit: cmd._getUnit(cStyle.height),
                    cellMargin: cStyle.margin,
                    cellPadding: cStyle.padding,
                    alignment: alignment,
                    bgColor: cStyle.backgroundColor || cell.bgColor,
                    className: cell.className,
                    id: cell.id,
                    borderWidth: cStyle.borderWidth || cell.border,
                    borderColor: cStyle.borderColor,
                    borderStyle: cStyle.borderStyle,
                    wrapText: cStyle.whiteSpace != 'nowrap'
                };
                return data;
            },
            _getAlignment: function (element, horizontalOnly) {
                var style = element.style;
                var hAlign = style.textAlign || element.align || '';
                if (horizontalOnly) {
                    return { textAlign: hAlign };
                }
                var vAlign = style.verticalAlign || element.vAlign || '';
                if (hAlign && vAlign) {
                    return {
                        textAlign: hAlign,
                        verticalAlign: vAlign
                    };
                }
                if (!hAlign && vAlign) {
                    return {
                        textAlign: 'left',
                        verticalAlign: vAlign
                    };
                }
                if (hAlign && !vAlign) {
                    return {
                        textAlign: hAlign,
                        verticalAlign: 'top'
                    };
                }
                return {
                    textAlign: '',
                    verticalAlign: ''
                };
            },
            _getUnit: function (value) {
                var unit = (value || '').match(reUnit);
                return unit ? unit[0] : 'px';
            },
            _selectedTable: function (range) {
                var nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
                return tableFormatFinder.findSuitable(nodes)[0];
            },
            _selectedCells: function (range) {
                var nodes = dom.filterBy(RangeUtils.nodes(range), dom.htmlIndentSpace, true);
                return cellsFormatFinder.findSuitable(nodes);
            }
        });
        var TableWizardTool = Editor.Tool.extend({
            command: function (options) {
                options.insertNewTable = this.options.insertNewTable;
                return new TableWizardCommand(options);
            }
        });
        var TableWizardEditTool = TableWizardTool.extend({
            update: function (ui, nodes) {
                var isFormatted = !tableFormatFinder.isFormatted(nodes);
                ui.toggleClass('k-state-disabled', isFormatted);
            }
        });
        kendo.ui.editor.TableWizardTool = TableWizardTool;
        kendo.ui.editor.TableWizardCommand = TableWizardCommand;
        registerTool('tableWizard', new TableWizardEditTool({
            command: TableWizardCommand,
            insertNewTable: false,
            template: new ToolTemplate({
                template: EditorUtils.buttonTemplate,
                title: 'Table Wizard'
            })
        }));
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('editor/table-wizard/table-wizard-dialog', ['editor/table-wizard/table-wizard-command'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, numericTextBoxSettings = {
                format: '0',
                min: 0
            }, units = [
                'px',
                'em'
            ], borderStyles = [
                'solid',
                'dotted',
                'dashed',
                'double',
                'groove',
                'ridge',
                'inset',
                'outset',
                'initial',
                'inherit',
                'none',
                'hidden'
            ];
        var tableAlignmentDropDownSettings = {
            dataSource: [
                {
                    className: 'k-icon k-i-table-align-middle-left',
                    value: 'left'
                },
                {
                    className: 'k-icon k-i-table-align-middle-center',
                    value: 'center'
                },
                {
                    className: 'k-icon k-i-table-align-middle-right',
                    value: 'right'
                },
                {
                    className: 'k-icon k-i-align-remove',
                    value: ''
                }
            ],
            dataTextField: 'className',
            dataValueField: 'value',
            template: '<span class=\'#: className #\' title=\'#: tooltip #\'></span>',
            valueTemplate: '<span class=\'k-align-group #: className #\' title=\'#: tooltip #\'></span>'
        };
        var cellAlignmentDropDownSettings = {
            dataSource: [
                {
                    className: 'k-icon k-i-table-align-top-left',
                    value: 'left top'
                },
                {
                    className: 'k-icon k-i-table-align-top-center',
                    value: 'center top'
                },
                {
                    className: 'k-icon k-i-table-align-top-right',
                    value: 'right top'
                },
                {
                    className: 'k-icon k-i-table-align-middle-left',
                    value: 'left middle'
                },
                {
                    className: 'k-icon k-i-table-align-middle-center',
                    value: 'center middle'
                },
                {
                    className: 'k-icon k-i-table-align-middle-right',
                    value: 'right middle'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-left',
                    value: 'left bottom'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-center',
                    value: 'center bottom'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-right',
                    value: 'right bottom'
                },
                {
                    className: 'k-icon k-i-align-remove',
                    value: ''
                }
            ],
            dataTextField: 'className',
            dataValueField: 'value',
            template: '<span class=\'#: className #\' title=\'#: tooltip #\'></span>',
            valueTemplate: '<span class=\'k-align-group #: className #\' title=\'#: tooltip #\'></span>'
        };
        var accessibilityAlignmentDropDownSettings = {
            dataSource: [
                {
                    className: 'k-icon k-i-table-align-top-left',
                    value: 'left top'
                },
                {
                    className: 'k-icon k-i-table-align-top-center',
                    value: 'center top'
                },
                {
                    className: 'k-icon k-i-table-align-top-right',
                    value: 'right top'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-left',
                    value: 'left bottom'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-center',
                    value: 'center bottom'
                },
                {
                    className: 'k-icon k-i-table-align-bottom-right',
                    value: 'right bottom'
                },
                {
                    className: 'k-icon k-i-align-remove',
                    value: ''
                }
            ],
            dataTextField: 'className',
            dataValueField: 'value',
            template: '<span class=\'#: className #\' title=\'#: tooltip #\'></span>',
            valueTemplate: '<span class=\'k-align-group #: className #\' title=\'#: tooltip #\'></span>'
        };
        var dialogTemplate = '<div class="k-editor-dialog k-editor-table-wizard-dialog k-action-window k-popup-edit-form">' + '<div class="k-edit-form-container">' + '<div id="k-table-wizard-tabs" class="k-root-tabs">' + '<ul>' + '<li class="k-state-active">#= messages.tableTab #</li>' + '<li>#= messages.cellTab #</li>' + '<li>#= messages.accessibilityTab #</li>' + '</ul>' + '<div id="k-table-properties">' + '<div class="k-edit-label">' + '<label for="k-editor-table-width">#= messages.width #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-width" />' + '<input id="k-editor-table-width-type" aria-label="#= messages.units #" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-height">#= messages.height #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-height" />' + '<input id="k-editor-table-height-type" aria-label="#= messages.units #" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-columns">#= messages.columns #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-columns" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-rows">#= messages.rows #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-rows" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-cell-spacing">#= messages.cellSpacing #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-cell-spacing" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-cell-padding">#= messages.cellPadding #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-cell-padding" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-alignment">#= messages.alignment #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-table-alignment" class="k-align" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-bg">#= messages.background #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-table-bg" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-css-class">#= messages.cssClass #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-css-class" class="k-input k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-id">#= messages.id #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-id" class="k-input k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-border-width">#= messages.border #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-border-width" />' + '<input id="k-editor-border-color" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-border-style">#= messages.borderStyle #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-border-style" />' + '</div>' + '<div class="k-edit-label">&nbsp;</div>' + '<div class="k-edit-field">' + '<input id="k-editor-collapse-borders" type="checkbox" class="k-checkbox" />' + '<label for="k-editor-collapse-borders" class="k-checkbox-label">#= messages.collapseBorders #</label>' + '</div>' + '</div>' + '<div id="k-cell-properties">' + '<div class="k-edit-field">' + '<input id="k-editor-selectAllCells" type="checkbox" class="k-checkbox" />' + '<label for="k-editor-selectAllCells" class="k-checkbox-label">#= messages.selectAllCells #</label>' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-width">#= messages.width #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-cell-width" />' + '<input id="k-editor-cell-width-type" aria-label="#= messages.units #" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-height">#= messages.height #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-cell-height" />' + '<input id="k-editor-cell-height-type" aria-label="#= messages.units #" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-cell-margin">#= messages.cellMargin #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-cell-margin" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-table-cells-padding">#= messages.cellPadding #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-table-cells-padding" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-alignment">#= messages.alignment #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-alignment" class="k-align" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-bg">#= messages.background #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-bg" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-css-class">#= messages.cssClass #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-css-class" class="k-input k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-id">#= messages.id #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-id" class="k-input k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-border-width">#= messages.border #</label>' + '</div>' + '<div class="k-edit-field">' + '<input type="numeric" id="k-editor-cell-border-width" />' + '<input id="k-editor-cell-border-color" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-cell-border-style">#= messages.borderStyle #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cell-border-style" />' + '</div>' + '<div class="k-edit-label">&nbsp;</div>' + '<div class="k-edit-field">' + '<input id="k-editor-wrap-text" type="checkbox" class="k-checkbox" />' + '<label for="k-editor-wrap-text" class="k-checkbox-label">#= messages.wrapText #</label>' + '</div>' + '</div>' + '<div id="k-accessibility-properties">' + '<div class="k-edit-label">' + '<label for="k-editor-table-caption">#= messages.caption #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-table-caption" class="k-input k-textbox" type="text" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-accessibility-alignment">#= messages.alignment #</label>' + '</div>' + '<div class="k-edit-field">' + '<input id="k-editor-accessibility-alignment" class="k-align" />' + '</div>' + '<div class="k-edit-label">' + '<label for="k-editor-accessibility-summary">#= messages.summary #</label>' + '</div>' + '<div class="k-edit-field">' + '<textarea id="k-editor-accessibility-summary" class="k-input k-textbox"></textarea>' + '</div>' + '<div class="k-edit-label">&nbsp;</div>' + '<div class="k-edit-field">' + '<input id="k-editor-cells-headers" type="checkbox" class="k-checkbox" />' + '<label for="k-editor-cells-headers" class="k-checkbox-label">#= messages.associateCellsWithHeaders #</label>' + '</div>' + '</div>' + '</div>' + '<div class="k-edit-buttons k-state-default">' + '<button class="k-button k-primary k-dialog-ok">#= messages.dialogOk #</button>' + '<button class="k-button k-dialog-close">#= messages.dialogCancel #</button>' + '</div>' + '</div>' + '</div>';
        var TableWizardDialog = kendo.Class.extend({
            init: function (options) {
                this.options = options;
            },
            open: function () {
                var that = this, options = that.options, dialogOptions = options.dialogOptions, tableData = options.table, dialog, messages = options.messages;
                function close(e) {
                    e.preventDefault();
                    that.destroy();
                    dialog.destroy();
                }
                function okHandler(e) {
                    that.collectDialogValues(tableData);
                    close(e);
                    if (that.change) {
                        that.change();
                    }
                    options.closeCallback(tableData);
                }
                function closeHandler(e) {
                    close(e);
                    options.closeCallback();
                }
                dialogOptions.close = closeHandler;
                dialogOptions.title = messages.tableWizard;
                dialogOptions.visible = options.visible;
                dialog = $(that._dialogTemplate(messages)).appendTo(document.body).kendoWindow(dialogOptions).closest('.k-window').toggleClass('k-rtl', options.isRtl).end().find('.k-dialog-ok').click(okHandler).end().find('.k-dialog-close').click(closeHandler).end().data('kendoWindow');
                var element = dialog.element;
                that._initTabStripComponent(element);
                that._initTableViewComponents(element, tableData);
                that._initCellViewComponents(element, tableData);
                that._initAccessibilityViewComponents(element, tableData);
                dialog.center();
                dialog.open();
            },
            _initTabStripComponent: function (element) {
                var components = this.components = {};
                components.tabStrip = element.find('#k-table-wizard-tabs').kendoTabStrip({ animation: false }).data('kendoTabStrip');
            },
            collectDialogValues: function () {
                var that = this;
                var data = that.options.table;
                that._collectTableViewValues(data);
                that._collectCellViewValues(data);
                that._collectAccessibilityViewValues(data);
            },
            _collectTableViewValues: function (tableData) {
                var tableView = this.components.tableView;
                var tableProperties = tableData.tableProperties;
                tableProperties.width = tableView.width.value();
                tableProperties.widthUnit = tableView.widthUnit.value();
                tableProperties.height = tableView.height.value();
                tableProperties.columns = tableView.columns.value();
                tableProperties.rows = tableView.rows.value();
                tableProperties.heightUnit = tableView.heightUnit.value();
                tableProperties.cellSpacing = tableView.cellSpacing.value();
                tableProperties.cellPadding = tableView.cellPadding.value();
                tableProperties.alignment = tableView.alignment.value();
                tableProperties.bgColor = tableView.bgColor.value();
                tableProperties.className = tableView.className.value;
                tableProperties.id = tableView.id.value;
                tableProperties.borderWidth = tableView.borderWidth.value();
                tableProperties.borderColor = tableView.borderColor.value();
                tableProperties.borderStyle = tableView.borderStyle.value();
                tableProperties.collapseBorders = tableView.collapseBorders.checked;
            },
            _collectCellViewValues: function (table) {
                var cellData = table.cellProperties = {};
                var cellView = this.components.cellView;
                cellData.selectAllCells = cellView.selectAllCells.checked;
                cellData.width = cellView.width.value();
                cellData.widthUnit = cellView.widthUnit.value();
                cellData.height = cellView.height.value();
                cellData.heightUnit = cellView.heightUnit.value();
                cellData.cellMargin = cellView.cellMargin.value();
                cellData.cellPadding = cellView.cellPadding.value();
                cellData.alignment = cellView.alignment.value();
                cellData.bgColor = cellView.bgColor.value();
                cellData.className = cellView.className.value;
                cellData.id = cellView.id.value;
                cellData.borderWidth = cellView.borderWidth.value();
                cellData.borderColor = cellView.borderColor.value();
                cellData.borderStyle = cellView.borderStyle.value();
                cellData.wrapText = cellView.wrapText.checked;
            },
            _collectAccessibilityViewValues: function (table) {
                var tableProperties = table.tableProperties;
                var accessibilityView = this.components.accessibilityView;
                tableProperties.captionContent = accessibilityView.captionContent.value;
                tableProperties.captionAlignment = accessibilityView.captionAlignment.value();
                tableProperties.summary = accessibilityView.summary.value;
                tableProperties.cellsWithHeaders = accessibilityView.cellsWithHeaders.checked;
            },
            _addUnit: function (units, value) {
                if (value && $.inArray(value, units) == -1) {
                    units.push(value);
                }
            },
            _initTableViewComponents: function (element, table) {
                var components = this.components;
                var tableView = components.tableView = {};
                var tableProperties = table.tableProperties = table.tableProperties || {};
                tableProperties.borderStyle = tableProperties.borderStyle || '';
                this._addUnit(units, tableProperties.widthUnit);
                this._addUnit(units, tableProperties.heightUnit);
                this._initNumericTextbox(element.find('#k-editor-table-width'), 'width', tableProperties, tableView);
                this._initNumericTextbox(element.find('#k-editor-table-height'), 'height', tableProperties, tableView);
                this._initNumericTextbox(element.find('#k-editor-table-columns'), 'columns', tableProperties, tableView, {
                    min: 1,
                    value: 4
                });
                this._initNumericTextbox(element.find('#k-editor-table-rows'), 'rows', tableProperties, tableView, {
                    min: 1,
                    value: 4
                });
                this._initDropDownList(element.find('#k-editor-table-width-type'), 'widthUnit', tableProperties, tableView, units);
                this._initDropDownList(element.find('#k-editor-table-height-type'), 'heightUnit', tableProperties, tableView, units);
                this._initNumericTextbox(element.find('#k-editor-table-cell-spacing'), 'cellSpacing', tableProperties, tableView);
                this._initNumericTextbox(element.find('#k-editor-table-cell-padding'), 'cellPadding', tableProperties, tableView);
                this._initTableAlignmentDropDown(element.find('#k-editor-table-alignment'), tableProperties);
                this._initColorPicker(element.find('#k-editor-table-bg'), 'bgColor', tableProperties, tableView);
                this._initInput(element.find('#k-editor-css-class'), 'className', tableProperties, tableView);
                this._initInput(element.find('#k-editor-id'), 'id', tableProperties, tableView);
                this._initNumericTextbox(element.find('#k-editor-border-width'), 'borderWidth', tableProperties, tableView);
                this._initColorPicker(element.find('#k-editor-border-color'), 'borderColor', tableProperties, tableView);
                this._initDropDownList(element.find('#k-editor-border-style'), 'borderStyle', tableProperties, tableView, borderStyles);
                this._initCheckbox(element.find('#k-editor-collapse-borders'), 'collapseBorders', tableProperties, tableView);
            },
            _initCellViewComponents: function (element, table) {
                var components = this.components;
                var cellView = components.cellView = {};
                table.selectedCells = table.selectedCells = table.selectedCells || [];
                var cellProperties = table.selectedCells[0] || {
                    borderStyle: '',
                    wrapText: true
                };
                this._addUnit(units, cellProperties.widthUnit);
                this._addUnit(units, cellProperties.heightUnit);
                this._initCheckbox(element.find('#k-editor-selectAllCells'), 'selectAllCells', table.tableProperties, cellView);
                this._initNumericTextbox(element.find('#k-editor-cell-width'), 'width', cellProperties, cellView);
                this._initNumericTextbox(element.find('#k-editor-cell-height'), 'height', cellProperties, cellView);
                this._initDropDownList(element.find('#k-editor-cell-width-type'), 'widthUnit', cellProperties, cellView, units);
                this._initDropDownList(element.find('#k-editor-cell-height-type'), 'heightUnit', cellProperties, cellView, units);
                this._initNumericTextbox(element.find('#k-editor-table-cell-margin'), 'cellMargin', cellProperties, cellView);
                this._initNumericTextbox(element.find('#k-editor-table-cells-padding'), 'cellPadding', cellProperties, cellView);
                this._initCellAlignmentDropDown(element.find('#k-editor-cell-alignment'), cellProperties);
                this._initColorPicker(element.find('#k-editor-cell-bg'), 'bgColor', cellProperties, cellView);
                this._initInput(element.find('#k-editor-cell-css-class'), 'className', cellProperties, cellView);
                this._initInput(element.find('#k-editor-cell-id'), 'id', cellProperties, cellView);
                this._initNumericTextbox(element.find('#k-editor-cell-border-width'), 'borderWidth', cellProperties, cellView);
                this._initColorPicker(element.find('#k-editor-cell-border-color'), 'borderColor', cellProperties, cellView);
                this._initDropDownList(element.find('#k-editor-cell-border-style'), 'borderStyle', cellProperties, cellView, borderStyles);
                this._initCheckbox(element.find('#k-editor-wrap-text'), 'wrapText', cellProperties, cellView);
            },
            _initAccessibilityViewComponents: function (element, table) {
                var components = this.components;
                var accessibilityView = components.accessibilityView = {};
                var tableProperties = table.tableProperties;
                this._initInput(element.find('#k-editor-table-caption'), 'captionContent', tableProperties, accessibilityView);
                this._initAccessibilityAlignmentDropDown(element.find('#k-editor-accessibility-alignment'), tableProperties);
                this._initInput(element.find('#k-editor-accessibility-summary'), 'summary', tableProperties, accessibilityView);
                this._initCheckbox(element.find('#k-editor-cells-headers'), 'cellsWithHeaders', tableProperties, accessibilityView);
            },
            _initNumericTextbox: function (element, property, data, storage, settings) {
                var component = storage[property] = element.kendoNumericTextBox(settings ? $.extend({}, numericTextBoxSettings, settings) : numericTextBoxSettings).data('kendoNumericTextBox');
                if (property in data) {
                    component.value(parseInt(data[property], 10));
                }
            },
            _initDropDownList: function (element, property, data, storage, dataSource) {
                var component = storage[property] = element.kendoDropDownList({ dataSource: dataSource }).data('kendoDropDownList');
                this._setComponentValue(component, data, property);
            },
            _initTableAlignmentDropDown: function (element, data) {
                var messages = this.options.messages;
                var tableView = this.components.tableView;
                var dataSource = tableAlignmentDropDownSettings.dataSource;
                dataSource[0].tooltip = messages.alignLeft;
                dataSource[1].tooltip = messages.alignCenter;
                dataSource[2].tooltip = messages.alignRight;
                dataSource[3].tooltip = messages.alignRemove;
                this._initAlignmentDropDown(element, tableAlignmentDropDownSettings, 'alignment', data, tableView);
            },
            _initCellAlignmentDropDown: function (element, data) {
                var messages = this.options.messages;
                var cellView = this.components.cellView;
                var dataSource = cellAlignmentDropDownSettings.dataSource;
                dataSource[0].tooltip = messages.alignLeftTop;
                dataSource[1].tooltip = messages.alignCenterTop;
                dataSource[2].tooltip = messages.alignRightTop;
                dataSource[3].tooltip = messages.alignLeftMiddle;
                dataSource[4].tooltip = messages.alignCenterMiddle;
                dataSource[5].tooltip = messages.alignRightMiddle;
                dataSource[6].tooltip = messages.alignLeftBottom;
                dataSource[7].tooltip = messages.alignCenterBottom;
                dataSource[8].tooltip = messages.alignRightBottom;
                dataSource[9].tooltip = messages.alignRemove;
                this._initAlignmentDropDown(element, cellAlignmentDropDownSettings, 'alignment', data, cellView);
            },
            _initAccessibilityAlignmentDropDown: function (element, data) {
                var messages = this.options.messages;
                var accessibilityView = this.components.accessibilityView;
                var dataSource = accessibilityAlignmentDropDownSettings.dataSource;
                dataSource[0].tooltip = messages.alignLeftTop;
                dataSource[1].tooltip = messages.alignCenterTop;
                dataSource[2].tooltip = messages.alignRightTop;
                dataSource[3].tooltip = messages.alignLeftBottom;
                dataSource[4].tooltip = messages.alignCenterBottom;
                dataSource[5].tooltip = messages.alignRightBottom;
                dataSource[6].tooltip = messages.alignRemove;
                this._initAlignmentDropDown(element, accessibilityAlignmentDropDownSettings, 'captionAlignment', data, accessibilityView);
            },
            _initAlignmentDropDown: function (element, settings, name, data, storage) {
                var component = storage[name] = element.kendoDropDownList(settings).data('kendoDropDownList');
                component.list.addClass('k-align').css('width', '110px');
                this._setComponentValue(component, data, name);
            },
            _setComponentValue: function (component, data, property) {
                if (property in data) {
                    component.value(data[property]);
                }
            },
            _initColorPicker: function (element, property, data, storage) {
                var component = storage[property] = element.kendoColorPicker({
                    buttons: false,
                    clearButton: true
                }).data('kendoColorPicker');
                if (data[property]) {
                    component.value(data[property]);
                }
            },
            _initInput: function (element, property, data, storage) {
                var component = storage[property] = element.get(0);
                if (property in data) {
                    component.value = data[property];
                }
            },
            _initCheckbox: function (element, property, data, storage) {
                var component = storage[property] = element.get(0);
                if (property in data) {
                    component.checked = data[property];
                }
            },
            destroy: function () {
                this._destroyComponents(this.components.tableView);
                this._destroyComponents(this.components.cellView);
                this._destroyComponents(this.components.accessibilityView);
                this._destroyComponents(this.components);
                delete this.components;
            },
            _destroyComponents: function (components) {
                for (var widget in components) {
                    if (components[widget].destroy) {
                        components[widget].destroy();
                    }
                    delete components[widget];
                }
            },
            _dialogTemplate: function (messages) {
                return kendo.template(dialogTemplate)({ messages: messages });
            }
        });
        kendo.ui.editor.TableWizardDialog = TableWizardDialog;
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.editor', [
        'kendo.combobox',
        'kendo.dropdownlist',
        'kendo.resizable',
        'kendo.window',
        'kendo.colorpicker',
        'kendo.imagebrowser',
        'kendo.tabstrip',
        'kendo.numerictextbox',
        'util/undoredostack',
        'editor/main',
        'editor/dom',
        'editor/serializer',
        'editor/range',
        'editor/system',
        'editor/inlineformat',
        'editor/formatblock',
        'editor/linebreak',
        'editor/lists',
        'editor/link',
        'editor/file',
        'editor/image',
        'editor/components',
        'editor/indent',
        'editor/viewhtml',
        'editor/formatting',
        'editor/toolbar',
        'editor/tables',
        'editor/export',
        'editor/import',
        'editor/resizing/column-resizing',
        'editor/resizing/row-resizing',
        'editor/resizing/table-resizing',
        'editor/resizing/table-resize-handle',
        'editor/immutables',
        'editor/table-wizard/table-wizard-command',
        'editor/table-wizard/table-wizard-dialog'
    ], f);
}(function () {
    var __meta__ = {
        id: 'editor',
        name: 'Editor',
        category: 'web',
        description: 'Rich text editor component',
        depends: [
            'combobox',
            'dropdownlist',
            'window',
            'colorpicker'
        ],
        features: [
            {
                id: 'editor-imagebrowser',
                name: 'Image Browser',
                description: 'Support for uploading and inserting images',
                depends: ['imagebrowser']
            },
            {
                id: 'editor-resizable',
                name: 'Resize handle',
                description: 'Support for resizing the content area via a resize handle',
                depends: ['resizable']
            },
            {
                id: 'editor-tablewizard',
                name: 'Table wizard dialog',
                description: 'Support for table properties configuration',
                depends: [
                    'tabstrip',
                    'button',
                    'numerictextbox'
                ]
            },
            {
                id: 'editor-pdf-export',
                name: 'PDF export',
                description: 'Export Editor content as PDF',
                depends: [
                    'pdf',
                    'drawing'
                ]
            }
        ]
    };
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.maskedtextbox', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'maskedtextbox',
        name: 'MaskedTextBox',
        category: 'web',
        description: 'The MaskedTextBox widget allows to specify a mask type on an input field.',
        depends: ['core']
    };
    (function ($, undefined) {
        var global = window;
        var min = global.Math.min;
        var kendo = global.kendo;
        var caret = kendo.caret;
        var keys = kendo.keys;
        var ui = kendo.ui;
        var Widget = ui.Widget;
        var NS = '.kendoMaskedTextBox';
        var proxy = $.proxy;
        var setTimeout = window.setTimeout;
        var STATEDISABLED = 'k-state-disabled';
        var STATEINVALID = 'k-state-invalid';
        var DISABLED = 'disabled';
        var READONLY = 'readonly';
        var CHANGE = 'change';
        var MOUSEUP = 'mouseup';
        var DROP = 'drop';
        var KEYDOWN = 'keydown';
        var PASTE = 'paste';
        var INPUT = 'input';
        function ns(name) {
            return name + NS;
        }
        var INPUT_EVENT_NAME = ns(kendo.support.propertyChangeEvent ? 'propertychange' : INPUT);
        function stringDiffStart(str1, str2) {
            var i = 0;
            while (i < str2.length) {
                if (str1[i] !== str2[i]) {
                    break;
                }
                i++;
            }
            return i;
        }
        var MaskedTextBox = Widget.extend({
            init: function (element, options) {
                var that = this;
                var DOMElement;
                Widget.fn.init.call(that, element, options);
                that._rules = $.extend({}, that.rules, that.options.rules);
                element = that.element;
                DOMElement = element[0];
                that._wrapper();
                that._tokenize();
                that._form();
                that.element.addClass('k-textbox').attr('autocomplete', 'off').on('focus' + NS, function () {
                    var value = DOMElement.value;
                    if (!value) {
                        DOMElement.value = that._old = that._emptyMask;
                    } else {
                        that._togglePrompt(true);
                    }
                    that._oldValue = value;
                    that._timeoutId = setTimeout(function () {
                        caret(element, 0, value ? that._maskLength : 0);
                    });
                }).on('focusout' + NS, function () {
                    var value = element.val();
                    clearTimeout(that._timeoutId);
                    DOMElement.value = that._old = '';
                    if (value !== that._emptyMask) {
                        DOMElement.value = that._old = value;
                    }
                    that._change();
                    that._togglePrompt();
                });
                var disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                that.value(that.options.value || element.val());
                that._validationIcon = $('<span class=\'k-icon k-i-warning\'></span>').insertAfter(element);
                kendo.notify(that);
            },
            options: {
                name: 'MaskedTextBox',
                clearPromptChar: false,
                unmaskOnPost: false,
                promptChar: '_',
                culture: '',
                rules: {},
                value: '',
                mask: ''
            },
            events: [CHANGE],
            rules: {
                '0': /\d/,
                '9': /\d|\s/,
                '#': /\d|\s|\+|\-/,
                'L': /[a-zA-Z]/,
                '?': /[a-zA-Z]|\s/,
                '&': /\S/,
                'C': /./,
                'A': /[a-zA-Z0-9]/,
                'a': /[a-zA-Z0-9]|\s/
            },
            setOptions: function (options) {
                var that = this;
                Widget.fn.setOptions.call(that, options);
                that._rules = $.extend({}, that.rules, that.options.rules);
                that._tokenize();
                this._unbindInput();
                this._bindInput();
                that.value(that.element.val());
            },
            destroy: function () {
                var that = this;
                that.element.off(NS);
                if (that._formElement) {
                    that._formElement.off('reset', that._resetHandler);
                    that._formElement.off('submit', that._submitHandler);
                }
                Widget.fn.destroy.call(that);
            },
            raw: function () {
                var unmasked = this._unmask(this.element.val(), 0);
                return unmasked.replace(new RegExp(this.options.promptChar, 'g'), '');
            },
            value: function (value) {
                var element = this.element;
                var emptyMask = this._emptyMask;
                if (value === undefined) {
                    return this.element.val();
                }
                if (value === null) {
                    value = '';
                }
                if (!emptyMask) {
                    this._oldValue = value;
                    element.val(value);
                    return;
                }
                value = this._unmask(value + '');
                element.val(value ? emptyMask : '');
                this._mask(0, this._maskLength, value);
                this._unmaskedValue = null;
                value = element.val();
                this._oldValue = value;
                if (kendo._activeElement() !== element) {
                    if (value === emptyMask) {
                        element.val('');
                    } else {
                        this._togglePrompt();
                    }
                }
            },
            _togglePrompt: function (show) {
                var DOMElement = this.element[0];
                var value = DOMElement.value;
                if (this.options.clearPromptChar) {
                    if (!show) {
                        value = value.replace(new RegExp(this.options.promptChar, 'g'), ' ');
                    } else {
                        value = this._oldValue;
                    }
                    DOMElement.value = this._old = value;
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            _bindInput: function () {
                var that = this;
                if (that._maskLength) {
                    if (that.options.$angular) {
                        that.element.off(INPUT);
                    }
                    that.element.on(ns(KEYDOWN), proxy(that._keydown, that)).on(ns(DROP), proxy(that._drop, that)).on(ns(CHANGE), proxy(that._trackChange, that)).on(INPUT_EVENT_NAME, proxy(that._inputHandler, that));
                    if (kendo.support.browser.msie) {
                        var version = kendo.support.browser.version;
                        if (version > 8 && version < 11) {
                            var events = [
                                ns(MOUSEUP),
                                ns(DROP),
                                ns(KEYDOWN),
                                ns(PASTE)
                            ].join(' ');
                            that.element.on(events, proxy(that._legacyIEInputHandler, that));
                        }
                    }
                }
            },
            _unbindInput: function () {
                var events = [
                    INPUT_EVENT_NAME,
                    ns(KEYDOWN),
                    ns(MOUSEUP),
                    ns(DROP),
                    ns(PASTE)
                ].join(' ');
                this.element.off(events);
            },
            _editable: function (options) {
                var that = this;
                var element = that.element;
                var wrapper = that.wrapper;
                var disable = options.disable;
                var readonly = options.readonly;
                that._unbindInput();
                if (!readonly && !disable) {
                    element.removeAttr(DISABLED).removeAttr(READONLY);
                    wrapper.removeClass(STATEDISABLED);
                    that._bindInput();
                } else {
                    element.attr(DISABLED, disable).attr(READONLY, readonly);
                    wrapper.toggleClass(STATEDISABLED, disable);
                }
            },
            _change: function () {
                var that = this;
                var value = that.value();
                if (value !== that._oldValue) {
                    that._oldValue = value;
                    that.trigger(CHANGE);
                    that.element.trigger(CHANGE);
                } else if (value === '' && that.__changing) {
                    that.element.trigger(CHANGE);
                }
            },
            inputChange: function (backward) {
                var that = this;
                var old = that._old;
                var element = that.element[0];
                var value = element.value;
                var selection = caret(element);
                var cursor = selection[1];
                var lengthDiff = value.length - old.length;
                var mobile = kendo.support.mobileOS;
                if (that.__dropping && lengthDiff < 0) {
                    return;
                }
                if (lengthDiff === -1 && mobile.android && mobile.browser === 'chrome') {
                    backward = true;
                }
                var contentStart = min(cursor, stringDiffStart(value, old));
                var content = value.substring(contentStart, cursor);
                element.value = value.substring(0, contentStart) + that._emptyMask.substring(contentStart);
                var caretPos = that._mask(contentStart, cursor, content);
                var endContent = that._trimStartPromptChars(value.substring(cursor), min(lengthDiff, caretPos - contentStart));
                var unmasked = that._unmask(endContent, old.length - endContent.length);
                that._mask(caretPos, caretPos, unmasked);
                if (backward) {
                    caretPos = that._findCaretPosBackwards(contentStart);
                }
                caret(element, caretPos);
                that.__dropping = false;
            },
            _trimStartPromptChars: function (content, count) {
                var promptChar = this.options.promptChar;
                while (count-- > 0 && content.indexOf(promptChar) === 0) {
                    content = content.substring(1);
                }
                return content;
            },
            _findCaretPosBackwards: function (pos) {
                var caretStart = this._find(pos, true);
                if (caretStart < pos) {
                    caretStart += 1;
                }
                return caretStart;
            },
            _inputHandler: function () {
                if (kendo._activeElement() !== this.element[0]) {
                    return;
                }
                this.inputChange(this.__backward);
            },
            _legacyIEInputHandler: function (e) {
                var that = this;
                var input = that.element[0];
                var value = input.value;
                var type = e.type;
                that.__pasting = type === 'paste';
                setTimeout(function () {
                    if (type === 'mouseup' && that.__pasting) {
                        return;
                    }
                    if (input.value !== value) {
                        that.inputChange(that.__backward);
                    }
                });
            },
            _trackChange: function () {
                var that = this;
                that.__changing = true;
                setTimeout(function () {
                    that.__changing = false;
                });
            },
            _form: function () {
                var that = this;
                var element = that.element;
                var formId = element.attr('form');
                var form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        setTimeout(function () {
                            that.value(element[0].value);
                        });
                    };
                    that._submitHandler = function () {
                        that.element[0].value = that._old = that.raw();
                    };
                    if (that.options.unmaskOnPost) {
                        form.on('submit', that._submitHandler);
                    }
                    that._formElement = form.on('reset', that._resetHandler);
                }
            },
            _keydown: function (e) {
                var key = e.keyCode;
                this.__backward = key === keys.BACKSPACE;
                if (key === keys.ENTER) {
                    this._change();
                }
            },
            _drop: function () {
                this.__dropping = true;
            },
            _find: function (idx, backward) {
                var value = this.element.val() || this._emptyMask;
                var step = 1;
                if (backward === true) {
                    step = -1;
                }
                while (idx > -1 || idx <= this._maskLength) {
                    if (value.charAt(idx) !== this.tokens[idx]) {
                        return idx;
                    }
                    idx += step;
                }
                return -1;
            },
            _mask: function (start, end, value, backward) {
                var element = this.element[0];
                var current = element.value || this._emptyMask;
                var empty = this.options.promptChar;
                var valueLength;
                var chrIdx = 0;
                var unmasked;
                var chr;
                var idx;
                start = this._find(start, backward);
                if (start > end) {
                    end = start;
                }
                unmasked = this._unmask(current.substring(end), end);
                value = this._unmask(value, start);
                valueLength = value.length;
                if (value) {
                    unmasked = unmasked.replace(new RegExp('^_{0,' + valueLength + '}'), '');
                }
                value += unmasked;
                current = current.split('');
                chr = value.charAt(chrIdx);
                while (start < this._maskLength) {
                    current[start] = chr || empty;
                    chr = value.charAt(++chrIdx);
                    if (idx === undefined && chrIdx > valueLength) {
                        idx = start;
                    }
                    start = this._find(start + 1);
                }
                element.value = this._old = current.join('');
                if (kendo._activeElement() === element) {
                    if (idx === undefined) {
                        idx = this._maskLength;
                    }
                    caret(element, idx);
                }
                return idx;
            },
            _unmask: function (value, idx) {
                if (!value) {
                    return '';
                }
                if (this._unmaskedValue === value) {
                    return this._unmaskedValue;
                }
                value = (value + '').split('');
                var chr;
                var token;
                var chrIdx = 0;
                var tokenIdx = idx || 0;
                var empty = this.options.promptChar;
                var valueLength = value.length;
                var tokensLength = this.tokens.length;
                var result = '';
                while (tokenIdx < tokensLength) {
                    chr = value[chrIdx];
                    token = this.tokens[tokenIdx];
                    if (chr === token || chr === empty) {
                        result += chr === empty ? empty : '';
                        chrIdx += 1;
                        tokenIdx += 1;
                    } else if (typeof token !== 'string') {
                        if (token && token.test && token.test(chr) || $.isFunction(token) && token(chr)) {
                            result += chr;
                            tokenIdx += 1;
                        } else {
                            if (valueLength === 1) {
                                this._blinkInvalidState();
                            }
                        }
                        chrIdx += 1;
                    } else {
                        tokenIdx += 1;
                    }
                    if (chrIdx >= valueLength) {
                        break;
                    }
                }
                this._unmaskedValue = result;
                return result;
            },
            _wrapper: function () {
                var that = this;
                var element = that.element;
                var DOMElement = element[0];
                var wrapper = element.wrap('<span class=\'k-widget k-maskedtextbox\'></span>').parent();
                wrapper[0].style.cssText = DOMElement.style.cssText;
                DOMElement.style.width = '100%';
                that.wrapper = wrapper.addClass(DOMElement.className);
            },
            _blinkInvalidState: function () {
                var that = this;
                that.wrapper.addClass(STATEINVALID);
                clearTimeout(that._invalidStateTimeout);
                that._invalidStateTimeout = setTimeout(proxy(that._removeInvalidState, that), 100);
            },
            _removeInvalidState: function () {
                var that = this;
                that.wrapper.removeClass(STATEINVALID);
                that._invalidStateTimeout = null;
            },
            _tokenize: function () {
                var tokens = [];
                var tokenIdx = 0;
                var mask = this.options.mask || '';
                var maskChars = mask.split('');
                var length = maskChars.length;
                var idx = 0;
                var chr;
                var rule;
                var emptyMask = '';
                var promptChar = this.options.promptChar;
                var numberFormat = kendo.getCulture(this.options.culture).numberFormat;
                var rules = this._rules;
                for (; idx < length; idx++) {
                    chr = maskChars[idx];
                    rule = rules[chr];
                    if (rule) {
                        tokens[tokenIdx] = rule;
                        emptyMask += promptChar;
                        tokenIdx += 1;
                    } else {
                        if (chr === '.' || chr === ',') {
                            chr = numberFormat[chr];
                        } else if (chr === '$') {
                            chr = numberFormat.currency.symbol;
                        } else if (chr === '\\') {
                            idx += 1;
                            chr = maskChars[idx];
                        }
                        chr = chr.split('');
                        for (var i = 0, l = chr.length; i < l; i++) {
                            tokens[tokenIdx] = chr[i];
                            emptyMask += chr[i];
                            tokenIdx += 1;
                        }
                    }
                }
                this.tokens = tokens;
                this._emptyMask = emptyMask;
                this._maskLength = emptyMask.length;
            }
        });
        ui.plugin(MaskedTextBox);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.toolbar', [
        'kendo.core',
        'kendo.userevents',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'toolbar',
        name: 'ToolBar',
        category: 'web',
        description: 'The ToolBar widget displays one or more command buttons divided into groups.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Class = kendo.Class, Widget = kendo.ui.Widget, proxy = $.proxy, isFunction = kendo.isFunction, keys = kendo.keys, outerWidth = kendo._outerWidth, TOOLBAR = 'k-toolbar', BUTTON = 'k-button', OVERFLOW_BUTTON = 'k-overflow-button', TOGGLE_BUTTON = 'k-toggle-button', BUTTON_GROUP = 'k-button-group', SPLIT_BUTTON = 'k-split-button', SEPARATOR = 'k-separator', POPUP = 'k-popup', RESIZABLE_TOOLBAR = 'k-toolbar-resizable', STATE_ACTIVE = 'k-state-active', STATE_DISABLED = 'k-state-disabled', STATE_HIDDEN = 'k-state-hidden', GROUP_START = 'k-group-start', GROUP_END = 'k-group-end', PRIMARY = 'k-primary', ICON = 'k-icon', ICON_PREFIX = 'k-i-', BUTTON_ICON = 'k-button-icon', BUTTON_ICON_TEXT = 'k-button-icontext', LIST_CONTAINER = 'k-list-container k-split-container', SPLIT_BUTTON_ARROW = 'k-split-button-arrow', OVERFLOW_ANCHOR = 'k-overflow-anchor', OVERFLOW_CONTAINER = 'k-overflow-container', FIRST_TOOLBAR_VISIBLE = 'k-toolbar-first-visible', LAST_TOOLBAR_VISIBLE = 'k-toolbar-last-visible', CLICK = 'click', TOGGLE = 'toggle', OPEN = 'open', CLOSE = 'close', OVERFLOW_OPEN = 'overflowOpen', OVERFLOW_CLOSE = 'overflowClose', OVERFLOW_NEVER = 'never', OVERFLOW_AUTO = 'auto', OVERFLOW_ALWAYS = 'always', OVERFLOW_HIDDEN = 'k-overflow-hidden', KENDO_UID_ATTR = kendo.attr('uid');
        kendo.toolbar = {};
        var components = {
            overflowAnchor: '<div tabindex="0" class="k-overflow-anchor"></div>',
            overflowContainer: '<ul class="k-overflow-container k-list-container"></ul>'
        };
        kendo.toolbar.registerComponent = function (name, toolbar, overflow) {
            components[name] = {
                toolbar: toolbar,
                overflow: overflow
            };
        };
        var Item = kendo.Class.extend({
            addOverflowAttr: function () {
                this.element.attr(kendo.attr('overflow'), this.options.overflow || OVERFLOW_AUTO);
            },
            addUidAttr: function () {
                this.element.attr(KENDO_UID_ATTR, this.options.uid);
            },
            addIdAttr: function () {
                if (this.options.id) {
                    this.element.attr('id', this.options.id);
                }
            },
            addOverflowIdAttr: function () {
                if (this.options.id) {
                    this.element.attr('id', this.options.id + '_overflow');
                }
            },
            attributes: function () {
                if (this.options.attributes) {
                    this.element.attr(this.options.attributes);
                }
            },
            show: function () {
                this.element.removeClass(STATE_HIDDEN).show();
                this.options.hidden = false;
            },
            hide: function () {
                this.element.addClass(STATE_HIDDEN).hide();
                this.options.hidden = true;
            },
            remove: function () {
                this.element.remove();
            },
            enable: function (isEnabled) {
                if (isEnabled === undefined) {
                    isEnabled = true;
                }
                this.element.toggleClass(STATE_DISABLED, !isEnabled);
                this.options.enable = isEnabled;
            },
            twin: function () {
                var uid = this.element.attr(KENDO_UID_ATTR);
                if (this.overflow) {
                    return this.toolbar.element.find('[' + KENDO_UID_ATTR + '=\'' + uid + '\']').data(this.options.type);
                } else if (this.toolbar.options.resizable) {
                    return this.toolbar.popup.element.find('[' + KENDO_UID_ATTR + '=\'' + uid + '\']').data(this.options.type);
                }
            }
        });
        kendo.toolbar.Item = Item;
        var Button = Item.extend({
            init: function (options, toolbar) {
                var element = options.useButtonTag ? $('<button tabindex="0"></button>') : $('<a href tabindex="0"></a>');
                this.element = element;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                if (options.primary) {
                    element.addClass(PRIMARY);
                }
                if (options.togglable) {
                    element.addClass(TOGGLE_BUTTON);
                    this.toggle(options.selected);
                }
                if (options.url !== undefined && !options.useButtonTag) {
                    element.attr('href', options.url);
                    if (options.mobile) {
                        element.attr(kendo.attr('role'), 'button');
                    }
                }
                if (options.group) {
                    element.attr(kendo.attr('group'), options.group);
                    this.group = this.toolbar.addToGroup(this, options.group);
                }
                if (!options.togglable && options.click && isFunction(options.click)) {
                    this.clickHandler = options.click;
                }
                if (options.togglable && options.toggle && isFunction(options.toggle)) {
                    this.toggleHandler = options.toggle;
                }
            },
            toggle: function (state, propagate) {
                state = !!state;
                if (this.group && state) {
                    this.group.select(this);
                } else if (!this.group) {
                    this.select(state);
                }
                if (propagate && this.twin()) {
                    this.twin().toggle(state);
                }
            },
            getParentGroup: function () {
                if (this.options.isChild) {
                    return this.element.closest('.' + BUTTON_GROUP).data('buttonGroup');
                }
            },
            _addGraphics: function () {
                var element = this.element, icon = this.options.icon, spriteCssClass = this.options.spriteCssClass, imageUrl = this.options.imageUrl, isEmpty, span, img;
                if (spriteCssClass || imageUrl || icon) {
                    isEmpty = true;
                    element.contents().filter(function () {
                        return !$(this).hasClass('k-sprite') && !$(this).hasClass(ICON) && !$(this).hasClass('k-image');
                    }).each(function (idx, el) {
                        if (el.nodeType == 1 || el.nodeType == 3 && $.trim(el.nodeValue).length > 0) {
                            isEmpty = false;
                        }
                    });
                    if (isEmpty) {
                        element.addClass(BUTTON_ICON);
                    } else {
                        element.addClass(BUTTON_ICON_TEXT);
                    }
                }
                if (icon) {
                    span = element.children('span.' + ICON).first();
                    if (!span[0]) {
                        span = $('<span class="' + ICON + '"></span>').prependTo(element);
                    }
                    span.addClass(ICON_PREFIX + icon);
                } else if (spriteCssClass) {
                    span = element.children('span.k-sprite').first();
                    if (!span[0]) {
                        span = $('<span class="k-sprite ' + ICON + '"></span>').prependTo(element);
                    }
                    span.addClass(spriteCssClass);
                } else if (imageUrl) {
                    img = element.children('img.k-image').first();
                    if (!img[0]) {
                        img = $('<img alt="icon" class="k-image" />').prependTo(element);
                    }
                    img.attr('src', imageUrl);
                }
            }
        });
        kendo.toolbar.Button = Button;
        var ToolBarButton = Button.extend({
            init: function (options, toolbar) {
                Button.fn.init.call(this, options, toolbar);
                var element = this.element;
                element.addClass(BUTTON);
                this.addIdAttr();
                if (options.align) {
                    element.addClass('k-align-' + options.align);
                }
                if (options.showText != 'overflow' && options.text) {
                    if (options.mobile) {
                        element.html('<span class="km-text">' + options.text + '</span>');
                    } else {
                        element.html(options.text);
                    }
                }
                options.hasIcon = options.showIcon != 'overflow' && (options.icon || options.spriteCssClass || options.imageUrl);
                if (options.hasIcon) {
                    this._addGraphics();
                }
                this.addUidAttr();
                this.addOverflowAttr();
                this.enable(options.enable);
                if (options.hidden) {
                    this.hide();
                }
                this.element.data({
                    type: 'button',
                    button: this
                });
            },
            select: function (selected) {
                if (selected === undefined) {
                    selected = false;
                }
                this.element.toggleClass(STATE_ACTIVE, selected);
                this.options.selected = selected;
            }
        });
        kendo.toolbar.ToolBarButton = ToolBarButton;
        var OverflowButton = Button.extend({
            init: function (options, toolbar) {
                this.overflow = true;
                Button.fn.init.call(this, options, toolbar);
                var element = this.element;
                if (options.showText != 'toolbar' && options.text) {
                    if (options.mobile) {
                        element.html('<span class="km-text">' + options.text + '</span>');
                    } else {
                        element.html('<span class="k-text">' + options.text + '</span>');
                    }
                }
                options.hasIcon = options.showIcon != 'toolbar' && (options.icon || options.spriteCssClass || options.imageUrl);
                if (options.hasIcon) {
                    this._addGraphics();
                }
                if (!options.isChild) {
                    this._wrap();
                }
                this.addOverflowIdAttr();
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this.enable(options.enable);
                element.addClass(OVERFLOW_BUTTON + ' ' + BUTTON);
                if (options.hidden) {
                    this.hide();
                }
                if (options.togglable) {
                    this.toggle(options.selected);
                }
                this.element.data({
                    type: 'button',
                    button: this
                });
            },
            _wrap: function () {
                this.element = this.element.wrap('<li></li>').parent();
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            },
            select: function (selected) {
                if (selected === undefined) {
                    selected = false;
                }
                if (this.options.isChild) {
                    this.element.toggleClass(STATE_ACTIVE, selected);
                } else {
                    this.element.find('.k-button').toggleClass(STATE_ACTIVE, selected);
                }
                this.options.selected = selected;
            }
        });
        kendo.toolbar.OverflowButton = OverflowButton;
        kendo.toolbar.registerComponent('button', ToolBarButton, OverflowButton);
        var ButtonGroup = Item.extend({
            createButtons: function (buttonConstructor) {
                var options = this.options;
                var items = options.buttons || [];
                var item;
                for (var i = 0; i < items.length; i++) {
                    if (!items[i].uid) {
                        items[i].uid = kendo.guid();
                    }
                    item = new buttonConstructor($.extend({
                        mobile: options.mobile,
                        isChild: true,
                        type: 'button'
                    }, items[i]), this.toolbar);
                    item.element.appendTo(this.element);
                }
            },
            refresh: function () {
                this.element.children().filter(':not(\'.' + STATE_HIDDEN + '\'):first').addClass(GROUP_START);
                this.element.children().filter(':not(\'.' + STATE_HIDDEN + '\'):last').addClass(GROUP_END);
            }
        });
        kendo.toolbar.ButtonGroup = ButtonGroup;
        var ToolBarButtonGroup = ButtonGroup.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<div></div>');
                this.options = options;
                this.toolbar = toolbar;
                this.addIdAttr();
                if (options.align) {
                    element.addClass('k-align-' + options.align);
                }
                this.createButtons(ToolBarButton);
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this.refresh();
                element.addClass(BUTTON_GROUP);
                this.element.data({
                    type: 'buttonGroup',
                    buttonGroup: this
                });
            }
        });
        kendo.toolbar.ToolBarButtonGroup = ToolBarButtonGroup;
        var OverflowButtonGroup = ButtonGroup.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<li></li>');
                this.options = options;
                this.toolbar = toolbar;
                this.overflow = true;
                this.addOverflowIdAttr();
                this.createButtons(OverflowButton);
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this.refresh();
                element.addClass((options.mobile ? '' : BUTTON_GROUP) + ' k-overflow-group');
                this.element.data({
                    type: 'buttonGroup',
                    buttonGroup: this
                });
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            }
        });
        kendo.toolbar.OverflowButtonGroup = OverflowButtonGroup;
        kendo.toolbar.registerComponent('buttonGroup', ToolBarButtonGroup, OverflowButtonGroup);
        var ToolBarSplitButton = Item.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<div class="' + SPLIT_BUTTON + '" tabindex="0"></div>');
                this.options = options;
                this.toolbar = toolbar;
                this.mainButton = new ToolBarButton($.extend({}, options, { hidden: false }), toolbar);
                this.arrowButton = $('<a class="' + BUTTON + ' ' + SPLIT_BUTTON_ARROW + '"><span class="' + (options.mobile ? 'km-icon km-arrowdown' : 'k-icon k-i-arrow-60-down') + '"></span></a>');
                this.popupElement = $('<ul class="' + LIST_CONTAINER + '"></ul>');
                this.mainButton.element.removeAttr('href tabindex').appendTo(element);
                this.arrowButton.appendTo(element);
                this.popupElement.appendTo(element);
                if (options.align) {
                    element.addClass('k-align-' + options.align);
                }
                if (!options.id) {
                    options.id = options.uid;
                }
                element.attr('id', options.id + '_wrapper');
                this.addOverflowAttr();
                this.addUidAttr();
                this.createMenuButtons();
                this.createPopup();
                this._navigatable();
                this.mainButton.main = true;
                this.enable(options.enable);
                if (options.hidden) {
                    this.hide();
                }
                element.data({
                    type: 'splitButton',
                    splitButton: this,
                    kendoPopup: this.popup
                });
            },
            _navigatable: function () {
                var that = this;
                that.popupElement.on('keydown', '.' + BUTTON, function (e) {
                    var li = $(e.target).parent();
                    e.preventDefault();
                    if (e.keyCode === keys.ESC || e.keyCode === keys.TAB || e.altKey && e.keyCode === keys.UP) {
                        that.toggle();
                        that.focus();
                    } else if (e.keyCode === keys.DOWN) {
                        findFocusableSibling(li, 'next').focus();
                    } else if (e.keyCode === keys.UP) {
                        findFocusableSibling(li, 'prev').focus();
                    } else if (e.keyCode === keys.SPACEBAR || e.keyCode === keys.ENTER) {
                        that.toolbar.userEvents.trigger('tap', { target: $(e.target) });
                    }
                });
            },
            createMenuButtons: function () {
                var options = this.options;
                var items = options.menuButtons;
                var item;
                for (var i = 0; i < items.length; i++) {
                    item = new ToolBarButton($.extend({
                        mobile: options.mobile,
                        type: 'button',
                        click: options.click
                    }, items[i]), this.toolbar);
                    item.element.wrap('<li></li>').parent().appendTo(this.popupElement);
                }
            },
            createPopup: function () {
                var options = this.options;
                var element = this.element;
                this.popupElement.attr('id', options.id + '_optionlist').attr(KENDO_UID_ATTR, options.rootUid);
                if (options.mobile) {
                    this.popupElement = actionSheetWrap(this.popupElement);
                }
                this.popup = this.popupElement.kendoPopup({
                    appendTo: options.mobile ? $(options.mobile).children('.km-pane') : null,
                    anchor: element,
                    isRtl: this.toolbar._isRtl,
                    copyAnchorStyles: false,
                    animation: options.animation,
                    open: adjustPopupWidth,
                    activate: function () {
                        this.element.find(':kendoFocusable').first().focus();
                    },
                    close: function () {
                        element.focus();
                    }
                }).data('kendoPopup');
                this.popup.element.on(CLICK, 'a.k-button', preventClick);
            },
            remove: function () {
                this.popup.element.off(CLICK, 'a.k-button');
                this.popup.destroy();
                this.element.remove();
            },
            toggle: function () {
                this.popup.toggle();
            },
            enable: function (isEnabled) {
                if (isEnabled === undefined) {
                    isEnabled = true;
                }
                this.mainButton.enable(isEnabled);
                this.options.enable = isEnabled;
            },
            focus: function () {
                this.element.focus();
            },
            hide: function () {
                if (this.popup) {
                    this.popup.close();
                }
                this.element.addClass(STATE_HIDDEN).hide();
                this.options.hidden = true;
            },
            show: function () {
                this.element.removeClass(STATE_HIDDEN).hide();
                this.options.hidden = false;
            }
        });
        kendo.toolbar.ToolBarSplitButton = ToolBarSplitButton;
        var OverflowSplitButton = Item.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<li class="' + SPLIT_BUTTON + '"></li>'), items = options.menuButtons, item;
                this.options = options;
                this.toolbar = toolbar;
                this.overflow = true;
                this.mainButton = new OverflowButton($.extend({ isChild: true }, options));
                this.mainButton.element.appendTo(element);
                for (var i = 0; i < items.length; i++) {
                    item = new OverflowButton($.extend({
                        mobile: options.mobile,
                        isChild: true
                    }, items[i]), this.toolbar);
                    item.element.appendTo(element);
                }
                this.addUidAttr();
                this.addOverflowAttr();
                this.mainButton.main = true;
                element.data({
                    type: 'splitButton',
                    splitButton: this
                });
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            }
        });
        kendo.toolbar.OverflowSplitButton = OverflowSplitButton;
        kendo.toolbar.registerComponent('splitButton', ToolBarSplitButton, OverflowSplitButton);
        var ToolBarSeparator = Item.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<div>&nbsp;</div>');
                this.element = element;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addIdAttr();
                this.addUidAttr();
                this.addOverflowAttr();
                element.addClass(SEPARATOR);
                element.data({
                    type: 'separator',
                    separator: this
                });
            }
        });
        var OverflowSeparator = Item.extend({
            init: function (options, toolbar) {
                var element = this.element = $('<li>&nbsp;</li>');
                this.element = element;
                this.options = options;
                this.toolbar = toolbar;
                this.overflow = true;
                this.attributes();
                this.addUidAttr();
                this.addOverflowIdAttr();
                element.addClass(SEPARATOR);
                element.data({
                    type: 'separator',
                    separator: this
                });
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            }
        });
        kendo.toolbar.registerComponent('separator', ToolBarSeparator, OverflowSeparator);
        var TemplateItem = Item.extend({
            init: function (template, options, toolbar) {
                var element = isFunction(template) ? template(options) : template;
                if (!(element instanceof jQuery)) {
                    element = $('<div></div>').html(element);
                } else {
                    element = element.wrap('<div></div>').parent();
                }
                this.element = element;
                this.options = options;
                this.options.type = 'template';
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addIdAttr();
                this.addOverflowAttr();
                element.data({
                    type: 'template',
                    template: this
                });
            }
        });
        kendo.toolbar.TemplateItem = TemplateItem;
        var OverflowTemplateItem = Item.extend({
            init: function (template, options, toolbar) {
                var element = isFunction(template) ? $(template(options)) : $(template);
                if (!(element instanceof jQuery)) {
                    element = $('<li></li>').html(element);
                } else {
                    element = element.wrap('<li></li>').parent();
                }
                this.element = element;
                this.options = options;
                this.options.type = 'template';
                this.toolbar = toolbar;
                this.overflow = true;
                this.attributes();
                this.addUidAttr();
                this.addOverflowIdAttr();
                this.addOverflowAttr();
                element.data({
                    type: 'template',
                    template: this
                });
            },
            overflowHidden: function () {
                this.element.addClass(OVERFLOW_HIDDEN);
            }
        });
        kendo.toolbar.OverflowTemplateItem = OverflowTemplateItem;
        function adjustPopupWidth() {
            var anchor = this.options.anchor, computedWidth = outerWidth(anchor), width;
            kendo.wrap(this.element).addClass('k-split-wrapper');
            if (this.element.css('box-sizing') !== 'border-box') {
                width = computedWidth - (outerWidth(this.element) - this.element.width());
            } else {
                width = computedWidth;
            }
            this.element.css({
                fontFamily: anchor.css('font-family'),
                'min-width': width
            });
        }
        function toggleActive(e) {
            if (!e.target.is('.k-toggle-button')) {
                e.target.toggleClass(STATE_ACTIVE, e.type == 'press');
            }
        }
        function actionSheetWrap(element) {
            element = $(element);
            return element.hasClass('km-actionsheet') ? element.closest('.km-popup-wrapper') : element.addClass('km-widget km-actionsheet').wrap('<div class="km-actionsheet-wrapper km-actionsheet-tablet km-widget km-popup"></div>').parent().wrap('<div class="km-popup-wrapper k-popup"></div>').parent();
        }
        function preventClick(e) {
            e.preventDefault();
        }
        function findFocusableSibling(element, dir) {
            var getSibling = dir === 'next' ? $.fn.next : $.fn.prev;
            var getter = dir === 'next' ? $.fn.first : $.fn.last;
            var candidate = getSibling.call(element);
            if (candidate.is(':kendoFocusable') || !candidate.length) {
                return candidate;
            }
            if (candidate.find(':kendoFocusable').length) {
                return getter.call(candidate.find(':kendoFocusable'));
            }
            return findFocusableSibling(candidate, dir);
        }
        var Group = Class.extend({
            init: function (name) {
                this.name = name;
                this.buttons = [];
            },
            add: function (button) {
                this.buttons[this.buttons.length] = button;
            },
            remove: function (button) {
                var index = $.inArray(button, this.buttons);
                this.buttons.splice(index, 1);
            },
            select: function (button) {
                var tmp;
                for (var i = 0; i < this.buttons.length; i++) {
                    tmp = this.buttons[i];
                    tmp.select(false);
                }
                button.select(true);
                if (button.twin()) {
                    button.twin().select(true);
                }
            }
        });
        var ToolBar = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.wrapper = that.element;
                element.addClass(TOOLBAR + ' k-widget');
                this.uid = kendo.guid();
                this._isRtl = kendo.support.isRtl(element);
                this._groups = {};
                element.attr(KENDO_UID_ATTR, this.uid);
                that.isMobile = typeof options.mobile === 'boolean' ? options.mobile : that.element.closest('.km-root')[0];
                that.animation = that.isMobile ? { open: { effects: 'fade' } } : {};
                if (that.isMobile) {
                    element.addClass('km-widget');
                    ICON = 'km-icon';
                    ICON_PREFIX = 'km-';
                    BUTTON = 'km-button';
                    BUTTON_GROUP = 'km-buttongroup km-widget';
                    STATE_ACTIVE = 'km-state-active';
                    STATE_DISABLED = 'km-state-disabled';
                }
                if (options.resizable) {
                    that._renderOverflow();
                    element.addClass(RESIZABLE_TOOLBAR);
                    that.overflowUserEvents = new kendo.UserEvents(that.element, {
                        threshold: 5,
                        allowSelection: true,
                        filter: '.' + OVERFLOW_ANCHOR,
                        tap: proxy(that._toggleOverflow, that)
                    });
                    that._resizeHandler = kendo.onResize(function () {
                        that.resize();
                    });
                } else {
                    that.popup = { element: $([]) };
                }
                if (options.items && options.items.length) {
                    for (var i = 0; i < options.items.length; i++) {
                        that.add(options.items[i]);
                    }
                }
                that.userEvents = new kendo.UserEvents(document, {
                    threshold: 5,
                    allowSelection: true,
                    filter: '[' + KENDO_UID_ATTR + '=' + this.uid + '] a.' + BUTTON + ', ' + '[' + KENDO_UID_ATTR + '=' + this.uid + '] .' + OVERFLOW_BUTTON,
                    tap: proxy(that._buttonClick, that),
                    press: toggleActive,
                    release: toggleActive
                });
                that.element.on(CLICK, 'a.k-button', preventClick);
                that._navigatable();
                if (options.resizable) {
                    that.popup.element.on(CLICK, +'a.k-button', preventClick);
                }
                if (options.resizable) {
                    this._toggleOverflowAnchor();
                }
                kendo.notify(that);
            },
            events: [
                CLICK,
                TOGGLE,
                OPEN,
                CLOSE,
                OVERFLOW_OPEN,
                OVERFLOW_CLOSE
            ],
            options: {
                name: 'ToolBar',
                items: [],
                resizable: true,
                mobile: null
            },
            addToGroup: function (button, groupName) {
                var group;
                if (!this._groups[groupName]) {
                    group = this._groups[groupName] = new Group();
                } else {
                    group = this._groups[groupName];
                }
                group.add(button);
                return group;
            },
            destroy: function () {
                var that = this;
                that.element.find('.' + SPLIT_BUTTON).each(function (idx, element) {
                    $(element).data('kendoPopup').destroy();
                });
                that.element.off(CLICK, 'a.k-button');
                that.userEvents.destroy();
                if (that.options.resizable) {
                    kendo.unbindResize(that._resizeHandler);
                    that.overflowUserEvents.destroy();
                    that.popup.element.off(CLICK, 'a.k-button');
                    that.popup.destroy();
                }
                Widget.fn.destroy.call(that);
            },
            add: function (options) {
                var component = components[options.type], template = options.template, tool, that = this, itemClasses = that.isMobile ? '' : 'k-item k-state-default', overflowTemplate = options.overflowTemplate, overflowTool;
                $.extend(options, {
                    uid: kendo.guid(),
                    animation: that.animation,
                    mobile: that.isMobile,
                    rootUid: that.uid
                });
                if (options.menuButtons) {
                    for (var i = 0; i < options.menuButtons.length; i++) {
                        $.extend(options.menuButtons[i], { uid: kendo.guid() });
                    }
                }
                if (template && !overflowTemplate) {
                    options.overflow = OVERFLOW_NEVER;
                } else if (!options.overflow) {
                    options.overflow = OVERFLOW_AUTO;
                }
                if (options.overflow !== OVERFLOW_NEVER && that.options.resizable) {
                    if (overflowTemplate) {
                        overflowTool = new OverflowTemplateItem(overflowTemplate, options, that);
                    } else if (component) {
                        overflowTool = new component.overflow(options, that);
                        overflowTool.element.addClass(itemClasses);
                    }
                    if (overflowTool) {
                        if (options.overflow === OVERFLOW_AUTO) {
                            overflowTool.overflowHidden();
                        }
                        overflowTool.element.appendTo(that.popup.container);
                        that.angular('compile', function () {
                            return { elements: overflowTool.element.get() };
                        });
                    }
                }
                if (options.overflow !== OVERFLOW_ALWAYS) {
                    if (template) {
                        tool = new TemplateItem(template, options, that);
                    } else if (component) {
                        tool = new component.toolbar(options, that);
                    }
                    if (tool) {
                        if (that.options.resizable) {
                            tool.element.appendTo(that.element).css('visibility', 'hidden');
                            that._shrink(that.element.innerWidth());
                            tool.element.css('visibility', 'visible');
                        } else {
                            tool.element.appendTo(that.element);
                        }
                        that.angular('compile', function () {
                            return { elements: tool.element.get() };
                        });
                    }
                }
            },
            _getItem: function (candidate) {
                var element, toolbarItem, overflowItem, isResizable = this.options.resizable, type;
                element = this.element.find(candidate);
                if (!element.length) {
                    element = $('.k-split-container[data-uid=' + this.uid + ']').find(candidate);
                }
                type = element.length ? element.data('type') : '';
                toolbarItem = element.data(type);
                if (toolbarItem) {
                    if (toolbarItem.main) {
                        element = element.parent('.' + SPLIT_BUTTON);
                        type = 'splitButton';
                        toolbarItem = element.data(type);
                    }
                    if (isResizable) {
                        overflowItem = toolbarItem.twin();
                    }
                } else if (isResizable) {
                    element = this.popup.element.find(candidate);
                    type = element.length ? element.data('type') : '';
                    overflowItem = element.data(type);
                    if (overflowItem && overflowItem.main) {
                        element = element.parent('.' + SPLIT_BUTTON);
                        type = 'splitButton';
                        overflowItem = element.data(type);
                    }
                }
                return {
                    type: type,
                    toolbar: toolbarItem,
                    overflow: overflowItem
                };
            },
            remove: function (candidate) {
                var item = this._getItem(candidate);
                if (item.toolbar) {
                    item.toolbar.remove();
                }
                if (item.overflow) {
                    item.overflow.remove();
                }
                this.resize(true);
            },
            hide: function (candidate) {
                var item = this._getItem(candidate);
                if (item.toolbar) {
                    if (item.toolbar.options.type === 'button' && item.toolbar.options.isChild) {
                        item.toolbar.hide();
                        item.toolbar.getParentGroup().refresh();
                    } else if (!item.toolbar.options.hidden) {
                        item.toolbar.hide();
                    }
                }
                if (item.overflow) {
                    if (item.overflow.options.type === 'button' && item.overflow.options.isChild) {
                        item.overflow.hide();
                        item.overflow.getParentGroup().refresh();
                    } else if (!item.overflow.options.hidden) {
                        item.overflow.hide();
                    }
                }
                this.resize(true);
            },
            show: function (candidate) {
                var item = this._getItem(candidate);
                if (item.toolbar) {
                    if (item.toolbar.options.type === 'button' && item.toolbar.options.isChild) {
                        item.toolbar.show();
                        item.toolbar.getParentGroup().refresh();
                    } else if (item.toolbar.options.hidden) {
                        item.toolbar.show();
                    }
                }
                if (item.overflow) {
                    if (item.overflow.options.type === 'button' && item.overflow.options.isChild) {
                        item.toolbar.show();
                        item.overflow.getParentGroup().refresh();
                    } else if (item.overflow.options.hidden) {
                        item.overflow.show();
                    }
                }
                this.resize(true);
            },
            enable: function (element, enable) {
                var item = this._getItem(element);
                if (typeof enable == 'undefined') {
                    enable = true;
                }
                if (item.toolbar) {
                    item.toolbar.enable(enable);
                }
                if (item.overflow) {
                    item.overflow.enable(enable);
                }
            },
            getSelectedFromGroup: function (groupName) {
                return this.element.find('.' + TOGGLE_BUTTON + '[data-group=\'' + groupName + '\']').filter('.' + STATE_ACTIVE);
            },
            toggle: function (button, checked) {
                var element = $(button), item = element.data('button');
                if (item.options.togglable) {
                    if (checked === undefined) {
                        checked = true;
                    }
                    item.toggle(checked, true);
                }
            },
            _renderOverflow: function () {
                var that = this, overflowContainer = components.overflowContainer, isRtl = that._isRtl, horizontalDirection = isRtl ? 'left' : 'right';
                that.overflowAnchor = $(components.overflowAnchor).addClass(BUTTON);
                that.element.append(that.overflowAnchor);
                if (that.isMobile) {
                    that.overflowAnchor.append('<span class="km-icon km-more"></span>');
                    overflowContainer = actionSheetWrap(overflowContainer);
                } else {
                    that.overflowAnchor.append('<span class="k-icon k-i-arrow-60-down"></span>');
                }
                that.popup = new kendo.ui.Popup(overflowContainer, {
                    origin: 'bottom ' + horizontalDirection,
                    position: 'top ' + horizontalDirection,
                    anchor: that.overflowAnchor,
                    isRtl: isRtl,
                    animation: that.animation,
                    appendTo: that.isMobile ? $(that.isMobile).children('.km-pane') : null,
                    copyAnchorStyles: false,
                    open: function (e) {
                        var wrapper = kendo.wrap(that.popup.element).addClass('k-overflow-wrapper');
                        if (!that.isMobile) {
                            wrapper.css('margin-left', (isRtl ? -1 : 1) * ((outerWidth(wrapper) - wrapper.width()) / 2 + 1));
                        } else {
                            that.popup.container.css('max-height', parseFloat($('.km-content:visible').innerHeight()) - 15 + 'px');
                        }
                        if (that.trigger(OVERFLOW_OPEN)) {
                            e.preventDefault();
                        }
                    },
                    activate: function () {
                        this.element.find(':kendoFocusable').first().focus();
                    },
                    close: function (e) {
                        if (that.trigger(OVERFLOW_CLOSE)) {
                            e.preventDefault();
                        }
                        this.element.focus();
                    }
                });
                that.popup.element.on('keydown', '.' + BUTTON, function (e) {
                    var target = $(e.target), li = target.parent(), isComplexTool = li.is('.' + BUTTON_GROUP) || li.is('.' + SPLIT_BUTTON), element;
                    e.preventDefault();
                    if (e.keyCode === keys.ESC || e.keyCode === keys.TAB || e.altKey && e.keyCode === keys.UP) {
                        that._toggleOverflow();
                        that.overflowAnchor.focus();
                    } else if (e.keyCode === keys.DOWN) {
                        element = !isComplexTool || isComplexTool && target.is(':last-child') ? li : target;
                        findFocusableSibling(element, 'next').focus();
                    } else if (e.keyCode === keys.UP) {
                        element = !isComplexTool || isComplexTool && target.is(':first-child') ? li : target;
                        findFocusableSibling(element, 'prev').focus();
                    } else if (e.keyCode === keys.SPACEBAR || e.keyCode === keys.ENTER) {
                        that.userEvents.trigger('tap', { target: $(e.target) });
                    }
                });
                if (that.isMobile) {
                    that.popup.container = that.popup.element.find('.' + OVERFLOW_CONTAINER);
                } else {
                    that.popup.container = that.popup.element;
                }
                that.popup.container.attr(KENDO_UID_ATTR, this.uid);
            },
            _toggleOverflowAnchor: function () {
                var hasVisibleChildren = false;
                if (this.options.mobile) {
                    hasVisibleChildren = this.popup.element.find('.' + OVERFLOW_CONTAINER).children(':not(.' + OVERFLOW_HIDDEN + ', .' + POPUP + ')').length > 0;
                } else {
                    hasVisibleChildren = this.popup.element.children(':not(.' + OVERFLOW_HIDDEN + ', .' + POPUP + ')').length > 0;
                }
                if (hasVisibleChildren) {
                    this.overflowAnchor.css({
                        visibility: 'visible',
                        width: ''
                    });
                } else {
                    this.overflowAnchor.css({
                        visibility: 'hidden',
                        width: '1px'
                    });
                }
            },
            _buttonClick: function (e) {
                var that = this, popup, target, item, splitContainer, isSplitButtonArrow = e.target.closest('.' + SPLIT_BUTTON_ARROW).length, handler, eventData, urlTarget;
                e.preventDefault();
                if (isSplitButtonArrow) {
                    that._toggle(e);
                    return;
                }
                target = $(e.target).closest('.' + BUTTON, that.element);
                if (target.hasClass(OVERFLOW_ANCHOR)) {
                    return;
                }
                item = target.data('button');
                if (!item && that.popup) {
                    target = $(e.target).closest('.' + OVERFLOW_BUTTON, that.popup.container);
                    item = target.parent('li').data('button');
                }
                if (!item || !item.options.enable) {
                    return;
                }
                if (item.options.togglable) {
                    handler = isFunction(item.toggleHandler) ? item.toggleHandler : null;
                    item.toggle(!item.options.selected, true);
                    eventData = {
                        target: target,
                        group: item.options.group,
                        checked: item.options.selected,
                        id: item.options.id
                    };
                    if (handler) {
                        handler.call(that, eventData);
                    }
                    that.trigger(TOGGLE, eventData);
                } else {
                    handler = isFunction(item.clickHandler) ? item.clickHandler : null;
                    eventData = {
                        sender: that,
                        target: target,
                        id: item.options.id
                    };
                    if (handler) {
                        handler.call(that, eventData);
                    }
                    that.trigger(CLICK, eventData);
                }
                if (item.options.url) {
                    if (item.options.attributes && item.options.attributes.target) {
                        urlTarget = item.options.attributes.target;
                    }
                    window.open(item.options.url, urlTarget || '_self');
                }
                if (target.hasClass(OVERFLOW_BUTTON)) {
                    that.popup.close();
                }
                splitContainer = target.closest('.k-split-container');
                if (splitContainer[0]) {
                    popup = splitContainer.data('kendoPopup');
                    (popup ? popup : splitContainer.parents('.km-popup-wrapper').data('kendoPopup')).close();
                }
            },
            _navigatable: function () {
                var that = this;
                that.element.attr('tabindex', 0).focus(function () {
                    var element = $(this).find(':kendoFocusable:first');
                    if (element.length === 0) {
                        return;
                    }
                    if (element.is('.' + OVERFLOW_ANCHOR)) {
                        element = findFocusableSibling(element, 'next');
                    }
                    element[0].focus();
                }).on('keydown', proxy(that._keydown, that));
            },
            _keydown: function (e) {
                var target = $(e.target), keyCode = e.keyCode, items = this.element.children(':not(.k-separator):visible');
                if (keyCode === keys.TAB) {
                    var element = target.parentsUntil(this.element).last(), lastHasFocus = false, firstHasFocus = false;
                    if (!element.length) {
                        element = target;
                    }
                    if (element.is('.' + OVERFLOW_ANCHOR)) {
                        if (e.shiftKey) {
                            e.preventDefault();
                        }
                        if (items.last().is(':kendoFocusable')) {
                            items.last().focus();
                        } else {
                            items.last().find(':kendoFocusable').last().focus();
                        }
                    }
                    if (!e.shiftKey && items.index(element) === items.length - 1) {
                        if (element.is('.' + BUTTON_GROUP)) {
                            lastHasFocus = target.is(':last-child');
                        } else {
                            lastHasFocus = true;
                        }
                    }
                    var isFirstTool = items.index(element) === items.not('.k-overflow-anchor').first().index();
                    if (e.shiftKey && isFirstTool) {
                        if (element.is('.' + BUTTON_GROUP)) {
                            firstHasFocus = target.is(':first-child');
                        } else {
                            firstHasFocus = true;
                        }
                    }
                    if (lastHasFocus && this.overflowAnchor && this.overflowAnchor.css('visibility') !== 'hidden') {
                        e.preventDefault();
                        this.overflowAnchor.focus();
                    }
                    if (firstHasFocus) {
                        e.preventDefault();
                        var prevFocusable = this._getPrevFocusable(this.wrapper);
                        if (prevFocusable) {
                            prevFocusable.focus();
                        }
                    }
                }
                if (e.altKey && keyCode === keys.DOWN) {
                    var splitButton = $(document.activeElement).data('splitButton');
                    var isOverflowAnchor = $(document.activeElement).is('.' + OVERFLOW_ANCHOR);
                    if (splitButton) {
                        splitButton.toggle();
                    } else if (isOverflowAnchor) {
                        this._toggleOverflow();
                    }
                    return;
                }
                if ((keyCode === keys.SPACEBAR || keyCode === keys.ENTER) && !target.is('input, checkbox')) {
                    e.preventDefault();
                    if (target.is('.' + SPLIT_BUTTON)) {
                        target = target.children().first();
                    }
                    this.userEvents.trigger('tap', { target: target });
                    return;
                }
            },
            _getPrevFocusable: function (element) {
                if (element.is('html')) {
                    return element;
                }
                var elementToFocus, prevElement, prevElements = element.prevAll();
                prevElements.each(function () {
                    prevElement = $(this);
                    if (prevElement.is(':kendoFocusable')) {
                        elementToFocus = prevElement;
                        return false;
                    } else if (prevElement.find(':kendoFocusable').length > 0) {
                        elementToFocus = prevElement.find(':kendoFocusable').last();
                        return false;
                    }
                });
                if (elementToFocus) {
                    return elementToFocus;
                } else {
                    return this._getPrevFocusable(element.parent());
                }
            },
            _toggle: function (e) {
                var splitButton = $(e.target).closest('.' + SPLIT_BUTTON).data('splitButton'), isDefaultPrevented;
                e.preventDefault();
                if (!splitButton.options.enable) {
                    return;
                }
                if (splitButton.popup.element.is(':visible')) {
                    isDefaultPrevented = this.trigger(CLOSE, { target: splitButton.element });
                } else {
                    isDefaultPrevented = this.trigger(OPEN, { target: splitButton.element });
                }
                if (!isDefaultPrevented) {
                    splitButton.toggle();
                }
            },
            _toggleOverflow: function () {
                this.popup.toggle();
            },
            _resize: function (e) {
                var containerWidth = e.width;
                if (!this.options.resizable) {
                    return;
                }
                this.popup.close();
                this._shrink(containerWidth);
                this._stretch(containerWidth);
                this._markVisibles();
                this._toggleOverflowAnchor();
            },
            _childrenWidth: function () {
                var childrenWidth = 0;
                this.element.children(':visible:not(\'.' + STATE_HIDDEN + '\')').each(function () {
                    childrenWidth += outerWidth($(this), true);
                });
                return Math.ceil(childrenWidth);
            },
            _shrink: function (containerWidth) {
                var commandElement, visibleCommands;
                if (containerWidth < this._childrenWidth()) {
                    visibleCommands = this.element.children(':visible:not([data-overflow=\'never\'], .' + OVERFLOW_ANCHOR + ')');
                    for (var i = visibleCommands.length - 1; i >= 0; i--) {
                        commandElement = visibleCommands.eq(i);
                        if (containerWidth > this._childrenWidth()) {
                            break;
                        } else {
                            this._hideItem(commandElement);
                        }
                    }
                }
            },
            _stretch: function (containerWidth) {
                var commandElement, hiddenCommands;
                if (containerWidth > this._childrenWidth()) {
                    hiddenCommands = this.element.children(':hidden:not(\'.' + STATE_HIDDEN + '\')');
                    for (var i = 0; i < hiddenCommands.length; i++) {
                        commandElement = hiddenCommands.eq(i);
                        if (containerWidth < this._childrenWidth() || !this._showItem(commandElement, containerWidth)) {
                            break;
                        }
                    }
                }
            },
            _hideItem: function (item) {
                item.hide();
                if (this.popup) {
                    this.popup.container.find('>li[data-uid=\'' + item.data('uid') + '\']').removeClass(OVERFLOW_HIDDEN);
                }
            },
            _showItem: function (item, containerWidth) {
                if (item.length && containerWidth > this._childrenWidth() + outerWidth(item, true)) {
                    item.show();
                    if (this.popup) {
                        this.popup.container.find('>li[data-uid=\'' + item.data('uid') + '\']').addClass(OVERFLOW_HIDDEN);
                    }
                    return true;
                }
                return false;
            },
            _markVisibles: function () {
                var overflowItems = this.popup.container.children(), toolbarItems = this.element.children(':not(.k-overflow-anchor)'), visibleOverflowItems = overflowItems.filter(':not(.k-overflow-hidden)'), visibleToolbarItems = toolbarItems.filter(':visible');
                overflowItems.add(toolbarItems).removeClass(FIRST_TOOLBAR_VISIBLE + ' ' + LAST_TOOLBAR_VISIBLE);
                visibleOverflowItems.first().add(visibleToolbarItems.first()).addClass(FIRST_TOOLBAR_VISIBLE);
                visibleOverflowItems.last().add(visibleToolbarItems.last()).addClass(LAST_TOOLBAR_VISIBLE);
            }
        });
        kendo.ui.plugin(ToolBar);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mediaplayer', [
        'kendo.slider',
        'kendo.toolbar',
        'kendo.dropdownlist',
        'kendo.tooltip'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mediaplayer',
        name: 'MediaPlayer',
        category: 'web',
        description: '',
        depends: [
            'slider',
            'toolbar',
            'dropdownlist',
            'tooltip'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, END = 'end', PAUSE = 'pause', PLAY = 'play', READY = 'ready', TIMECHANGE = 'timeChange', VOLUMECHANGE = 'volumeChange', FULLSCREEN_ENTER = 'k-i-full-screen', FULLSCREEN_EXIT = 'k-i-full-screen-exit', MUTE = 'k-i-volume-off', LOW_VOLUME = 'k-i-volume-down', HIGH_VOLUME = 'k-i-volume-up', VIDEO_QUALITY = 'k-mediaplayer-quality', STATE_PLAY = 'k-i-play', STATE_PAUSE = 'k-i-pause', TITLEBAR = 'k-mediaplayer-titlebar', TITLE = 'k-title', TOOLBARWRAP = 'k-mediaplayer-toolbar-wrap', TOOLBAR = 'k-mediaplayer-toolbar', SLIDER = 'k-mediaplayer-seekbar', VOLUME_SLIDER = 'k-mediaplayer-volume', MEDIA = 'k-mediaplayer-media', OVERLAY = 'k-mediaplayer-overlay', YTPLAYER = 'k-mediaplayer-yt', DOT = '.', ui = kendo.ui, ns = '.kendoMediaPlayer', baseTime = new Date(1970, 0, 1), timeZoneSec = baseTime.getTimezoneOffset() * 60, Widget = kendo.ui.Widget, isArray = $.isArray, timeFormats = {
                shortTime: 'mm:ss',
                longTime: 'HH:mm:ss'
            }, template = kendo.template, proxy = $.proxy, keys = kendo.keys, templates = {
                htmlPlayer: '<video class=\'' + MEDIA + '\'> </video>',
                titleBar: template('<div class=\'' + TITLEBAR + '\' role=\'heading\'><span class=\'' + TITLE + '\'>Video Title</span></div>'),
                toolBar: '<div class=\'' + TOOLBARWRAP + '\'><div class=\'' + TOOLBAR + '\'></div></div>',
                youtubePlayer: '<div class=\'' + YTPLAYER + '\'> </div>',
                toolBarTime: '<span class=\'k-mediaplayer-currenttime\'>00:00:00</span> / <span class=\'k-mediaplayer-duration\'>00:00:00</span>',
                slider: '<input class=\'' + SLIDER + '\' value=\'0\' title=\'seekbar\' />',
                volumeSlider: '<input class=\'' + VOLUME_SLIDER + '\' title=\'volume\'/>',
                qualityDropDown: '<input class=\'' + VIDEO_QUALITY + '\' title=\'video quality\' />',
                toolTip: '#= kendo.toString(new Date(value), \'HH:mm:ss\') #'
            };
        var MediaPlayer = Widget.extend({
            init: function (element, options) {
                this.wrapper = $(element);
                Widget.fn.init.call(this, element, options);
                this.wrapper.addClass('k-mediaplayer k-widget');
                options = this.options;
                this._currentIndex = 0;
                this._createTitlebar();
                this._createToolbar();
                this._createDropDown();
                this._createSlider();
                this._createVolumeSlider();
                this._timers = {};
                this._aria();
                this._navigatable();
                if (options.media) {
                    this.media(this.options.media);
                }
                kendo.notify(this);
            },
            events: [
                END,
                PAUSE,
                PLAY,
                READY,
                TIMECHANGE,
                VOLUMECHANGE
            ],
            options: {
                name: 'MediaPlayer',
                autoPlay: false,
                autoRepeat: false,
                volume: 100,
                fullScreen: false,
                mute: false,
                navigatable: false,
                forwardSeek: true,
                media: null,
                messages: {
                    'pause': 'Pause',
                    'play': 'Play',
                    'mute': 'Mute',
                    'unmute': 'Unmute',
                    'quality': 'Quality',
                    'fullscreen': 'Full Screen'
                }
            },
            _msToTime: function (ms) {
                var time = new Date(baseTime.getTime());
                time.setSeconds(ms);
                return time;
            },
            _timeToSec: function (time) {
                var curTime = new Date(time).getTime();
                return curTime / 1000;
            },
            _createTitlebar: function () {
                this._titleBar = this.wrapper.find(DOT + TITLEBAR);
                if (this._titleBar.length === 0) {
                    this.wrapper.append(templates.titleBar);
                    this._titleBar = this.wrapper.find(DOT + TITLEBAR);
                }
            },
            _createSlider: function () {
                var sliderElement = this.wrapper.find(DOT + SLIDER);
                if (!this._slider) {
                    this._sliderDragChangeHandler = proxy(this._sliderDragChange, this);
                    this._sliderDraggingHandler = proxy(this._sliderDragging, this);
                    sliderElement = this.wrapper.find(DOT + SLIDER);
                    this._slider = new ui.Slider(sliderElement[0], {
                        smallStep: 1000,
                        tickPlacement: 'none',
                        showButtons: false,
                        change: this._sliderDragChangeHandler,
                        slide: this._sliderDraggingHandler,
                        tooltip: { template: templates.toolTip },
                        dragHandleTitle: ''
                    });
                }
            },
            _createVolumeSlider: function () {
                var volumeSliderElement = this.wrapper.find(DOT + VOLUME_SLIDER);
                if (!this._volumeSlider) {
                    this._volumeDraggingHandler = proxy(this._volumeDragging, this);
                    this._volumeChangeHandler = proxy(this._volumeChange, this);
                    volumeSliderElement.width(87);
                    this._volumeSlider = new ui.Slider(volumeSliderElement[0], {
                        smallStep: 1,
                        min: 0,
                        max: 100,
                        value: this.options.volume,
                        slide: this._volumeDraggingHandler,
                        change: this._volumeChangeHandler,
                        tickPlacement: 'none',
                        showButtons: false,
                        tooltip: { enabled: false },
                        dragHandleTitle: ''
                    });
                }
            },
            _resetTime: function () {
                if (this._youTubeVideo) {
                    this._ytmedia.seekTo(0, true);
                } else {
                    this._media.currentTime = 0;
                }
                this._mediaTimeUpdate();
                $.grep(this._toolBar.options.items, function (e) {
                    return !!e.template;
                }).template = templates.toolBarTime;
            },
            _currentUrl: function () {
                var media = this.media();
                return isArray(media.source) ? media.source[this._currentIndex].url : media.source;
            },
            _isYouTubeUrl: function () {
                return !!this._currentUrl().match('youtube.com/|youtu.be/');
            },
            _setPlayerUrl: function () {
                var oldPlayer = this._youTubeVideo;
                this.stop();
                this._youTubeVideo = this._isYouTubeUrl();
                if (oldPlayer !== this._youTubeVideo) {
                    this.wrapper.find(DOT + YTPLAYER).toggle();
                    this.wrapper.find(DOT + MEDIA).toggle();
                }
                var initialized = this._media || this._ytmedia;
                this._initializePlayer();
                if (initialized) {
                    this.mute(this.mute());
                    this.volume(this.volume());
                }
                if (!this._youTubeVideo) {
                    this._videoOverlay.show();
                    this.wrapper.find(DOT + MEDIA + ' > source').remove();
                    this.wrapper.find(DOT + MEDIA).attr('src', this._currentUrl());
                    if (this.options.autoPlay) {
                        this.play();
                    }
                } else if (this._ytmedia) {
                    if (this._videoOverlay) {
                        this._videoOverlay.hide();
                    }
                    if (this.options.autoPlay) {
                        this._ytmedia.loadVideoById(this._getMediaId());
                        this._playStateToggle(true);
                    } else {
                        this._ytmedia.cueVideoById(this._getMediaId());
                        this._playStateToggle(true);
                    }
                }
            },
            _createToolbar: function () {
                var toolBarElement = this.wrapper.find(DOT + TOOLBAR);
                if (toolBarElement.length === 0) {
                    this._toolbarClickHandler = proxy(this._toolbarClick, this);
                    this.wrapper.append(templates.toolBar);
                    toolBarElement = this.wrapper.find(DOT + TOOLBAR);
                    toolBarElement.width(this.wrapper.find(DOT + MEDIA).width());
                    this._toolBar = new ui.ToolBar(toolBarElement, {
                        click: this._toolbarClickHandler,
                        resizable: false,
                        items: [
                            {
                                type: 'button',
                                attributes: { 'class': 'k-play-button' },
                                icon: 'play'
                            },
                            {
                                template: templates.toolBarTime,
                                attributes: { 'class': 'k-mediaplayer-currenttime-wrap' }
                            },
                            {
                                type: 'separator',
                                attributes: { 'class': 'k-toolbar-spacer' }
                            },
                            {
                                type: 'button',
                                attributes: { 'class': 'k-volume-button' },
                                icon: 'volume-up'
                            },
                            {
                                template: templates.volumeSlider,
                                attributes: { 'class': 'k-mediaplayer-volume-wrap' }
                            },
                            {
                                template: templates.qualityDropDown,
                                attributes: { 'class': 'k-mediaplayer-quality-wrap' }
                            },
                            {
                                type: 'button',
                                attributes: { 'class': 'k-fullscreen-button' },
                                icon: 'full-screen'
                            }
                        ]
                    });
                    toolBarElement.before(templates.slider);
                    this._volumeButton = toolBarElement.find('.k-volume-button');
                    this._fullscreenButton = toolBarElement.find('.k-fullscreen-button');
                    this._volumeButton.attr('title', this.options.mute ? this.options.messages.unmute : this.options.messages.mute);
                    this._volumeButton.attr('aria-label', this.options.mute ? this.options.messages.unmute : this.options.messages.mute);
                    this._fullscreenButton.attr('title', this.options.messages.fullscreen);
                    this._fullscreenButton.attr('aria-label', this.options.messages.fullscreen);
                    toolBarElement.width('auto');
                    this._currentTimeElement = toolBarElement.find('.k-mediaplayer-currenttime');
                    this._durationElement = toolBarElement.find('.k-mediaplayer-duration');
                    this._playButton = toolBarElement.find('.k-play-button');
                    this._playButtonSpan = this._playButton.find('.k-i-play');
                    if (this.options.autoPlay) {
                        this._playStateToggle(true);
                    }
                    $([
                        this._volumeButton[0],
                        toolBarElement.find('.k-mediaplayer-volume-wrap')[0],
                        toolBarElement.find('.k-mediaplayer-quality-wrap')[0],
                        this._fullscreenButton[0]
                    ]).wrapAll('<div class=\'k-align-right\' />');
                    toolBarElement.find('.k-button').addClass('k-bare');
                }
            },
            _createDropDown: function () {
                var dropDownElement = this.wrapper.find(DOT + VIDEO_QUALITY);
                var media = this.media();
                if (typeof dropDownElement.data('kendoDropDownList') === 'undefined') {
                    this._dropDownSelectHandler = proxy(this._dropDownSelect, this);
                    this._dropDown = new ui.DropDownList(dropDownElement, {
                        dataTextField: 'quality',
                        dataValueField: 'url',
                        popup: {
                            position: 'bottom',
                            origin: 'top',
                            appendTo: this.wrapper
                        },
                        animation: {
                            open: {
                                effects: 'slideIn:up',
                                duration: 1
                            }
                        },
                        select: this._dropDownSelectHandler
                    });
                    if (media && isArray(media.source)) {
                        this._dropDown.setDataSource(media.source);
                        this._dropDown.select(0);
                    }
                    this._dropDown.wrapper.addClass('k-button k-bare');
                    this._dropDown.wrapper.attr('title', this.options.messages.quality).hide();
                    this._dropDown.wrapper.find('span.k-i-arrow-60-down').removeClass('k-i-arrow-60-down').addClass('k-icon k-i-hd');
                    this._dropDown.list.addClass('k-quality-list');
                }
            },
            _dropDownSelect: function (e) {
                if (this._currentIndex !== e.item.index()) {
                    this._currentIndex = e.item.index();
                    this._setPlayerUrl();
                }
            },
            _toolbarClick: function (e) {
                var target = $(e.target).children().first();
                var isPaused = target.hasClass(STATE_PLAY);
                if (!this.media()) {
                    return;
                }
                if (target.hasClass(STATE_PLAY) || target.hasClass(STATE_PAUSE)) {
                    if (isPaused) {
                        this.play();
                    } else {
                        this.pause();
                    }
                }
                if (target.hasClass(FULLSCREEN_ENTER) || target.hasClass(FULLSCREEN_EXIT)) {
                    if (this._isInFullScreen) {
                        target.removeClass(FULLSCREEN_EXIT).addClass(FULLSCREEN_ENTER);
                        this.fullScreen(false);
                    } else {
                        target.removeClass(FULLSCREEN_ENTER).addClass(FULLSCREEN_EXIT);
                        this.fullScreen(true);
                    }
                }
                if (target.hasClass(MUTE) || target.hasClass(LOW_VOLUME) || target.hasClass(HIGH_VOLUME)) {
                    var muted = this.mute();
                    this.mute(!muted);
                }
            },
            _sliderDragging: function () {
                if (!this.media()) {
                    return;
                }
                this._isDragging = true;
            },
            _sliderDragChange: function (e) {
                var that = this;
                var slider = e.sender;
                var tzOffset = timeZoneSec * 1000;
                if (!this.media()) {
                    return;
                }
                that._sliderChangeFired = true;
                that._isDragging = false;
                if (!this.options.forwardSeek && slider.value() > this._seekBarLastPosition) {
                    setTimeout(function () {
                        slider.value(that._seekBarLastPosition);
                    }, 1);
                } else if (this._youTubeVideo) {
                    that._ytmedia.seekTo(that._timeToSec(e.value - tzOffset));
                } else {
                    that._media.currentTime = that._timeToSec(e.value - tzOffset);
                }
                that.trigger(TIMECHANGE);
                that._preventPlay = true;
            },
            _changeVolumeButtonImage: function (volume) {
                var volumeButton = this._volumeButton;
                var volumeElement = volumeButton.find('span');
                var cssClass = volumeElement.attr('class');
                cssClass = cssClass.substring(0, cssClass.lastIndexOf(' '));
                if (volume === 0) {
                    volumeElement.attr('class', cssClass + ' ' + MUTE);
                    volumeButton.attr('title', this.options.messages.unmute);
                    volumeButton.attr('aria-label', this.options.messages.unmute);
                } else if (volume > 0 && volume < 51) {
                    volumeElement.attr('class', cssClass + ' ' + LOW_VOLUME);
                    volumeButton.attr('title', this.options.messages.mute);
                    volumeButton.attr('aria-label', this.options.messages.mute);
                } else {
                    volumeElement.attr('class', cssClass + ' ' + HIGH_VOLUME);
                    volumeButton.attr('title', this.options.messages.mute);
                    volumeButton.attr('aria-label', this.options.messages.mute);
                }
            },
            _volumeDragging: function (e) {
                if (!this.media()) {
                    return;
                }
                this.volume(e.value);
                this._changeVolumeButtonImage(e.value);
                this.trigger(VOLUMECHANGE);
            },
            _volumeChange: function (e) {
                if (!this.media()) {
                    return;
                }
                this.volume(e.value);
                this._changeVolumeButtonImage(e.value);
                this.trigger(VOLUMECHANGE);
            },
            _mediaTimeUpdate: function () {
                var currentTime = this._youTubeVideo ? this._ytmedia.getCurrentTime() : this._media.currentTime;
                var timeInMs = this._msToTime(currentTime);
                this._currentTimeElement.text(kendo.toString(timeInMs, this._timeFormat));
                if (!this._isDragging) {
                    this._seekBarLastPosition = (currentTime + timeZoneSec) * 1000;
                    this._slider.value(this._seekBarLastPosition);
                }
                return this.isPlaying();
            },
            _playStateToggle: function (play) {
                if (typeof play === 'undefined') {
                    play = this._playButtonSpan.is(DOT + STATE_PLAY);
                }
                if (play) {
                    this._playButtonSpan.removeClass(STATE_PLAY).addClass(STATE_PAUSE);
                    this._playButton.attr('title', this.options.messages.pause);
                    this._playButton.attr('aria-label', this.options.messages.pause);
                } else {
                    this._playButtonSpan.removeClass(STATE_PAUSE).addClass(STATE_PLAY);
                    this._playButton.attr('title', this.options.messages.play);
                    this._playButton.attr('aria-label', this.options.messages.play);
                }
            },
            _mediaEnded: function () {
                this._playStateToggle(false);
                this._currentTimeElement.text(kendo.toString(this._msToTime(0), this._timeFormat));
                this._slider.value((0 + timeZoneSec) * 1000);
                this.trigger(END);
            },
            _mediaPlay: function () {
                this.trigger(PLAY);
            },
            _mediaReady: function () {
                this.trigger(READY);
            },
            _mediaDurationChange: function () {
                var durationTime = this._msToTime(this._youTubeVideo ? this._ytmedia.getDuration() : this._media.duration);
                this._timeFormat = durationTime.getHours() === 0 ? timeFormats.shortTime : timeFormats.longTime;
                this._durationElement.text(kendo.toString(durationTime, this._timeFormat));
                this._slider.setOptions({
                    min: baseTime.getTime(),
                    max: durationTime.getTime()
                });
                if (!this._isFirstRun) {
                    this._resetTime();
                    this._isFirstRun = true;
                }
            },
            _createYoutubePlayer: function () {
                this._mediaTimeUpdateHandler = proxy(this._mediaTimeUpdate, this);
                this._mediaDurationChangeHandler = proxy(this._mediaDurationChange, this);
                this.wrapper.prepend(templates.youtubePlayer);
                this._ytPlayer = this.wrapper.find(DOT + YTPLAYER)[0];
                $(this._ytPlayer).css({
                    width: this.wrapper.width(),
                    height: this.wrapper.height()
                });
                if (!window.YT || !window.YT.Player) {
                    if (!window.onYouTubeIframeAPIReadyRegister) {
                        window.onYouTubeIframeAPIReadyRegister = [];
                        $.getScript('https://www.youtube.com/iframe_api');
                        window.onYouTubeIframeAPIReady = function () {
                            if (window.onYouTubeIframeAPIReadyRegister) {
                                for (var i = 0; i < window.onYouTubeIframeAPIReadyRegister.length; i++) {
                                    window.onYouTubeIframeAPIReadyRegister[i]._youtubeApiReady();
                                }
                            }
                            window.onYouTubeIframeAPIReadyRegister.length = 0;
                            window.onYouTubeIframeAPIReadyRegister = undefined;
                        };
                    }
                    window.onYouTubeIframeAPIReadyRegister[window.onYouTubeIframeAPIReadyRegister.length] = this;
                } else {
                    this._configurePlayer();
                }
            },
            _poll: function (name, callback, interval, context) {
                var that = this;
                if (that._timers[name] !== null) {
                    clearTimeout(that._timers[name]);
                }
                that._timers[name] = setTimeout(function (context) {
                    return function callLater() {
                        if (callback.call(context)) {
                            that._timers[name] = setTimeout(callLater, interval);
                        }
                    };
                }(context), interval);
                return that._timers[name];
            },
            _youtubeApiReady: function () {
                this._configurePlayer();
            },
            _configurePlayer: function () {
                var vars = {
                    'autoplay': +this.options.autoPlay,
                    'wmode': 'transparent',
                    'controls': 0,
                    'rel': 0,
                    'showinfo': 0
                };
                this._onYouTubePlayerReady = proxy(this._onYouTubePlayerReady, this);
                window.onYouTubePlayerReady = this._onYouTubePlayerReady;
                this._onPlayerStateChangeHandler = proxy(this._onPlayerStateChange, this);
                window.onPlayerStateChange = this._onPlayerStateChange;
                var player = new window.YT.Player(this.wrapper.find(DOT + YTPLAYER)[0], {
                    height: this.wrapper.height(),
                    width: this.wrapper.width(),
                    videoId: this._getMediaId(),
                    playerVars: vars,
                    events: {
                        'onReady': this._onYouTubePlayerReady,
                        'onStateChange': this._onPlayerStateChangeHandler
                    }
                });
            },
            _onYouTubePlayerReady: function (event) {
                this._ytmedia = event.target;
                this._ytmedia.getIframe().style.width = '100%';
                this._ytmedia.getIframe().style.height = '100%';
                this._youTubeVideo = true;
                this._mediaDurationChangeHandler();
                if (this.options.autoPlay) {
                    this._playStateToggle(true);
                    this._ytmedia.loadVideoById(this._getMediaId());
                } else {
                    this._ytmedia.cueVideoById(this._getMediaId());
                }
                if (this.options.mute) {
                    this.mute(true);
                }
                this.trigger(READY);
            },
            _updateTitle: function () {
                this.titlebar().text(this.media().title || this.media().source);
            },
            _onPlayerStateChange: function (event) {
                if (event.data === 0) {
                    this._slider.value(0);
                    this._paused = false;
                    this._playStateToggle(true);
                    this.trigger(END);
                    if (this.options.autoRepeat) {
                        this.play();
                    }
                } else if (event.data === 1) {
                    this._mediaDurationChange();
                    this._ytmedia.setVolume(this.volume());
                    if (this._sliderChangeFired) {
                        this._sliderChangeFired = false;
                    } else {
                        this._uiDisplay(false);
                    }
                    this.trigger(PLAY);
                    this._playStateToggle(true);
                    this._poll('progress', this._mediaTimeUpdate, 500, this);
                    this._paused = false;
                } else if (event.data === 2) {
                    if (!this._paused) {
                        this._uiDisplay(true);
                        this._playStateToggle(false);
                        this.trigger(PAUSE);
                        this._paused = true;
                    }
                }
            },
            _getMediaId: function () {
                var result = this._currentUrl();
                var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
                var match = result.match(regExp);
                if (match && match[7].length === 11) {
                    result = match[7];
                }
                return result;
            },
            _mouseClick: function () {
                if (this.isPaused()) {
                    this.play();
                } else {
                    this.pause();
                }
            },
            _initializePlayer: function () {
                if (!this._mouseMoveHandler) {
                    this._mouseMoveHandler = proxy(this._mouseMove, this);
                    this._mouseInHandler = proxy(this._mouseIn, this);
                    this._mouseOutHandler = proxy(this._mouseOut, this);
                    $(this.wrapper).on('mouseenter' + ns, this._mouseInHandler).on('mouseleave' + ns, this._mouseOutHandler).on('mousemove' + ns, this._mouseMoveHandler);
                }
                if (!this._ytmedia && this._youTubeVideo) {
                    this._createYoutubePlayer();
                } else if (!this._media && !this._youTubeVideo) {
                    this._createHtmlPlayer();
                }
            },
            _createHtmlPlayer: function () {
                if (!this._videoOverlay) {
                    this._mouseClickHanlder = proxy(this._mouseClick, this);
                    this.wrapper.append('<div class=\'' + OVERLAY + '\'></div>');
                    this._videoOverlay = this.wrapper.find('.k-mediaplayer-overlay').on('click' + ns, this._mouseClickHanlder);
                }
                this._mediaTimeUpdateHandler = proxy(this._mediaTimeUpdate, this);
                this._mediaDurationChangeHandler = proxy(this._mediaDurationChange, this);
                this._mediaEndedHandler = proxy(this._mediaEnded, this);
                this._mediaCanPlayHandler = proxy(this._mediaReady, this);
                this._mediaPlayHandler = proxy(this._mediaPlay, this);
                this._videoOverlay.after(templates.htmlPlayer);
                this._media = this.wrapper.find(DOT + MEDIA)[0];
                $(this._media).css({
                    width: '100%',
                    height: '100%'
                });
                if (this.options.mute) {
                    this.mute(true);
                }
                this._media.ontimeupdate = this._mediaTimeUpdateHandler;
                this._media.ondurationchange = this._mediaDurationChangeHandler;
                this._media.oncanplay = this._mediaCanPlayHandler;
                this._media.onplay = this._mediaPlayHandler;
                this._media.onended = this._mediaEndedHandler;
            },
            _mouseIn: function () {
                this._uiDisplay(true);
            },
            _mouseOut: function () {
                this._poll('mouseIdle', this._mouseIdle, 3000, this);
            },
            _mouseIdle: function () {
                this._uiDisplay(false);
                return false;
            },
            _mouseMove: function () {
                if (!(this._titleBar.is(':animated') || this._toolBar.element.is(':animated') || this._slider.wrapper.is(':animated'))) {
                    this._uiDisplay(true);
                }
                this._poll('mouseIdle', this._mouseIdle, 3000, this);
            },
            _uiDisplay: function (state) {
                var animationSpeed = 'slow';
                var uiElements = this._titleBar.add(this._toolBar.element.parent());
                if (state) {
                    uiElements.fadeIn(animationSpeed);
                } else {
                    uiElements.fadeOut(animationSpeed);
                }
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (!this.isPaused()) {
                    this.pause();
                }
                this.element.off(ns);
                this.element.find(DOT + OVERLAY).off(ns);
                this._timers = null;
                this._mouseMoveHandler = null;
                this._mouseOutHandler = null;
                this._mouseInHandler = null;
                this._mouseClickHanlder = null;
                this._keyDownHandler = null;
                this._fullscreenHandler = null;
                this._toolbarClickHandler = null;
                this._sliderDragChangeHandler = null;
                this._sliderDraggingHandler = null;
                this._volumeDraggingHandler = null;
                this._volumeChangeHandler = null;
                this._youtubeApiReadyHandler = null;
                this._onYouTubePlayerReady = null;
                this._onPlayerStateChangeHandler = null;
                this._dropDownSelectHandler = null;
                if (this._youTubeVideo) {
                    this._ytmedia.destroy();
                } else {
                    this._media.ontimeupdate = this._mediaTimeUpdateHandler = null;
                    this._media.ondurationchange = this._mediaDurationChangeHandler = null;
                    this._media.oncanplay = this._mediaCanPlayHandler = null;
                    this._media.onplay = this._mediaPlayHandler = null;
                    this._media.onended = this._mediaEndedHandler = null;
                    this._media.src = '';
                    this._media.remove();
                }
                this._mouseMoveTimer = null;
                clearTimeout(this._mouseMoveTimer);
                kendo.destroy(this.element);
            },
            seek: function (ms) {
                if (typeof ms === 'undefined') {
                    return 1000 * this._youTubeVideo ? this._ytmedia.getCurrentTime() : this._media ? this._media.currentTime : 0;
                }
                var seconds = ms / 1000;
                if (this._youTubeVideo) {
                    if (seconds + 3 >= this._ytmedia.getDuration() | 0) {
                        this._ytmedia.seekTo(this._ytmedia.getDuration() - 3 | 0, true);
                    } else {
                        this._ytmedia.seekTo(seconds, true);
                    }
                } else {
                    this._media.currentTime = seconds;
                }
                return this;
            },
            play: function () {
                if (this._youTubeVideo) {
                    this._ytmedia.playVideo();
                } else {
                    this._uiDisplay(false);
                    this._media.play();
                }
                this._paused = false;
                this._playStateToggle(true);
                return this;
            },
            stop: function () {
                if (this._youTubeVideo && this._ytmedia) {
                    this._ytmedia.stopVideo();
                } else if (this._media && !this._youTubeVideo) {
                    this._uiDisplay(true);
                    this._media.pause();
                    this._media.currentTime = 0;
                }
                this._paused = true;
                this._playStateToggle(false);
                return this;
            },
            pause: function () {
                if (this._youTubeVideo) {
                    this._ytmedia.pauseVideo();
                } else {
                    this._uiDisplay(true);
                    this._media.pause();
                }
                this._paused = true;
                this._playStateToggle(false);
                this.trigger(PAUSE);
                return this;
            },
            toolbar: function () {
                return this._toolBar;
            },
            dropdown: function () {
                return this._dropDown;
            },
            titlebar: function () {
                return this._titleBar;
            },
            fullScreen: function (enterFullScreen) {
                if (typeof enterFullScreen === 'undefined') {
                    return this._isInFullScreen || false;
                }
                var element = this.element.get(0);
                if (enterFullScreen) {
                    this.element.addClass('k-mediaplayer-fullscreen');
                    if (element.requestFullscreen) {
                        element.requestFullscreen();
                    } else if (element.webkitRequestFullscreen) {
                        element.webkitRequestFullscreen();
                    } else if (element.mozRequestFullScreen) {
                        element.mozRequestFullScreen();
                    } else if (element.msRequestFullscreen) {
                        element.msRequestFullscreen();
                    }
                    this._isInFullScreen = true;
                } else {
                    if (document.cancelFullscreen) {
                        document.cancelFullscreen();
                    } else if (document.webkitCancelFullScreen) {
                        document.webkitCancelFullScreen();
                    } else if (document.mozCancelFullScreen) {
                        document.mozCancelFullScreen();
                    } else if (document.msCancelFullscreen) {
                        document.msCancelFullscreen();
                    } else if (document.exitFullscreen) {
                        document.exitFullscreen();
                    } else if (document.msExitFullscreen) {
                        document.msExitFullscreen();
                    }
                    this.element.removeClass('k-mediaplayer-fullscreen');
                    this._isInFullScreen = false;
                }
                this._slider.resize();
            },
            volume: function (value) {
                if (typeof value === 'undefined') {
                    return typeof this._volume !== 'undefined' ? this._volume : this._volume = this.options.volume;
                }
                this._volume = value;
                this.mute(value <= 0);
                if (this._youTubeVideo) {
                    this._ytmedia.setVolume(this._volume);
                } else {
                    this._media.volume = this._volume / 100;
                }
                this._volumeSlider.value(value);
            },
            mute: function (muted) {
                var currentState = this._youTubeVideo ? this._ytmedia && this._ytmedia.isMuted() : this._media && this._media.muted;
                if (typeof muted === 'undefined' || muted === currentState) {
                    return currentState;
                }
                if (this._youTubeVideo) {
                    if (muted) {
                        this._ytmedia.mute();
                    } else {
                        this._ytmedia.unMute();
                    }
                } else {
                    this._media.muted = muted;
                }
                if (muted) {
                    this._volumeSlider.value(0);
                } else {
                    this._volumeSlider.value(this._media && this._media.volume * 100 || this._ytmedia && this._ytmedia.getVolume());
                }
                this.trigger(VOLUMECHANGE);
                this._changeVolumeButtonImage(this._volumeSlider.value());
            },
            isEnded: function () {
                if (this._youTubeVideo) {
                    return this._ytmedia.getPlayerState() === 0;
                } else {
                    return this._media.ended;
                }
            },
            media: function (value) {
                var dropdown = this.dropdown();
                if (typeof value === 'undefined') {
                    return typeof this._mediaData !== 'undefined' ? this._mediaData : this._mediaData = this.options.media;
                }
                if (isArray(value.source)) {
                    dropdown.setDataSource(value.source);
                    dropdown.wrapper.show();
                } else {
                    dropdown.wrapper.hide();
                }
                this._mediaData = value;
                this._updateTitle();
                this._setPlayerUrl();
            },
            isPaused: function () {
                return this._paused;
            },
            isPlaying: function () {
                return !this.isEnded() && !this._paused;
            },
            _aria: function () {
                this.wrapper.attr('role', 'region');
            },
            _navigatable: function () {
                this._fullscreenHandler = proxy(this._fullscreen, this);
                $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange' + ns, this._fullscreenHandler);
                if (this.options.navigatable) {
                    this.wrapper.attr('tabIndex', 0);
                    this._keyDownHandler = proxy(this._keyDown, this);
                    this.wrapper.on('keydown' + ns, this._keyDownHandler);
                }
            },
            _fullscreen: function () {
                var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
                this._uiDisplay(true);
                this._slider.resize();
                if (!isFullScreen) {
                    this.wrapper.find('span[class*="k-i-fullscreen"]').removeClass(FULLSCREEN_EXIT).addClass(FULLSCREEN_ENTER);
                    this.fullScreen(false);
                }
            },
            _keyDown: function (e) {
                e.preventDefault();
                var fsButton = this.wrapper.find('span[class*="k-i-fullscreen"]');
                if (e.keyCode === keys.SPACEBAR) {
                    if (this.isPlaying()) {
                        this.pause();
                    } else {
                        this.play();
                    }
                } else if (e.keyCode === keys.ENTER && !this._isInFullScreen) {
                    fsButton.removeClass(FULLSCREEN_ENTER).addClass(FULLSCREEN_EXIT);
                    this.fullScreen(true);
                } else if (e.keyCode === 77) {
                    var muted = this.mute();
                    this.mute(!muted);
                } else if (e.keyCode === keys.ESC && this._isInFullScreen) {
                    fsButton.removeClass(FULLSCREEN_EXIT).addClass(FULLSCREEN_ENTER);
                    this.fullScreen(false);
                }
            },
            _error: function () {
            },
            _progress: function () {
            }
        });
        ui.plugin(MediaPlayer);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define === 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pivotgrid', [
        'kendo.dom',
        'kendo.data'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pivotgrid',
        name: 'PivotGrid',
        category: 'web',
        description: 'The PivotGrid widget is a data summarization tool.',
        depends: [
            'dom',
            'data',
            'data.xml',
            'sortable'
        ],
        features: [
            {
                id: 'pivotgrid-configurator',
                name: 'Configurator',
                description: 'The PivotConfigurator widget allows the user to select data slices displayed in PivotGrid',
                depends: ['pivot.configurator']
            },
            {
                id: 'pivotgrid-filtering',
                name: 'Filtering',
                description: 'Support for filtering',
                depends: ['pivot.fieldmenu']
            },
            {
                id: 'pivotgrid-excel-export',
                name: 'Excel export',
                description: 'Export pivot grid data as Excel spreadsheet',
                depends: ['ooxml']
            },
            {
                id: 'pivotgrid-pdf-export',
                name: 'PDF export',
                description: 'Export pivot grid data as PDF',
                depends: [
                    'pdf',
                    'drawing'
                ]
            },
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Class = kendo.Class, Widget = ui.Widget, DataSource = kendo.data.DataSource, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, toString = {}.toString, identity = function (o) {
                return o;
            }, map = $.map, extend = $.extend, isFunction = kendo.isFunction, CHANGE = 'change', ERROR = 'error', MEASURES = 'Measures', PROGRESS = 'progress', STATERESET = 'stateReset', AUTO = 'auto', DIV = '<div/>', NS = '.kendoPivotGrid', ROW_TOTAL_KEY = '__row_total__', DATABINDING = 'dataBinding', DATABOUND = 'dataBound', EXPANDMEMBER = 'expandMember', COLLAPSEMEMBER = 'collapseMember', STATE_EXPANDED = 'k-i-collapse', STATE_COLLAPSED = 'k-i-expand', HEADER_TEMPLATE = '<span>#: data.member.caption || data.member.name #</span>', KPISTATUS_TEMPLATE = '<span class="k-icon k-i-#=data.dataItem.value > 0 ? "circle" : data.dataItem.value < 0 ? "stop" : "arrow-60-up k-i-hold"#" title="#:data.dataItem.value#"></span>', KPITREND_TEMPLATE = '<span class="k-icon k-i-#=data.dataItem.value > 0 ? "arrow-60-up" : data.dataItem.value < 0 ? "arrow-60-down" : "minus"#" title="#:data.dataItem.value#"></span>', DATACELL_TEMPLATE = '#= data.dataItem ? kendo.htmlEncode(data.dataItem.fmtValue || data.dataItem.value) || "&nbsp;" : "&nbsp;" #', LAYOUT_TABLE = '<table class="k-pivot-layout">' + '<tr>' + '<td>' + '<div class="k-pivot-rowheaders"></div>' + '</td>' + '<td>' + '<div class="k-pivot-table k-state-default"></div>' + '</td>' + '</tr>' + '</table>';
        var AXIS_ROWS = 'rows';
        var AXIS_COLUMNS = 'columns';
        function normalizeMeasures(measure) {
            var descriptor = typeof measure === 'string' ? [{ name: measure }] : measure;
            var descriptors = toString.call(descriptor) === '[object Array]' ? descriptor : descriptor !== undefined ? [descriptor] : [];
            return map(descriptors, function (d) {
                if (typeof d === 'string') {
                    return { name: d };
                }
                return {
                    name: d.name,
                    type: d.type
                };
            });
        }
        function normalizeMembers(member) {
            var descriptor = typeof member === 'string' ? [{
                    name: [member],
                    expand: false
                }] : member;
            var descriptors = toString.call(descriptor) === '[object Array]' ? descriptor : descriptor !== undefined ? [descriptor] : [];
            return map(descriptors, function (d) {
                if (typeof d === 'string') {
                    return {
                        name: [d],
                        expand: false
                    };
                }
                return {
                    name: toString.call(d.name) === '[object Array]' ? d.name.slice() : [d.name],
                    expand: d.expand
                };
            });
        }
        function normalizeName(name) {
            if (name.indexOf(' ') !== -1) {
                name = '["' + name + '"]';
            }
            return name;
        }
        function accumulateMembers(accumulator, rootTuple, tuple, level) {
            var idx, length;
            var children;
            var member;
            if (!tuple) {
                tuple = rootTuple;
            }
            if (!level) {
                level = 0;
            }
            member = tuple.members[level];
            if (!member || member.measure) {
                return;
            }
            children = member.children;
            length = children.length;
            if (tuple === rootTuple) {
                accumulator[kendo.stringify([member.name])] = !!length;
            } else if (length) {
                accumulator[kendo.stringify(buildPath(tuple, level))] = true;
            }
            if (length) {
                for (idx = 0; idx < length; idx++) {
                    accumulateMembers(accumulator, rootTuple, children[idx], level);
                }
            }
            accumulateMembers(accumulator, rootTuple, tuple, level + 1);
        }
        function descriptorsForAxes(tuples) {
            var result = {};
            if (tuples.length) {
                accumulateMembers(result, tuples[0]);
            }
            var descriptors = [];
            for (var k in result) {
                descriptors.push({
                    name: $.parseJSON(k),
                    expand: result[k]
                });
            }
            return descriptors;
        }
        function addMissingPathMembers(members, axis) {
            var tuples = axis.tuples || [];
            var firstTuple = tuples[0];
            if (firstTuple && members.length < firstTuple.members.length) {
                var tupleMembers = firstTuple.members;
                for (var idx = 0; idx < tupleMembers.length; idx++) {
                    if (tupleMembers[idx].measure) {
                        continue;
                    }
                    var found = false;
                    for (var j = 0; j < members.length; j++) {
                        if (getName(members[j]).indexOf(tupleMembers[idx].hierarchy) === 0) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        members.push({
                            name: [tupleMembers[idx].name],
                            expand: false
                        });
                    }
                }
            }
        }
        function tupleToDescriptors(tuple) {
            var result = [];
            var members = tuple.members;
            for (var idx = 0; idx < members.length; idx++) {
                if (members[idx].measure) {
                    continue;
                }
                result.push({
                    name: [members[idx].name],
                    expand: members[idx].children.length > 0
                });
            }
            return result;
        }
        function descriptorsForMembers(axis, members, measures) {
            axis = axis || {};
            addMissingPathMembers(members, axis);
            if (measures.length > 1) {
                members.push({
                    name: MEASURES,
                    measure: true,
                    children: normalizeMembers(measures)
                });
            }
            var tupletoSearch = { members: members };
            if (axis.tuples) {
                var result = findExistingTuple(axis.tuples, tupletoSearch);
                if (result.tuple) {
                    members = tupleToDescriptors(result.tuple);
                }
            }
            return members;
        }
        function createAggregateGetter(m) {
            var measureGetter = kendo.getter(m.field, true);
            return function (aggregatorContext, state) {
                return m.aggregate(measureGetter(aggregatorContext.dataItem), state, aggregatorContext);
            };
        }
        function isNumber(val) {
            return typeof val === 'number' && !isNaN(val);
        }
        function isDate(val) {
            return val && val.getTime;
        }
        var functions = {
            sum: function (value, state) {
                var accumulator = state.accumulator;
                if (!isNumber(accumulator)) {
                    accumulator = value;
                } else if (isNumber(value)) {
                    accumulator += value;
                }
                return accumulator;
            },
            count: function (value, state) {
                return (state.accumulator || 0) + 1;
            },
            average: {
                aggregate: function (value, state) {
                    var accumulator = state.accumulator;
                    if (state.count === undefined) {
                        state.count = 0;
                    }
                    if (!isNumber(accumulator)) {
                        accumulator = value;
                    } else if (isNumber(value)) {
                        accumulator += value;
                    }
                    if (isNumber(value)) {
                        state.count++;
                    }
                    return accumulator;
                },
                result: function (state) {
                    var accumulator = state.accumulator;
                    if (isNumber(accumulator)) {
                        accumulator = accumulator / state.count;
                    }
                    return accumulator;
                }
            },
            max: function (value, state) {
                var accumulator = state.accumulator;
                if (!isNumber(accumulator) && !isDate(accumulator)) {
                    accumulator = value;
                }
                if (accumulator < value && (isNumber(value) || isDate(value))) {
                    accumulator = value;
                }
                return accumulator;
            },
            min: function (value, state) {
                var accumulator = state.accumulator;
                if (!isNumber(accumulator) && !isDate(accumulator)) {
                    accumulator = value;
                }
                if (accumulator > value && (isNumber(value) || isDate(value))) {
                    accumulator = value;
                }
                return accumulator;
            }
        };
        var PivotCubeBuilder = Class.extend({
            init: function (options) {
                this.options = extend({}, this.options, options);
                this.dimensions = this._normalizeDescriptors('field', this.options.dimensions);
                this.measures = this._normalizeDescriptors('name', this.options.measures);
            },
            _normalizeDescriptors: function (keyField, descriptors) {
                descriptors = descriptors || {};
                var fields = {};
                var field;
                if (toString.call(descriptors) === '[object Array]') {
                    for (var idx = 0, length = descriptors.length; idx < length; idx++) {
                        field = descriptors[idx];
                        if (typeof field === 'string') {
                            fields[field] = {};
                        } else if (field[keyField]) {
                            fields[field[keyField]] = field;
                        }
                    }
                    descriptors = fields;
                }
                return descriptors;
            },
            _rootTuples: function (rootNames, measureAggregators) {
                var aggregatorsLength = measureAggregators.length || 1;
                var dimensionsSchema = this.dimensions || [];
                var root, name, parts;
                var measureIdx = 0;
                var idx;
                var rootNamesLength = rootNames.length;
                var result = [];
                var keys = [];
                if (rootNamesLength || measureAggregators.length) {
                    for (measureIdx = 0; measureIdx < aggregatorsLength; measureIdx++) {
                        root = { members: [] };
                        for (idx = 0; idx < rootNamesLength; idx++) {
                            name = rootNames[idx];
                            parts = name.split('&');
                            root.members[root.members.length] = {
                                children: [],
                                caption: (dimensionsSchema[name] || {}).caption || 'All',
                                name: name,
                                levelName: name,
                                levelNum: '0',
                                hasChildren: true,
                                parentName: parts.length > 1 ? parts[0] : undefined,
                                hierarchy: name
                            };
                        }
                        if (aggregatorsLength > 1) {
                            root.members[root.members.length] = {
                                children: [],
                                caption: measureAggregators[measureIdx].caption,
                                name: measureAggregators[measureIdx].descriptor.name,
                                levelName: 'MEASURES',
                                levelNum: '0',
                                hasChildren: false,
                                parentName: undefined,
                                hierarchy: 'MEASURES'
                            };
                        }
                        result[result.length] = root;
                    }
                    keys.push(ROW_TOTAL_KEY);
                }
                return {
                    keys: keys,
                    tuples: result
                };
            },
            _expandedTuples: function (map, expanded, measureAggregators) {
                var aggregatorsLength = measureAggregators.length || 1;
                var dimensionsSchema = this.dimensions || [];
                var measureIdx;
                var tuple;
                var key;
                var mapItem;
                var current;
                var currentKeys;
                var accumulator = [];
                var accumulatorKeys = [];
                var memberInfo;
                var expandedNames;
                var parts;
                var name;
                var idx;
                for (key in map) {
                    mapItem = map[key];
                    memberInfo = this._findExpandedMember(expanded, mapItem.uniquePath);
                    current = accumulator[memberInfo.index] || [];
                    currentKeys = accumulatorKeys[memberInfo.index] || [];
                    expandedNames = memberInfo.member.names;
                    for (measureIdx = 0; measureIdx < aggregatorsLength; measureIdx++) {
                        tuple = { members: [] };
                        for (idx = 0; idx < expandedNames.length; idx++) {
                            if (idx === memberInfo.member.expandedIdx) {
                                tuple.members[tuple.members.length] = {
                                    children: [],
                                    caption: mapItem.value,
                                    name: mapItem.name,
                                    hasChildren: false,
                                    levelNum: 1,
                                    levelName: mapItem.parentName + mapItem.name,
                                    parentName: mapItem.parentName,
                                    hierarchy: mapItem.parentName + mapItem.name
                                };
                                if (measureIdx === 0) {
                                    currentKeys.push(buildPath(tuple, idx).join(''));
                                }
                            } else {
                                name = expandedNames[idx];
                                parts = name.split('&');
                                tuple.members[tuple.members.length] = {
                                    children: [],
                                    caption: (dimensionsSchema[name] || {}).caption || 'All',
                                    name: name,
                                    levelName: name,
                                    levelNum: '0',
                                    hasChildren: true,
                                    parentName: parts.length > 1 ? parts[0] : undefined,
                                    hierarchy: name
                                };
                            }
                        }
                        if (aggregatorsLength > 1) {
                            tuple.members[tuple.members.length] = {
                                children: [],
                                caption: measureAggregators[measureIdx].caption,
                                name: measureAggregators[measureIdx].descriptor.name,
                                levelName: 'MEASURES',
                                levelNum: '0',
                                hasChildren: true,
                                parentName: undefined,
                                hierarchy: 'MEASURES'
                            };
                        }
                        current[current.length] = tuple;
                    }
                    accumulator[memberInfo.index] = current;
                    accumulatorKeys[memberInfo.index] = currentKeys;
                }
                return {
                    keys: accumulatorKeys,
                    tuples: accumulator
                };
            },
            _findExpandedMember: function (members, parentName) {
                for (var idx = 0; idx < members.length; idx++) {
                    if (members[idx].uniquePath === parentName) {
                        return {
                            member: members[idx],
                            index: idx
                        };
                    }
                }
            },
            _asTuples: function (map, descriptor, measureAggregators) {
                measureAggregators = measureAggregators || [];
                var rootInfo = this._rootTuples(descriptor.root, measureAggregators);
                var expandedInfo = this._expandedTuples(map, descriptor.expanded, measureAggregators);
                return {
                    keys: [].concat.apply(rootInfo.keys, expandedInfo.keys),
                    tuples: [].concat.apply(rootInfo.tuples, expandedInfo.tuples)
                };
            },
            _measuresInfo: function (measures, rowAxis) {
                var idx = 0;
                var length = measures && measures.length;
                var aggregateNames = [];
                var resultFuncs = {};
                var formats = {};
                var descriptors = this.measures || {};
                var measure;
                var name;
                for (; idx < length; idx++) {
                    name = measures[idx].descriptor.name;
                    measure = descriptors[name] || {};
                    aggregateNames.push(name);
                    if (measure.result) {
                        resultFuncs[name] = measure.result;
                    }
                    if (measure.format) {
                        formats[name] = measure.format;
                    }
                }
                return {
                    names: aggregateNames,
                    formats: formats,
                    resultFuncs: resultFuncs,
                    rowAxis: rowAxis
                };
            },
            _toDataArray: function (map, measuresInfo, rowKeys, columnKeys) {
                var result = [];
                var aggregates;
                var name, i, j, k, n;
                var row, column, columnKey;
                var rowMeasureNamesLength = 1;
                var rowMeasureNames = [];
                var columnMeasureNames;
                var rowLength = rowKeys.length || 1;
                var columnLength = columnKeys.length || 1;
                if (measuresInfo.rowAxis) {
                    rowMeasureNames = measuresInfo.names;
                    rowMeasureNamesLength = rowMeasureNames.length;
                } else {
                    columnMeasureNames = measuresInfo.names;
                }
                for (i = 0; i < rowLength; i++) {
                    row = map[rowKeys[i] || ROW_TOTAL_KEY];
                    for (n = 0; n < rowMeasureNamesLength; n++) {
                        if (measuresInfo.rowAxis) {
                            columnMeasureNames = [rowMeasureNames[n]];
                        }
                        for (j = 0; j < columnLength; j++) {
                            columnKey = columnKeys[j] || ROW_TOTAL_KEY;
                            column = row.items[columnKey];
                            if (columnKey === ROW_TOTAL_KEY) {
                                aggregates = row.aggregates;
                            } else {
                                aggregates = column ? column.aggregates : {};
                            }
                            for (k = 0; k < columnMeasureNames.length; k++) {
                                name = columnMeasureNames[k];
                                this._addData(result, aggregates[name], measuresInfo.formats[name], measuresInfo.resultFuncs[name]);
                            }
                        }
                    }
                }
                return result;
            },
            _addData: function (result, value, format, resultFunc) {
                var fmtValue = '';
                var ordinal;
                if (value) {
                    value = resultFunc ? resultFunc(value) : value.accumulator;
                    fmtValue = format ? kendo.format(format, value) : value;
                }
                ordinal = result.length;
                result[ordinal] = {
                    ordinal: ordinal,
                    value: value || '',
                    fmtValue: fmtValue
                };
            },
            _matchDescriptors: function (dataItem, descriptor, getters) {
                var parts;
                var parentField;
                var expectedValue;
                var names = descriptor.names;
                var idx = descriptor.expandedIdx;
                var value;
                while (idx > 0) {
                    parts = names[--idx].split('&');
                    if (parts.length > 1) {
                        parentField = parts[0];
                        expectedValue = parts[1];
                        value = getters[parentField](dataItem);
                        value = value !== undefined && value !== null ? value.toString() : value;
                        if (value != expectedValue) {
                            return false;
                        }
                    }
                }
                return true;
            },
            _calculateAggregate: function (measureAggregators, aggregatorContext, totalItem) {
                var result = {};
                var state;
                var name;
                for (var measureIdx = 0; measureIdx < measureAggregators.length; measureIdx++) {
                    name = measureAggregators[measureIdx].descriptor.name;
                    state = totalItem.aggregates[name] || {};
                    state.accumulator = measureAggregators[measureIdx].aggregator(aggregatorContext, state);
                    result[name] = state;
                }
                return result;
            },
            _processColumns: function (measureAggregators, descriptors, getters, columns, aggregatorContext, rowTotal, state, updateColumn) {
                var value;
                var descriptor;
                var column;
                var totalItem;
                var key, name, parentName, path;
                var dataItem = aggregatorContext.dataItem;
                var idx = 0;
                for (; idx < descriptors.length; idx++) {
                    descriptor = descriptors[idx];
                    if (!this._matchDescriptors(dataItem, descriptor, getters)) {
                        continue;
                    }
                    path = descriptor.names.slice(0, descriptor.expandedIdx).join('');
                    name = descriptor.names[descriptor.expandedIdx];
                    value = getters[name](dataItem);
                    value = value !== undefined && value !== null ? value.toString() : value;
                    parentName = name;
                    name = name + '&' + value;
                    key = path + name;
                    column = columns[key] || {
                        index: state.columnIndex,
                        parentName: parentName,
                        name: name,
                        uniquePath: path + parentName,
                        value: value
                    };
                    totalItem = rowTotal.items[key] || { aggregates: {} };
                    rowTotal.items[key] = {
                        index: column.index,
                        aggregates: this._calculateAggregate(measureAggregators, aggregatorContext, totalItem)
                    };
                    if (updateColumn) {
                        if (!columns[key]) {
                            state.columnIndex++;
                        }
                        columns[key] = column;
                    }
                }
            },
            _measureAggregators: function (options) {
                var measureDescriptors = options.measures || [];
                var measures = this.measures || {};
                var aggregators = [];
                var descriptor, measure, idx, length;
                var defaultAggregate, aggregate;
                if (measureDescriptors.length) {
                    for (idx = 0, length = measureDescriptors.length; idx < length; idx++) {
                        descriptor = measureDescriptors[idx];
                        measure = measures[descriptor.name];
                        defaultAggregate = null;
                        if (measure) {
                            aggregate = measure.aggregate;
                            if (typeof aggregate === 'string') {
                                defaultAggregate = functions[aggregate.toLowerCase()];
                                if (!defaultAggregate) {
                                    throw new Error('There is no such aggregate function');
                                }
                                measure.aggregate = defaultAggregate.aggregate || defaultAggregate;
                                measure.result = defaultAggregate.result;
                            }
                            aggregators.push({
                                descriptor: descriptor,
                                caption: measure.caption,
                                result: measure.result,
                                aggregator: createAggregateGetter(measure)
                            });
                        }
                    }
                } else {
                    aggregators.push({
                        descriptor: { name: 'default' },
                        caption: 'default',
                        aggregator: function () {
                            return 1;
                        }
                    });
                }
                return aggregators;
            },
            _buildGetters: function (names) {
                var result = {};
                var parts;
                var name;
                for (var idx = 0; idx < names.length; idx++) {
                    name = names[idx];
                    parts = name.split('&');
                    if (parts.length > 1) {
                        result[parts[0]] = kendo.getter(parts[0], true);
                    } else {
                        result[name] = kendo.getter(normalizeName(name), true);
                    }
                }
                return result;
            },
            _parseDescriptors: function (descriptors) {
                var parsedDescriptors = parseDescriptors(descriptors);
                var rootNames = getRootNames(parsedDescriptors.root);
                var expanded = parsedDescriptors.expanded;
                var result = [];
                for (var idx = 0; idx < expanded.length; idx++) {
                    result.push(mapNames(expanded[idx].name, rootNames));
                }
                return {
                    root: rootNames,
                    expanded: result
                };
            },
            _filter: function (data, filter) {
                if (!filter) {
                    return data;
                }
                var expr;
                var idx = 0;
                var filters = filter.filters;
                for (; idx < filters.length; idx++) {
                    expr = filters[idx];
                    if (expr.operator === 'in') {
                        filters[idx] = this._normalizeFilter(expr);
                    }
                }
                return new kendo.data.Query(data).filter(filter).data;
            },
            _normalizeFilter: function (filter) {
                var value = filter.value.split(',');
                var result = [];
                if (!value.length) {
                    return value;
                }
                for (var idx = 0; idx < value.length; idx++) {
                    result.push({
                        field: filter.field,
                        operator: 'eq',
                        value: value[idx]
                    });
                }
                return {
                    logic: 'or',
                    filters: result
                };
            },
            process: function (data, options) {
                data = data || [];
                options = options || {};
                data = this._filter(data, options.filter);
                var measures = options.measures || [];
                var measuresRowAxis = options.measuresAxis === 'rows';
                var columnDescriptors = options.columns || [];
                var rowDescriptors = options.rows || [];
                if (!columnDescriptors.length && rowDescriptors.length && (!measures.length || measures.length && measuresRowAxis)) {
                    columnDescriptors = rowDescriptors;
                    rowDescriptors = [];
                    measuresRowAxis = false;
                }
                if (!columnDescriptors.length && !rowDescriptors.length) {
                    measuresRowAxis = false;
                }
                if (!columnDescriptors.length && measures.length) {
                    columnDescriptors = normalizeMembers(options.measures);
                }
                columnDescriptors = this._parseDescriptors(columnDescriptors);
                rowDescriptors = this._parseDescriptors(rowDescriptors);
                var aggregatedData = {};
                var columns = {};
                var rows = {};
                var rowValue;
                var state = { columnIndex: 0 };
                var measureAggregators = this._measureAggregators(options);
                var columnGetters = this._buildGetters(columnDescriptors.root);
                var rowGetters = this._buildGetters(rowDescriptors.root);
                var processed = false;
                var expandedColumns = columnDescriptors.expanded;
                var expandedRows = rowDescriptors.expanded;
                var dataItem;
                var aggregatorContext;
                var hasExpandedRows = expandedRows.length !== 0;
                var rowIdx, rowDescriptor, rowName, rowTotal;
                var key, path, parentName, value;
                var columnsInfo, rowsInfo;
                var length = data.length;
                var idx = 0;
                if (columnDescriptors.root.length || rowDescriptors.root.length) {
                    processed = true;
                    for (idx = 0; idx < length; idx++) {
                        dataItem = data[idx];
                        aggregatorContext = {
                            dataItem: dataItem,
                            index: idx
                        };
                        rowTotal = aggregatedData[ROW_TOTAL_KEY] || {
                            items: {},
                            aggregates: {}
                        };
                        this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, rowTotal, state, !hasExpandedRows);
                        rowTotal.aggregates = this._calculateAggregate(measureAggregators, aggregatorContext, rowTotal);
                        aggregatedData[ROW_TOTAL_KEY] = rowTotal;
                        for (rowIdx = 0; rowIdx < expandedRows.length; rowIdx++) {
                            rowDescriptor = expandedRows[rowIdx];
                            if (!this._matchDescriptors(dataItem, rowDescriptor, rowGetters)) {
                                this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, {
                                    items: {},
                                    aggregates: {}
                                }, state, true);
                                continue;
                            }
                            path = rowDescriptor.names.slice(0, rowDescriptor.expandedIdx).join('');
                            rowName = rowDescriptor.names[rowDescriptor.expandedIdx];
                            parentName = rowName;
                            rowValue = rowGetters[rowName](dataItem);
                            rowValue = rowValue !== undefined ? rowValue.toString() : rowValue;
                            rowName = rowName + '&' + rowValue;
                            key = path + rowName;
                            rows[key] = {
                                uniquePath: path + parentName,
                                parentName: parentName,
                                name: rowName,
                                value: rowValue
                            };
                            value = aggregatedData[key] || {
                                items: {},
                                aggregates: {}
                            };
                            this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, value, state, true);
                            value.aggregates = this._calculateAggregate(measureAggregators, aggregatorContext, value);
                            aggregatedData[key] = value;
                        }
                    }
                }
                if (processed && length) {
                    if (measureAggregators.length > 1 && (!options.columns || !options.columns.length)) {
                        columnDescriptors = {
                            root: [],
                            expanded: []
                        };
                    }
                    columnsInfo = this._asTuples(columns, columnDescriptors, measuresRowAxis ? [] : measureAggregators);
                    rowsInfo = this._asTuples(rows, rowDescriptors, measuresRowAxis ? measureAggregators : []);
                    columns = columnsInfo.tuples;
                    rows = rowsInfo.tuples;
                    aggregatedData = this._toDataArray(aggregatedData, this._measuresInfo(measureAggregators, measuresRowAxis), rowsInfo.keys, columnsInfo.keys);
                } else {
                    aggregatedData = columns = rows = [];
                }
                return {
                    axes: {
                        columns: { tuples: columns },
                        rows: { tuples: rows }
                    },
                    data: aggregatedData
                };
            }
        });
        var PivotTransport = Class.extend({
            init: function (options, transport) {
                this.transport = transport;
                this.options = transport.options || {};
                if (!this.transport.discover) {
                    if (isFunction(options.discover)) {
                        this.discover = options.discover;
                    }
                }
            },
            read: function (options) {
                return this.transport.read(options);
            },
            update: function (options) {
                return this.transport.update(options);
            },
            create: function (options) {
                return this.transport.create(options);
            },
            destroy: function (options) {
                return this.transport.destroy(options);
            },
            discover: function (options) {
                if (this.transport.discover) {
                    return this.transport.discover(options);
                }
                options.success({});
            },
            catalog: function (val) {
                var options = this.options || {};
                if (val === undefined) {
                    return (options.connection || {}).catalog;
                }
                var connection = options.connection || {};
                connection.catalog = val;
                this.options.connection = connection;
                $.extend(this.transport.options, { connection: connection });
            },
            cube: function (val) {
                var options = this.options || {};
                if (val === undefined) {
                    return (options.connection || {}).cube;
                }
                var connection = options.connection || {};
                connection.cube = val;
                this.options.connection = connection;
                extend(true, this.transport.options, { connection: connection });
            }
        });
        var PivotDataSource = DataSource.extend({
            init: function (options) {
                var cube = ((options || {}).schema || {}).cube;
                var measuresAxis = 'columns';
                var measures;
                var schema = {
                    axes: identity,
                    cubes: identity,
                    catalogs: identity,
                    measures: identity,
                    dimensions: identity,
                    hierarchies: identity,
                    levels: identity,
                    members: identity
                };
                if (cube) {
                    schema = $.extend(schema, this._cubeSchema(cube));
                    this.cubeBuilder = new PivotCubeBuilder(cube);
                }
                DataSource.fn.init.call(this, extend(true, {}, { schema: schema }, options));
                this.transport = new PivotTransport(this.options.transport || {}, this.transport);
                this._columns = normalizeMembers(this.options.columns);
                this._rows = normalizeMembers(this.options.rows);
                measures = this.options.measures || [];
                if (toString.call(measures) === '[object Object]') {
                    measuresAxis = measures.axis || 'columns';
                    measures = measures.values || [];
                }
                this._measures = normalizeMeasures(measures);
                this._measuresAxis = measuresAxis;
                this._skipNormalize = 0;
                this._axes = {};
            },
            _cubeSchema: function (cube) {
                return {
                    dimensions: function () {
                        var result = [];
                        var dimensions = cube.dimensions;
                        for (var key in dimensions) {
                            result.push({
                                name: key,
                                caption: dimensions[key].caption || key,
                                uniqueName: key,
                                defaultHierarchy: key,
                                type: 1
                            });
                        }
                        if (cube.measures) {
                            result.push({
                                name: MEASURES,
                                caption: MEASURES,
                                uniqueName: MEASURES,
                                type: 2
                            });
                        }
                        return result;
                    },
                    hierarchies: function () {
                        return [];
                    },
                    measures: function () {
                        var result = [];
                        var measures = cube.measures;
                        for (var key in measures) {
                            result.push({
                                name: key,
                                caption: key,
                                uniqueName: key,
                                aggregator: key
                            });
                        }
                        return result;
                    },
                    members: $.proxy(function (response, restrictions) {
                        var name = restrictions.levelUniqueName || restrictions.memberUniqueName;
                        var schemaData = this.options.schema.data;
                        var dataGetter = isFunction(schemaData) ? schemaData : kendo.getter(schemaData, true);
                        var data = this.options.data && dataGetter(this.options.data) || this._rawData || [];
                        var result = [];
                        var getter;
                        var value;
                        var idx = 0;
                        var distinct = {};
                        if (name) {
                            name = name.split('.')[0];
                        }
                        if (!restrictions.treeOp) {
                            result.push({
                                caption: cube.dimensions[name].caption || name,
                                childrenCardinality: '1',
                                dimensionUniqueName: name,
                                hierarchyUniqueName: name,
                                levelUniqueName: name,
                                name: name,
                                uniqueName: name
                            });
                            return result;
                        }
                        getter = kendo.getter(normalizeName(name), true);
                        for (; idx < data.length; idx++) {
                            value = getter(data[idx]);
                            if ((value || value === 0) && !distinct[value]) {
                                distinct[value] = true;
                                result.push({
                                    caption: value,
                                    childrenCardinality: '0',
                                    dimensionUniqueName: name,
                                    hierarchyUniqueName: name,
                                    levelUniqueName: name,
                                    name: value,
                                    uniqueName: value
                                });
                            }
                        }
                        return result;
                    }, this)
                };
            },
            options: {
                serverSorting: true,
                serverPaging: true,
                serverFiltering: true,
                serverGrouping: true,
                serverAggregates: true
            },
            catalog: function (val) {
                if (val === undefined) {
                    return this.transport.catalog();
                }
                this.transport.catalog(val);
                this._mergeState({});
                this._axes = {};
                this.data([]);
            },
            cube: function (val) {
                if (val === undefined) {
                    return this.transport.cube();
                }
                this.transport.cube(val);
                this._axes = {};
                this._mergeState({});
                this.data([]);
            },
            axes: function () {
                return this._axes;
            },
            columns: function (val) {
                if (val === undefined) {
                    return this._columns;
                }
                this._skipNormalize += 1;
                this._clearAxesData = true;
                this._columns = normalizeMembers(val);
                this.query({
                    columns: val,
                    rows: this.rowsAxisDescriptors(),
                    measures: this.measures(),
                    sort: this.sort(),
                    filter: this.filter()
                });
            },
            rows: function (val) {
                if (val === undefined) {
                    return this._rows;
                }
                this._skipNormalize += 1;
                this._clearAxesData = true;
                this._rows = normalizeMembers(val);
                this.query({
                    columns: this.columnsAxisDescriptors(),
                    rows: val,
                    measures: this.measures(),
                    sort: this.sort(),
                    filter: this.filter()
                });
            },
            measures: function (val) {
                if (val === undefined) {
                    return this._measures;
                }
                this._skipNormalize += 1;
                this._clearAxesData = true;
                this.query({
                    columns: this.columnsAxisDescriptors(),
                    rows: this.rowsAxisDescriptors(),
                    measures: normalizeMeasures(val),
                    sort: this.sort(),
                    filter: this.filter()
                });
            },
            measuresAxis: function () {
                return this._measuresAxis || 'columns';
            },
            _expandPath: function (path, axis) {
                var origin = axis === 'columns' ? 'columns' : 'rows';
                var other = axis === 'columns' ? 'rows' : 'columns';
                var members = normalizeMembers(path);
                var memberToExpand = getName(members[members.length - 1]);
                this._lastExpanded = origin;
                members = descriptorsForMembers(this.axes()[origin], members, this.measures());
                for (var idx = 0; idx < members.length; idx++) {
                    var memberName = getName(members[idx]);
                    if (memberName === memberToExpand) {
                        if (members[idx].expand) {
                            return;
                        }
                        members[idx].expand = true;
                    } else {
                        members[idx].expand = false;
                    }
                }
                var descriptors = {};
                descriptors[origin] = members;
                descriptors[other] = this._descriptorsForAxis(other);
                this._query(descriptors);
            },
            _descriptorsForAxis: function (axis) {
                var axes = this.axes();
                var descriptors = this[axis]() || [];
                if (axes && axes[axis] && axes[axis].tuples && axes[axis].tuples[0]) {
                    descriptors = descriptorsForAxes(axes[axis].tuples || []);
                }
                return descriptors;
            },
            columnsAxisDescriptors: function () {
                return this._descriptorsForAxis('columns');
            },
            rowsAxisDescriptors: function () {
                return this._descriptorsForAxis('rows');
            },
            _process: function (data, e) {
                this._view = data;
                e = e || {};
                e.items = e.items || this._view;
                this.trigger(CHANGE, e);
            },
            _query: function (options) {
                var that = this;
                if (!options) {
                    this._skipNormalize += 1;
                    this._clearAxesData = true;
                }
                return that.query(extend({}, {
                    page: that.page(),
                    pageSize: that.pageSize(),
                    sort: that.sort(),
                    filter: that.filter(),
                    group: that.group(),
                    aggregate: that.aggregate(),
                    columns: this.columnsAxisDescriptors(),
                    rows: this.rowsAxisDescriptors(),
                    measures: this.measures()
                }, options));
            },
            query: function (options) {
                var state = this._mergeState(options);
                if (this._data.length && this.cubeBuilder) {
                    this._params(state);
                    this._updateLocalData(this._pristineData);
                    return $.Deferred().resolve().promise();
                }
                return this.read(state);
            },
            _mergeState: function (options) {
                options = DataSource.fn._mergeState.call(this, options);
                if (options !== undefined) {
                    this._measures = normalizeMeasures(options.measures);
                    if (options.columns) {
                        options.columns = normalizeMembers(options.columns);
                    } else if (!options.columns) {
                        this._columns = [];
                    }
                    if (options.rows) {
                        options.rows = normalizeMembers(options.rows);
                    } else if (!options.rows) {
                        this._rows = [];
                    }
                }
                return options;
            },
            filter: function (val) {
                if (val === undefined) {
                    return this._filter;
                }
                this._skipNormalize += 1;
                this._clearAxesData = true;
                this._query({
                    filter: val,
                    page: 1
                });
            },
            expandColumn: function (path) {
                this._expandPath(path, 'columns');
            },
            expandRow: function (path) {
                this._expandPath(path, 'rows');
            },
            success: function (data) {
                var originalData;
                if (this.cubeBuilder) {
                    originalData = (this.reader.data(data) || []).slice(0);
                }
                DataSource.fn.success.call(this, data);
                if (originalData) {
                    this._pristineData = originalData;
                }
            },
            _processResult: function (data, axes) {
                if (this.cubeBuilder) {
                    var processedData = this.cubeBuilder.process(data, this._requestData);
                    data = processedData.data;
                    axes = processedData.axes;
                }
                var columnIndexes, rowIndexes;
                var tuples, resultAxis, measures, axisToSkip;
                var columnDescriptors = this.columns();
                var rowDescriptors = this.rows();
                var hasColumnTuples = axes.columns && axes.columns.tuples;
                if (!columnDescriptors.length && rowDescriptors.length && hasColumnTuples && (this._rowMeasures().length || !this.measures().length)) {
                    axes = {
                        columns: {},
                        rows: axes.columns
                    };
                }
                if (!columnDescriptors.length && !rowDescriptors.length && this.measuresAxis() === 'rows' && hasColumnTuples) {
                    axes = {
                        columns: {},
                        rows: axes.columns
                    };
                }
                this._axes = {
                    columns: normalizeAxis(this._axes.columns),
                    rows: normalizeAxis(this._axes.rows)
                };
                axes = {
                    columns: normalizeAxis(axes.columns),
                    rows: normalizeAxis(axes.rows)
                };
                columnIndexes = this._normalizeTuples(axes.columns.tuples, this._axes.columns.tuples, columnDescriptors, this._columnMeasures());
                rowIndexes = this._normalizeTuples(axes.rows.tuples, this._axes.rows.tuples, rowDescriptors, this._rowMeasures());
                this._skipNormalize -= 1;
                if (!this.cubeBuilder) {
                    data = this._normalizeData({
                        columnsLength: axes.columns.tuples.length,
                        rowsLength: axes.rows.tuples.length,
                        columnIndexes: columnIndexes,
                        rowIndexes: rowIndexes,
                        data: data
                    });
                }
                if (this._lastExpanded == 'rows') {
                    tuples = axes.columns.tuples;
                    measures = this._columnMeasures();
                    resultAxis = validateAxis(axes.columns, this._axes.columns, measures);
                    if (resultAxis) {
                        axisToSkip = 'columns';
                        axes.columns = resultAxis;
                        adjustDataByColumn(tuples, resultAxis.tuples, axes.rows.tuples.length, measures, data);
                        if (!this.cubeBuilder) {
                            data = this._normalizeData({
                                columnsLength: membersCount(axes.columns.tuples, measures),
                                rowsLength: axes.rows.tuples.length,
                                data: data
                            });
                        }
                    }
                } else if (this._lastExpanded == 'columns') {
                    tuples = axes.rows.tuples;
                    measures = this._rowMeasures();
                    resultAxis = validateAxis(axes.rows, this._axes.rows, measures);
                    if (resultAxis) {
                        axisToSkip = 'rows';
                        axes.rows = resultAxis;
                        adjustDataByRow(tuples, resultAxis.tuples, axes.columns.tuples.length, measures, data);
                        if (!this.cubeBuilder) {
                            data = this._normalizeData({
                                columnsLength: membersCount(axes.rows.tuples, measures),
                                rowsLength: axes.columns.tuples.length,
                                data: data
                            });
                        }
                    }
                }
                this._lastExpanded = null;
                var result = this._mergeAxes(axes, data, axisToSkip);
                this._axes = result.axes;
                return result.data;
            },
            _readData: function (data) {
                var axes = this.reader.axes(data);
                var newData = this.reader.data(data);
                if (this.cubeBuilder) {
                    this._rawData = newData;
                }
                return this._processResult(newData, axes);
            },
            _createTuple: function (tuple, measure, buildRoot) {
                var members = tuple.members;
                var length = members.length;
                var root = { members: [] };
                var levelName, levelNum;
                var name, parentName;
                var hasChildren;
                var hierarchy;
                var caption;
                var member;
                var idx = 0;
                if (measure) {
                    length -= 1;
                }
                for (; idx < length; idx++) {
                    member = members[idx];
                    levelNum = Number(member.levelNum);
                    name = member.name;
                    parentName = member.parentName;
                    caption = member.caption || name;
                    hasChildren = member.hasChildren;
                    hierarchy = member.hierarchy;
                    levelName = member.levelName;
                    if (buildRoot) {
                        caption = 'All';
                        if (levelNum === 0) {
                            parentName = member.name;
                        } else {
                            levelNum -= 1;
                        }
                        hasChildren = true;
                        name = hierarchy = levelName = parentName;
                    }
                    root.members.push({
                        name: name,
                        children: [],
                        caption: caption,
                        levelName: levelName,
                        levelNum: levelNum.toString(),
                        hasChildren: hasChildren,
                        hierarchy: hierarchy,
                        parentName: !buildRoot ? parentName : ''
                    });
                }
                if (measure) {
                    root.members.push({
                        name: measure.name,
                        children: []
                    });
                }
                return root;
            },
            _hasRoot: function (target, source, descriptors) {
                if (source.length) {
                    return findExistingTuple(source, target).tuple;
                }
                var members = target.members;
                var member;
                var descriptor;
                var isRoot = true;
                var levelNum;
                for (var idx = 0, length = members.length; idx < length; idx++) {
                    member = members[idx];
                    levelNum = Number(member.levelNum) || 0;
                    descriptor = descriptors[idx];
                    if (!(levelNum === 0 || descriptor && member.name === getName(descriptor))) {
                        isRoot = false;
                        break;
                    }
                }
                return isRoot;
            },
            _mergeAxes: function (sourceAxes, data, axisToSkip) {
                var columnMeasures = this._columnMeasures();
                var rowMeasures = this._rowMeasures();
                var axes = this.axes();
                var startIndex, tuples;
                var oldRowsLength = membersCount(axes.rows.tuples, rowMeasures);
                var newRowsLength = sourceAxes.rows.tuples.length;
                var oldColumnsLength = membersCount(axes.columns.tuples, columnMeasures);
                var newColumnsLength = sourceAxes.columns.tuples.length;
                if (axisToSkip == 'columns') {
                    newColumnsLength = oldColumnsLength;
                    tuples = sourceAxes.columns.tuples;
                } else {
                    tuples = parseSource(sourceAxes.columns.tuples, columnMeasures);
                    data = prepareDataOnColumns(tuples, data);
                }
                var mergedColumns = mergeTuples(axes.columns.tuples, tuples, columnMeasures);
                if (axisToSkip == 'rows') {
                    newRowsLength = membersCount(sourceAxes.rows.tuples, rowMeasures);
                    tuples = sourceAxes.rows.tuples;
                } else {
                    tuples = parseSource(sourceAxes.rows.tuples, rowMeasures);
                    data = prepareDataOnRows(tuples, data);
                }
                var mergedRows = mergeTuples(axes.rows.tuples, tuples, rowMeasures);
                axes.columns.tuples = mergedColumns.tuples;
                axes.rows.tuples = mergedRows.tuples;
                if (oldColumnsLength !== membersCount(axes.columns.tuples, columnMeasures)) {
                    startIndex = mergedColumns.index + findDataIndex(mergedColumns.parsedRoot, mergedColumns.memberIndex, columnMeasures);
                    var offset = oldColumnsLength + newColumnsLength;
                    data = this._mergeColumnData(data, startIndex, newRowsLength, newColumnsLength, offset);
                } else if (oldRowsLength !== membersCount(axes.rows.tuples, rowMeasures)) {
                    startIndex = mergedRows.index + findDataIndex(mergedRows.parsedRoot, mergedRows.memberIndex, rowMeasures);
                    data = this._mergeRowData(data, startIndex, newRowsLength, newColumnsLength);
                }
                if (axes.columns.tuples.length === 0 && axes.rows.tuples.length === 0) {
                    data = [];
                }
                return {
                    axes: axes,
                    data: data
                };
            },
            _mergeColumnData: function (newData, columnIndex, rowsLength, columnsLength, offset) {
                var data = this.data().toJSON();
                var rowIndex, index, drop = 0, toAdd;
                var columnMeasures = Math.max(this._columnMeasures().length, 1);
                rowsLength = Math.max(rowsLength, 1);
                if (data.length > 0) {
                    drop = columnMeasures;
                    offset -= columnMeasures;
                }
                for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
                    index = columnIndex + rowIndex * offset;
                    toAdd = newData.splice(0, columnsLength);
                    toAdd.splice(0, drop);
                    [].splice.apply(data, [
                        index,
                        0
                    ].concat(toAdd));
                }
                return data;
            },
            _mergeRowData: function (newData, rowIndex, rowsLength, columnsLength) {
                var data = this.data().toJSON();
                var idx, dataIndex, toAdd;
                var rowMeasures = Math.max(this._rowMeasures().length, 1);
                columnsLength = Math.max(columnsLength, 1);
                if (data.length > 0) {
                    rowsLength -= rowMeasures;
                    newData.splice(0, columnsLength * rowMeasures);
                }
                for (idx = 0; idx < rowsLength; idx++) {
                    toAdd = newData.splice(0, columnsLength);
                    dataIndex = rowIndex * columnsLength + idx * columnsLength;
                    [].splice.apply(data, [
                        dataIndex,
                        0
                    ].concat(toAdd));
                }
                return data;
            },
            _columnMeasures: function () {
                var measures = this.measures();
                var columnMeasures = [];
                if (this.measuresAxis() === 'columns') {
                    if (this.columns().length === 0) {
                        columnMeasures = measures;
                    } else if (measures.length > 1) {
                        columnMeasures = measures;
                    }
                }
                return columnMeasures;
            },
            _rowMeasures: function () {
                var measures = this.measures();
                var rowMeasures = [];
                if (this.measuresAxis() === 'rows') {
                    if (this.rows().length === 0) {
                        rowMeasures = measures;
                    } else if (measures.length > 1) {
                        rowMeasures = measures;
                    }
                }
                return rowMeasures;
            },
            _updateLocalData: function (data, state) {
                if (this.cubeBuilder) {
                    if (state) {
                        this._requestData = state;
                    }
                    data = this._processResult(data);
                }
                this._data = this._observe(data);
                this._ranges = [];
                this._addRange(this._data);
                this._total = this._data.length;
                this._pristineTotal = this._total;
                this._process(this._data);
            },
            data: function (value) {
                var that = this;
                if (value !== undefined) {
                    this._pristineData = value.slice(0);
                    this._updateLocalData(value, {
                        columns: this.columns(),
                        rows: this.rows(),
                        measures: this.measures()
                    });
                } else {
                    return that._data;
                }
            },
            _normalizeTuples: function (tuples, source, descriptors, measures) {
                var length = measures.length || 1;
                var idx = 0;
                var roots = [];
                var indexes = {};
                var measureIdx = 0;
                var tuple, memberIdx, last;
                if (!tuples.length) {
                    return;
                }
                if (this._skipNormalize <= 0 && !this._hasRoot(tuples[0], source, descriptors)) {
                    this._skipNormalize = 0;
                    for (; idx < length; idx++) {
                        roots.push(this._createTuple(tuples[0], measures[idx], true));
                        indexes[idx] = idx;
                    }
                    tuples.splice.apply(tuples, [
                        0,
                        tuples.length
                    ].concat(roots).concat(tuples));
                    idx = length;
                }
                if (measures.length) {
                    last = tuple = tuples[idx];
                    memberIdx = tuple.members.length - 1;
                    while (tuple) {
                        if (measureIdx >= length) {
                            measureIdx = 0;
                        }
                        if (tuple.members[memberIdx].name !== measures[measureIdx].name) {
                            tuples.splice(idx, 0, this._createTuple(tuple, measures[measureIdx]));
                            indexes[idx] = idx;
                        }
                        idx += 1;
                        measureIdx += 1;
                        tuple = tuples[idx];
                        if (length > measureIdx && (!tuple || tupleName(last, memberIdx - 1) !== tupleName(tuple, memberIdx - 1))) {
                            for (; measureIdx < length; measureIdx++) {
                                tuples.splice(idx, 0, this._createTuple(last, measures[measureIdx]));
                                indexes[idx] = idx;
                                idx += 1;
                            }
                            tuple = tuples[idx];
                        }
                        last = tuple;
                    }
                }
                return indexes;
            },
            _addMissingDataItems: function (result, metadata) {
                while (metadata.rowIndexes[parseInt(result.length / metadata.columnsLength, 10)] !== undefined) {
                    for (var idx = 0; idx < metadata.columnsLength; idx++) {
                        result = addEmptyDataItem(result);
                    }
                }
                while (metadata.columnIndexes[result.length % metadata.columnsLength] !== undefined) {
                    result = addEmptyDataItem(result);
                }
                return result;
            },
            _normalizeOrdinals: function (result, dataItem, metadata) {
                var lastOrdinal = metadata.lastOrdinal;
                if (!dataItem) {
                    return addEmptyDataItem(result);
                }
                if (dataItem.ordinal - lastOrdinal > 1) {
                    lastOrdinal += 1;
                    while (lastOrdinal < dataItem.ordinal && result.length < metadata.length) {
                        result = this._addMissingDataItems(addEmptyDataItem(result), metadata);
                        lastOrdinal += 1;
                    }
                }
                dataItem.ordinal = result.length;
                result[result.length] = dataItem;
                return result;
            },
            _normalizeData: function (options) {
                var data = options.data;
                var dataIdx = 0;
                var dataItem;
                var result = [];
                var lastOrdinal;
                var length;
                options.lastOrdinal = 0;
                options.columnIndexes = options.columnIndexes || {};
                options.rowIndexes = options.rowIndexes || {};
                options.columnsLength = options.columnsLength || 1;
                options.rowsLength = options.rowsLength || 1;
                options.length = options.columnsLength * options.rowsLength;
                length = options.length;
                if (data.length === length) {
                    return data;
                }
                while (result.length < length) {
                    dataItem = data[dataIdx++];
                    if (dataItem) {
                        lastOrdinal = dataItem.ordinal;
                    }
                    result = this._normalizeOrdinals(this._addMissingDataItems(result, options), dataItem, options);
                    options.lastOrdinal = lastOrdinal;
                }
                return result;
            },
            discover: function (options, converter) {
                var that = this, transport = that.transport;
                return $.Deferred(function (deferred) {
                    transport.discover(extend({
                        success: function (response) {
                            response = that.reader.parse(response);
                            if (that._handleCustomErrors(response)) {
                                return;
                            }
                            if (converter) {
                                response = converter(response);
                            }
                            deferred.resolve(response);
                        },
                        error: function (response, status, error) {
                            deferred.reject(response);
                            that.error(response, status, error);
                        }
                    }, options));
                }).promise().done(function () {
                    that.trigger('schemaChange');
                });
            },
            schemaMeasures: function () {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaMeasures',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube()
                        }
                    }
                }, function (response) {
                    return that.reader.measures(response);
                });
            },
            schemaKPIs: function () {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaKPIs',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube()
                        }
                    }
                }, function (response) {
                    return that.reader.kpis(response);
                });
            },
            schemaDimensions: function () {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaDimensions',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube()
                        }
                    }
                }, function (response) {
                    return that.reader.dimensions(response);
                });
            },
            schemaHierarchies: function (dimensionName) {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaHierarchies',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube(),
                            dimensionUniqueName: dimensionName
                        }
                    }
                }, function (response) {
                    return that.reader.hierarchies(response);
                });
            },
            schemaLevels: function (hierarchyName) {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaLevels',
                        restrictions: {
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube(),
                            hierarchyUniqueName: hierarchyName
                        }
                    }
                }, function (response) {
                    return that.reader.levels(response);
                });
            },
            schemaCubes: function () {
                var that = this;
                return that.discover({
                    data: {
                        command: 'schemaCubes',
                        restrictions: { catalogName: that.transport.catalog() }
                    }
                }, function (response) {
                    return that.reader.cubes(response);
                });
            },
            schemaCatalogs: function () {
                var that = this;
                return that.discover({ data: { command: 'schemaCatalogs' } }, function (response) {
                    return that.reader.catalogs(response);
                });
            },
            schemaMembers: function (restrictions) {
                var that = this;
                var success = function (restrictions) {
                    return function (response) {
                        return that.reader.members(response, restrictions);
                    };
                }(restrictions);
                return that.discover({
                    data: {
                        command: 'schemaMembers',
                        restrictions: extend({
                            catalogName: that.transport.catalog(),
                            cubeName: that.transport.cube()
                        }, restrictions)
                    }
                }, success);
            },
            _params: function (data) {
                if (this._clearAxesData) {
                    this._axes = {};
                    this._data = this._observe([]);
                    this._clearAxesData = false;
                    this.trigger(STATERESET);
                }
                var options = DataSource.fn._params.call(this, data);
                options = extend({
                    measures: this.measures(),
                    measuresAxis: this.measuresAxis(),
                    columns: this.columns(),
                    rows: this.rows()
                }, options);
                if (this.cubeBuilder) {
                    this._requestData = options;
                }
                return options;
            }
        });
        function addEmptyDataItem(result) {
            result[result.length] = {
                value: '',
                fmtValue: '',
                ordinal: result.length
            };
            return result;
        }
        function validateAxis(newAxis, axis, measures) {
            if (newAxis.tuples.length < membersCount(axis.tuples, measures)) {
                return axis;
            }
            return;
        }
        function adjustDataByColumn(sourceTuples, targetTuples, rowsLength, measures, data) {
            var columnIdx, rowIdx, dataIdx;
            var columnsLength = sourceTuples.length;
            var targetColumnsLength = membersCount(targetTuples, measures);
            var measuresLength = measures.length || 1;
            for (rowIdx = 0; rowIdx < rowsLength; rowIdx++) {
                for (columnIdx = 0; columnIdx < columnsLength; columnIdx++) {
                    dataIdx = tupleIndex(sourceTuples[columnIdx], targetTuples) * measuresLength;
                    dataIdx += columnIdx % measuresLength;
                    data[rowIdx * columnsLength + columnIdx].ordinal = rowIdx * targetColumnsLength + dataIdx;
                }
            }
        }
        function adjustDataByRow(sourceTuples, targetTuples, columnsLength, measures, data) {
            var columnIdx, rowIdx, dataIdx;
            var rowsLength = sourceTuples.length;
            var measuresLength = measures.length || 1;
            for (rowIdx = 0; rowIdx < rowsLength; rowIdx++) {
                dataIdx = tupleIndex(sourceTuples[rowIdx], targetTuples);
                dataIdx *= measuresLength;
                dataIdx += rowIdx % measuresLength;
                for (columnIdx = 0; columnIdx < columnsLength; columnIdx++) {
                    data[rowIdx * columnsLength + columnIdx].ordinal = dataIdx * columnsLength + columnIdx;
                }
            }
        }
        function tupleIndex(tuple, collection) {
            return findExistingTuple(collection, tuple).index;
        }
        function membersCount(tuples, measures) {
            if (!tuples.length) {
                return 0;
            }
            var queue = tuples.slice();
            var current = queue.shift();
            var result = 1;
            while (current) {
                if (current.members) {
                    [].push.apply(queue, current.members);
                } else if (current.children) {
                    if (!current.measure) {
                        result += current.children.length;
                    }
                    [].push.apply(queue, current.children);
                }
                current = queue.shift();
            }
            if (measures.length) {
                result = result * measures.length;
            }
            return result;
        }
        function normalizeAxis(axis) {
            if (!axis) {
                axis = { tuples: [] };
            }
            if (!axis.tuples) {
                axis.tuples = [];
            }
            return axis;
        }
        function findDataIndex(tuple, memberIndex, measures) {
            if (!tuple) {
                return 0;
            }
            var measuresLength = Math.max(measures.length, 1);
            var tuples = tuple.members.slice(0, memberIndex);
            var counter = measuresLength;
            var current = tuples.shift();
            if (measuresLength > 1) {
                measuresLength += 1;
            }
            while (current) {
                if (current.name === MEASURES) {
                    counter += measuresLength;
                } else if (current.children) {
                    [].push.apply(tuples, current.children);
                } else {
                    counter++;
                    [].push.apply(tuples, current.members);
                }
                current = tuples.shift();
            }
            return counter;
        }
        function mergeTuples(target, source, measures) {
            if (!source[0]) {
                return {
                    parsedRoot: null,
                    tuples: target,
                    memberIndex: 0,
                    index: 0
                };
            }
            var result = findExistingTuple(target, source[0]);
            if (!result.tuple) {
                return {
                    parsedRoot: null,
                    tuples: source,
                    memberIndex: 0,
                    index: 0
                };
            }
            var targetMembers = result.tuple.members;
            var sourceMembers = source[0].members;
            var memberIndex = -1;
            if (targetMembers.length !== sourceMembers.length) {
                return {
                    parsedRoot: null,
                    tuples: source,
                    memberIndex: 0,
                    index: 0
                };
            }
            for (var idx = 0, length = targetMembers.length; idx < length; idx++) {
                if (!targetMembers[idx].measure && sourceMembers[idx].children[0]) {
                    if (memberIndex == -1 && sourceMembers[idx].children.length) {
                        memberIndex = idx;
                    }
                    targetMembers[idx].children = sourceMembers[idx].children;
                }
            }
            measures = Math.max(measures.length, 1);
            return {
                parsedRoot: result.tuple,
                index: result.index * measures,
                memberIndex: memberIndex,
                tuples: target
            };
        }
        function equalTuples(first, second) {
            var equal = true;
            var idx, length;
            first = first.members;
            second = second.members;
            for (idx = 0, length = first.length; idx < length; idx++) {
                if (first[idx].measure || second[idx].measure) {
                    continue;
                }
                equal = equal && getName(first[idx]) === getName(second[idx]);
            }
            return equal;
        }
        function findExistingTuple(tuples, toFind) {
            var idx, length, tuple, found, counter = 0;
            var memberIndex, membersLength, member;
            for (idx = 0, length = tuples.length; idx < length; idx++) {
                tuple = tuples[idx];
                if (equalTuples(tuple, toFind)) {
                    return {
                        tuple: tuple,
                        index: counter
                    };
                }
                counter++;
                for (memberIndex = 0, membersLength = tuple.members.length; memberIndex < membersLength; memberIndex++) {
                    member = tuple.members[memberIndex];
                    if (member.measure) {
                        continue;
                    }
                    found = findExistingTuple(member.children, toFind);
                    counter += found.index;
                    if (found.tuple) {
                        return {
                            tuple: found.tuple,
                            index: counter
                        };
                    }
                }
            }
            return { index: counter };
        }
        function addMembers(members, map) {
            var member, i, len, path = '';
            for (i = 0, len = members.length; i < len; i++) {
                member = members[i];
                path += member.name;
                if (!map[path]) {
                    map[path] = member;
                }
            }
        }
        function findParentMember(tuple, map) {
            var members = tuple.members;
            var i, len, member, path = '';
            var parentPath = '';
            var parentMember;
            for (i = 0, len = members.length; i < len; i++) {
                member = members[i];
                if (parentMember) {
                    if (map[path + member.name]) {
                        path += member.name;
                        parentMember = map[path];
                        continue;
                    } else if (map[path + member.parentName]) {
                        return map[path + member.parentName];
                    } else if (map[parentPath + member.parentName]) {
                        return map[parentPath + member.parentName];
                    } else {
                        return map[parentPath];
                    }
                }
                path += member.name;
                parentMember = map[member.parentName];
                if (!parentMember) {
                    parentMember = map[path];
                    if (!parentMember) {
                        return null;
                    }
                }
                if (parentMember) {
                    parentPath += parentMember.name;
                }
            }
            return parentMember;
        }
        function measurePosition(tuple, measures) {
            if (measures.length === 0) {
                return -1;
            }
            var measure = measures[0];
            var members = tuple.members;
            for (var idx = 0, len = members.length; idx < len; idx++) {
                if (members[idx].name == measure.name) {
                    return idx;
                }
            }
        }
        function normalizeTupleMeasures(tuple, index) {
            if (index < 0) {
                return;
            }
            var member = {
                name: MEASURES,
                measure: true,
                children: [$.extend({
                        members: [],
                        dataIndex: tuple.dataIndex
                    }, tuple.members[index])]
            };
            tuple.members.splice(index, 1, member);
            tuple.dataIndex = undefined;
        }
        function parseSource(tuples, measures) {
            if (tuples.length < 1) {
                return [];
            }
            var result = [];
            var map = {};
            var measureIndex = measurePosition(tuples[0], measures);
            for (var i = 0; i < tuples.length; i++) {
                var tuple = tuples[i];
                tuple.dataIndex = i;
                normalizeTupleMeasures(tuple, measureIndex);
                var parentMember = findParentMember(tuple, map);
                if (parentMember) {
                    if (measureIndex < 0 || !parentMember.measure) {
                        parentMember.children.push(tuple);
                    } else {
                        parentMember.children.push(tuple.members[measureIndex].children[0]);
                    }
                } else {
                    result.push(tuple);
                }
                addMembers(tuple.members, map);
            }
            return result;
        }
        function prepareDataOnRows(tuples, data) {
            if (!tuples || !tuples.length) {
                return data;
            }
            var result = [];
            var indices = buildDataIndices(tuples);
            var rowsLength = indices.length;
            var columnsLength = Math.max(data.length / rowsLength, 1);
            var rowIndex, columnIndex, targetIndex, sourceIndex;
            var calcIndex;
            for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
                targetIndex = columnsLength * rowIndex;
                sourceIndex = columnsLength * indices[rowIndex];
                for (columnIndex = 0; columnIndex < columnsLength; columnIndex++) {
                    calcIndex = parseInt(sourceIndex + columnIndex, 10);
                    result[parseInt(targetIndex + columnIndex, 10)] = data[calcIndex] || {
                        value: '',
                        fmtValue: '',
                        ordinal: calcIndex
                    };
                }
            }
            return result;
        }
        function prepareDataOnColumns(tuples, data) {
            if (!tuples || !tuples.length) {
                return data;
            }
            var result = [];
            var indices = buildDataIndices(tuples);
            var columnsLength = indices.length;
            var rowsLength = Math.max(data.length / columnsLength, 1);
            var columnIndex, rowIndex, dataIndex, calcIndex;
            for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
                dataIndex = columnsLength * rowIndex;
                for (columnIndex = 0; columnIndex < columnsLength; columnIndex++) {
                    calcIndex = indices[columnIndex] + dataIndex;
                    result[dataIndex + columnIndex] = data[calcIndex] || {
                        value: '',
                        fmtValue: '',
                        ordinal: calcIndex
                    };
                }
            }
            return result;
        }
        function buildDataIndices(tuples) {
            tuples = tuples.slice();
            var result = [];
            var tuple = tuples.shift();
            var idx, length, spliceIndex, children, member;
            while (tuple) {
                if (tuple.dataIndex !== undefined) {
                    result.push(tuple.dataIndex);
                }
                spliceIndex = 0;
                for (idx = 0, length = tuple.members.length; idx < length; idx++) {
                    member = tuple.members[idx];
                    children = member.children;
                    if (member.measure) {
                        [].splice.apply(tuples, [
                            0,
                            0
                        ].concat(children));
                    } else {
                        [].splice.apply(tuples, [
                            spliceIndex,
                            0
                        ].concat(children));
                    }
                    spliceIndex += children.length;
                }
                tuple = tuples.shift();
            }
            return result;
        }
        PivotDataSource.create = function (options) {
            options = options && options.push ? { data: options } : options;
            var dataSource = options || {}, data = dataSource.data;
            dataSource.data = data;
            if (!(dataSource instanceof PivotDataSource) && dataSource instanceof kendo.data.DataSource) {
                throw new Error('Incorrect DataSource type. Only PivotDataSource instances are supported');
            }
            return dataSource instanceof PivotDataSource ? dataSource : new PivotDataSource(dataSource);
        };
        function baseHierarchyPath(memberName) {
            var parts = memberName.split('.');
            if (parts.length > 2) {
                return parts[0] + '.' + parts[1];
            }
            return memberName;
        }
        function expandMemberDescriptor(names, sort) {
            var idx = names.length - 1;
            var name = names[idx];
            var sortDescriptor;
            sortDescriptor = sortDescriptorForMember(sort, name);
            if (sortDescriptor && sortDescriptor.dir) {
                name = 'ORDER(' + name + '.Children,' + sortDescriptor.field + '.CurrentMember.MEMBER_CAPTION,' + sortDescriptor.dir + ')';
            } else {
                name += '.Children';
            }
            names[idx] = name;
            return names;
        }
        function sortDescriptorForMember(sort, member) {
            for (var idx = 0, length = sort.length; idx < length; idx++) {
                if (member.indexOf(sort[idx].field) === 0) {
                    return sort[idx];
                }
            }
            return null;
        }
        function crossJoin(names) {
            var result = 'CROSSJOIN({';
            var r;
            if (names.length > 2) {
                r = names.pop();
                result += crossJoin(names);
            } else {
                result += names.shift();
                r = names.pop();
            }
            result += '},{';
            result += r;
            result += '})';
            return result;
        }
        function crossJoinCommand(members, measures) {
            var tmp = members.slice(0);
            if (measures.length > 1) {
                tmp.push('{' + measureNames(measures).join(',') + '}');
            }
            return crossJoin(tmp);
        }
        function measureNames(measures) {
            var idx = 0;
            var length = measures.length;
            var result = [];
            var measure;
            for (; idx < length; idx++) {
                measure = measures[idx];
                result.push(measure.name !== undefined ? measure.name : measure);
            }
            return result;
        }
        function getName(name) {
            name = name.name || name;
            if (toString.call(name) === '[object Array]') {
                name = name[name.length - 1];
            }
            return name;
        }
        function getRootNames(members) {
            var length = members.length;
            var names = [];
            var idx = 0;
            for (; idx < length; idx++) {
                names.push(members[idx].name[0]);
            }
            return names;
        }
        function mapNames(names, rootNames) {
            var name;
            var rootName;
            var j;
            var idx = 0;
            var length = names.length;
            var rootLength = rootNames.length;
            rootNames = rootNames.slice(0);
            for (; idx < length; idx++) {
                name = names[idx];
                for (j = 0; j < rootLength; j++) {
                    rootName = baseHierarchyPath(rootNames[j]);
                    if (name.indexOf(rootName) !== -1) {
                        rootNames[j] = name;
                        break;
                    }
                }
            }
            return {
                names: rootNames,
                expandedIdx: j,
                uniquePath: rootNames.slice(0, j + 1).join('')
            };
        }
        function parseDescriptors(members) {
            var expanded = [];
            var child = [];
            var root = [];
            var member;
            var j, l;
            var idx = 0;
            var length = members.length;
            var name;
            var hierarchyName;
            var found;
            for (; idx < length; idx++) {
                member = members[idx];
                name = member.name;
                found = false;
                if (toString.call(name) !== '[object Array]') {
                    member.name = name = [name];
                }
                if (name.length > 1) {
                    child.push(member);
                } else {
                    hierarchyName = baseHierarchyPath(name[0]);
                    for (j = 0, l = root.length; j < l; j++) {
                        if (root[j].name[0].indexOf(hierarchyName) === 0) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        root.push(member);
                    }
                    if (member.expand) {
                        expanded.push(member);
                    }
                }
            }
            expanded = expanded.concat(child);
            return {
                root: root,
                expanded: expanded
            };
        }
        function serializeMembers(members, measures, sort) {
            var command = '';
            members = members || [];
            var expanded = parseDescriptors(members);
            var root = expanded.root;
            var rootNames = getRootNames(root);
            var crossJoinCommands = [];
            expanded = expanded.expanded;
            var length = expanded.length;
            var idx = 0;
            var memberName;
            var names = [];
            if (rootNames.length > 1 || measures.length > 1) {
                crossJoinCommands.push(crossJoinCommand(rootNames, measures));
                for (; idx < length; idx++) {
                    memberName = expandMemberDescriptor(expanded[idx].name, sort);
                    names = mapNames(memberName, rootNames).names;
                    crossJoinCommands.push(crossJoinCommand(names, measures));
                }
                command += crossJoinCommands.join(',');
            } else {
                for (; idx < length; idx++) {
                    memberName = expandMemberDescriptor(expanded[idx].name, sort);
                    names.push(memberName[0]);
                }
                command += rootNames.concat(names).join(',');
            }
            return command;
        }
        var filterFunctionFormats = {
            contains: ', InStr({0}.CurrentMember.MEMBER_CAPTION,"{1}") > 0',
            doesnotcontain: ', InStr({0}.CurrentMember.MEMBER_CAPTION,"{1}")',
            startswith: ', Left({0}.CurrentMember.MEMBER_CAPTION,Len("{1}"))="{1}"',
            endswith: ', Right({0}.CurrentMember.MEMBER_CAPTION,Len("{1}"))="{1}"',
            eq: ', {0}.CurrentMember.MEMBER_CAPTION = "{1}"',
            neq: ', {0}.CurrentMember.MEMBER_CAPTION = "{1}"'
        };
        function serializeExpression(expression) {
            var command = '';
            var value = expression.value;
            var field = expression.field;
            var operator = expression.operator;
            if (operator == 'in') {
                command += '{';
                command += value;
                command += '}';
            } else {
                command += operator == 'neq' || operator == 'doesnotcontain' ? '-' : '';
                command += 'Filter(';
                command += field + '.MEMBERS';
                command += kendo.format(filterFunctionFormats[operator], field, value);
                command += ')';
            }
            return command;
        }
        function serializeFilters(filter, cube) {
            var command = '', current;
            var filters = filter.filters;
            var length = filters.length;
            var idx;
            for (idx = length - 1; idx >= 0; idx--) {
                current = 'SELECT (';
                current += serializeExpression(filters[idx]);
                current += ') ON 0';
                if (idx == length - 1) {
                    current += ' FROM [' + cube + ']';
                    command = current;
                } else {
                    command = current + ' FROM ( ' + command + ' )';
                }
            }
            return command;
        }
        function serializeOptions(parentTagName, options, capitalize) {
            var result = '';
            if (options) {
                result += '<' + parentTagName + '>';
                var value;
                for (var key in options) {
                    value = options[key];
                    if (capitalize) {
                        key = key.replace(/([A-Z]+(?=$|[A-Z][a-z])|[A-Z]?[a-z]+)/g, '$1_').toUpperCase().replace(/_$/, '');
                    }
                    result += '<' + key + '>' + value + '</' + key + '>';
                }
                result += '</' + parentTagName + '>';
            } else {
                result += '<' + parentTagName + '/>';
            }
            return result;
        }
        var xmlaDiscoverCommands = {
            schemaCubes: 'MDSCHEMA_CUBES',
            schemaCatalogs: 'DBSCHEMA_CATALOGS',
            schemaMeasures: 'MDSCHEMA_MEASURES',
            schemaDimensions: 'MDSCHEMA_DIMENSIONS',
            schemaHierarchies: 'MDSCHEMA_HIERARCHIES',
            schemaLevels: 'MDSCHEMA_LEVELS',
            schemaMembers: 'MDSCHEMA_MEMBERS',
            schemaKPIs: 'MDSCHEMA_KPIS'
        };
        var convertersMap = {
            read: function (options) {
                var command = '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Header/><Body><Execute xmlns="urn:schemas-microsoft-com:xml-analysis"><Command><Statement>';
                command += 'SELECT NON EMPTY {';
                var columns = options.columns || [];
                var rows = options.rows || [];
                var measures = options.measures || [];
                var measuresRowAxis = options.measuresAxis === 'rows';
                var sort = options.sort || [];
                if (!columns.length && rows.length && (!measures.length || measures.length && measuresRowAxis)) {
                    columns = rows;
                    rows = [];
                    measuresRowAxis = false;
                }
                if (!columns.length && !rows.length) {
                    measuresRowAxis = false;
                }
                if (columns.length) {
                    command += serializeMembers(columns, !measuresRowAxis ? measures : [], sort);
                } else if (measures.length && !measuresRowAxis) {
                    command += measureNames(measures).join(',');
                }
                command += '} DIMENSION PROPERTIES CHILDREN_CARDINALITY, PARENT_UNIQUE_NAME ON COLUMNS';
                if (rows.length || measuresRowAxis && measures.length > 1) {
                    command += ', NON EMPTY {';
                    if (rows.length) {
                        command += serializeMembers(rows, measuresRowAxis ? measures : [], sort);
                    } else {
                        command += measureNames(measures).join(',');
                    }
                    command += '} DIMENSION PROPERTIES CHILDREN_CARDINALITY, PARENT_UNIQUE_NAME ON ROWS';
                }
                if (options.filter) {
                    command += ' FROM ';
                    command += '(';
                    command += serializeFilters(options.filter, options.connection.cube);
                    command += ')';
                } else {
                    command += ' FROM [' + options.connection.cube + ']';
                }
                if (measures.length == 1 && columns.length) {
                    command += ' WHERE (' + measureNames(measures).join(',') + ')';
                }
                command += '</Statement></Command><Properties><PropertyList><Catalog>' + options.connection.catalog + '</Catalog><Format>Multidimensional</Format></PropertyList></Properties></Execute></Body></Envelope>';
                return command.replace(/\&/g, '&amp;');
            },
            discover: function (options) {
                options = options || {};
                var command = '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Header/><Body><Discover xmlns="urn:schemas-microsoft-com:xml-analysis">';
                command += '<RequestType>' + (xmlaDiscoverCommands[options.command] || options.command) + '</RequestType>';
                command += '<Restrictions>' + serializeOptions('RestrictionList', options.restrictions, true) + '</Restrictions>';
                if (options.connection && options.connection.catalog) {
                    options.properties = $.extend({}, { Catalog: options.connection.catalog }, options.properties);
                }
                command += '<Properties>' + serializeOptions('PropertyList', options.properties) + '</Properties>';
                command += '</Discover></Body></Envelope>';
                return command;
            }
        };
        var XmlaTransport = kendo.data.RemoteTransport.extend({
            init: function (options) {
                var originalOptions = options;
                options = this.options = extend(true, {}, this.options, options);
                kendo.data.RemoteTransport.call(this, options);
                if (isFunction(originalOptions.discover)) {
                    this.discover = originalOptions.discover;
                } else if (typeof originalOptions.discover === 'string') {
                    this.options.discover = { url: originalOptions.discover };
                } else if (!originalOptions.discover) {
                    this.options.discover = this.options.read;
                }
            },
            setup: function (options, type) {
                options.data = options.data || {};
                $.extend(true, options.data, { connection: this.options.connection });
                return kendo.data.RemoteTransport.fn.setup.call(this, options, type);
            },
            options: {
                read: {
                    dataType: 'text',
                    contentType: 'text/xml',
                    type: 'POST'
                },
                discover: {
                    dataType: 'text',
                    contentType: 'text/xml',
                    type: 'POST'
                },
                parameterMap: function (options, type) {
                    return convertersMap[type](options, type);
                }
            },
            discover: function (options) {
                return $.ajax(this.setup(options, 'discover'));
            }
        });
        function asArray(object) {
            if (object == null) {
                return [];
            }
            var type = toString.call(object);
            if (type !== '[object Array]') {
                return [object];
            }
            return object;
        }
        function translateAxis(axis) {
            var result = { tuples: [] };
            var tuples = asArray(kendo.getter('Tuples.Tuple', true)(axis));
            var captionGetter = kendo.getter('Caption[\'#text\']');
            var unameGetter = kendo.getter('UName[\'#text\']');
            var levelNameGetter = kendo.getter('LName[\'#text\']');
            var levelNumGetter = kendo.getter('LNum[\'#text\']');
            var childrenGetter = kendo.getter('CHILDREN_CARDINALITY[\'#text\']', true);
            var hierarchyGetter = kendo.getter('[\'@Hierarchy\']');
            var parentNameGetter = kendo.getter('PARENT_UNIQUE_NAME[\'#text\']', true);
            for (var idx = 0; idx < tuples.length; idx++) {
                var members = [];
                var member = asArray(tuples[idx].Member);
                for (var memberIdx = 0; memberIdx < member.length; memberIdx++) {
                    members.push({
                        children: [],
                        caption: captionGetter(member[memberIdx]),
                        name: unameGetter(member[memberIdx]),
                        levelName: levelNameGetter(member[memberIdx]),
                        levelNum: levelNumGetter(member[memberIdx]),
                        hasChildren: parseInt(childrenGetter(member[memberIdx]), 10) > 0,
                        parentName: parentNameGetter(member[memberIdx]),
                        hierarchy: hierarchyGetter(member[memberIdx])
                    });
                }
                result.tuples.push({ members: members });
            }
            return result;
        }
        var schemaDataReaderMap = {
            cubes: {
                name: kendo.getter('CUBE_NAME[\'#text\']', true),
                caption: kendo.getter('CUBE_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                type: kendo.getter('CUBE_TYPE[\'#text\']', true)
            },
            catalogs: {
                name: kendo.getter('CATALOG_NAME[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true)
            },
            measures: {
                name: kendo.getter('MEASURE_NAME[\'#text\']', true),
                caption: kendo.getter('MEASURE_CAPTION[\'#text\']', true),
                uniqueName: kendo.getter('MEASURE_UNIQUE_NAME[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                aggregator: kendo.getter('MEASURE_AGGREGATOR[\'#text\']', true),
                groupName: kendo.getter('MEASUREGROUP_NAME[\'#text\']', true),
                displayFolder: kendo.getter('MEASURE_DISPLAY_FOLDER[\'#text\']', true),
                defaultFormat: kendo.getter('DEFAULT_FORMAT_STRING[\'#text\']', true)
            },
            kpis: {
                name: kendo.getter('KPI_NAME[\'#text\']', true),
                caption: kendo.getter('KPI_CAPTION[\'#text\']', true),
                value: kendo.getter('KPI_VALUE[\'#text\']', true),
                goal: kendo.getter('KPI_GOAL[\'#text\']', true),
                status: kendo.getter('KPI_STATUS[\'#text\']', true),
                trend: kendo.getter('KPI_TREND[\'#text\']', true),
                statusGraphic: kendo.getter('KPI_STATUS_GRAPHIC[\'#text\']', true),
                trendGraphic: kendo.getter('KPI_TREND_GRAPHIC[\'#text\']', true),
                description: kendo.getter('KPI_DESCRIPTION[\'#text\']', true),
                groupName: kendo.getter('MEASUREGROUP_NAME[\'#text\']', true)
            },
            dimensions: {
                name: kendo.getter('DIMENSION_NAME[\'#text\']', true),
                caption: kendo.getter('DIMENSION_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                uniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                defaultHierarchy: kendo.getter('DEFAULT_HIERARCHY[\'#text\']', true),
                type: kendo.getter('DIMENSION_TYPE[\'#text\']', true)
            },
            hierarchies: {
                name: kendo.getter('HIERARCHY_NAME[\'#text\']', true),
                caption: kendo.getter('HIERARCHY_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                uniqueName: kendo.getter('HIERARCHY_UNIQUE_NAME[\'#text\']', true),
                dimensionUniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                displayFolder: kendo.getter('HIERARCHY_DISPLAY_FOLDER[\'#text\']', true),
                origin: kendo.getter('HIERARCHY_ORIGIN[\'#text\']', true),
                defaultMember: kendo.getter('DEFAULT_MEMBER[\'#text\']', true)
            },
            levels: {
                name: kendo.getter('LEVEL_NAME[\'#text\']', true),
                caption: kendo.getter('LEVEL_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                uniqueName: kendo.getter('LEVEL_UNIQUE_NAME[\'#text\']', true),
                dimensionUniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                displayFolder: kendo.getter('LEVEL_DISPLAY_FOLDER[\'#text\']', true),
                orderingProperty: kendo.getter('LEVEL_ORDERING_PROPERTY[\'#text\']', true),
                origin: kendo.getter('LEVEL_ORIGIN[\'#text\']', true),
                hierarchyUniqueName: kendo.getter('HIERARCHY_UNIQUE_NAME[\'#text\']', true)
            },
            members: {
                name: kendo.getter('MEMBER_NAME[\'#text\']', true),
                caption: kendo.getter('MEMBER_CAPTION[\'#text\']', true),
                uniqueName: kendo.getter('MEMBER_UNIQUE_NAME[\'#text\']', true),
                dimensionUniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                hierarchyUniqueName: kendo.getter('HIERARCHY_UNIQUE_NAME[\'#text\']', true),
                levelUniqueName: kendo.getter('LEVEL_UNIQUE_NAME[\'#text\']', true),
                childrenCardinality: kendo.getter('CHILDREN_CARDINALITY[\'#text\']', true)
            }
        };
        var xmlaReaderMethods = [
            'axes',
            'catalogs',
            'cubes',
            'dimensions',
            'hierarchies',
            'levels',
            'measures'
        ];
        var XmlaDataReader = kendo.data.XmlDataReader.extend({
            init: function (options) {
                kendo.data.XmlDataReader.call(this, options);
                this._extend(options);
            },
            _extend: function (options) {
                var idx = 0;
                var length = xmlaReaderMethods.length;
                var methodName;
                var option;
                for (; idx < length; idx++) {
                    methodName = xmlaReaderMethods[idx];
                    option = options[methodName];
                    if (option && option !== identity) {
                        this[methodName] = option;
                    }
                }
            },
            parse: function (xml) {
                var result = kendo.data.XmlDataReader.fn.parse(xml.replace(/<(\/?)(\w|-)+:/g, '<$1'));
                return kendo.getter('[\'Envelope\'][\'Body\']', true)(result);
            },
            errors: function (root) {
                var fault = kendo.getter('[\'Fault\']', true)(root);
                if (fault) {
                    return [{
                            faultstring: kendo.getter('faultstring[\'#text\']', true)(fault),
                            faultcode: kendo.getter('faultcode[\'#text\']', true)(fault)
                        }];
                }
                return null;
            },
            axes: function (root) {
                root = kendo.getter('ExecuteResponse["return"].root', true)(root);
                var axes = asArray(kendo.getter('Axes.Axis', true)(root));
                var axis;
                var result = {
                    columns: {},
                    rows: {}
                };
                for (var idx = 0; idx < axes.length; idx++) {
                    axis = axes[idx];
                    if (axis['@name'].toLowerCase() !== 'sliceraxis') {
                        if (!result.columns.tuples) {
                            result.columns = translateAxis(axis);
                        } else {
                            result.rows = translateAxis(axis);
                        }
                    }
                }
                return result;
            },
            data: function (root) {
                root = kendo.getter('ExecuteResponse["return"].root', true)(root);
                var cells = asArray(kendo.getter('CellData.Cell', true)(root));
                var result = [];
                var ordinalGetter = kendo.getter('[\'@CellOrdinal\']');
                var valueGetter = kendo.getter('Value[\'#text\']');
                var fmtValueGetter = kendo.getter('FmtValue[\'#text\']');
                for (var idx = 0; idx < cells.length; idx++) {
                    result.push({
                        value: valueGetter(cells[idx]),
                        fmtValue: fmtValueGetter(cells[idx]),
                        ordinal: parseInt(ordinalGetter(cells[idx]), 10)
                    });
                }
                return result;
            },
            _mapSchema: function (root, getters) {
                root = kendo.getter('DiscoverResponse["return"].root', true)(root);
                var rows = asArray(kendo.getter('row', true)(root));
                var result = [];
                for (var idx = 0; idx < rows.length; idx++) {
                    var obj = {};
                    for (var key in getters) {
                        obj[key] = getters[key](rows[idx]);
                    }
                    result.push(obj);
                }
                return result;
            },
            measures: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.measures);
            },
            kpis: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.kpis);
            },
            hierarchies: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.hierarchies);
            },
            levels: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.levels);
            },
            dimensions: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.dimensions);
            },
            cubes: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.cubes);
            },
            catalogs: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.catalogs);
            },
            members: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.members);
            }
        });
        extend(true, kendo.data, {
            PivotDataSource: PivotDataSource,
            XmlaTransport: XmlaTransport,
            XmlaDataReader: XmlaDataReader,
            PivotCubeBuilder: PivotCubeBuilder,
            transports: { xmla: XmlaTransport },
            readers: { xmla: XmlaDataReader }
        });
        var sortExpr = function (expressions, name) {
            if (!expressions) {
                return null;
            }
            for (var idx = 0, length = expressions.length; idx < length; idx++) {
                if (expressions[idx].field === name) {
                    return expressions[idx];
                }
            }
            return null;
        };
        var removeExpr = function (expressions, name) {
            var result = [];
            for (var idx = 0, length = expressions.length; idx < length; idx++) {
                if (expressions[idx].field !== name) {
                    result.push(expressions[idx]);
                }
            }
            return result;
        };
        kendo.ui.PivotSettingTarget = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.element.addClass('k-pivot-setting');
                that.dataSource = kendo.data.PivotDataSource.create(options.dataSource);
                that._refreshHandler = $.proxy(that.refresh, that);
                that.dataSource.first(CHANGE, that._refreshHandler);
                if (!options.template) {
                    that.options.template = '<div data-' + kendo.ns + 'name="${data.name || data}">${data.name || data}' + (that.options.enabled ? '<a class="k-button k-button-icon k-bare"><span class="k-icon k-i-close k-setting-delete"></span></a>' : '') + '</div>';
                }
                that.template = kendo.template(that.options.template);
                that.emptyTemplate = kendo.template(that.options.emptyTemplate);
                that._sortable();
                that.element.on('click' + NS, '.k-button,.k-item', function (e) {
                    var target = $(e.target);
                    var name = target.closest('[' + kendo.attr('name') + ']').attr(kendo.attr('name'));
                    if (!name) {
                        return;
                    }
                    if (target.hasClass('k-i-close')) {
                        that.remove(name);
                    } else if (that.options.sortable && target[0] === e.currentTarget) {
                        that.sort({
                            field: name,
                            dir: target.find('.k-i-sort-asc-sm')[0] ? 'desc' : 'asc'
                        });
                    }
                });
                if (options.filterable || options.sortable) {
                    that.fieldMenu = new ui.PivotFieldMenu(that.element, {
                        messages: that.options.messages.fieldMenu,
                        filter: '.k-setting-fieldmenu',
                        filterable: options.filterable,
                        sortable: options.sortable,
                        dataSource: that.dataSource
                    });
                }
                that.refresh();
            },
            options: {
                name: 'PivotSettingTarget',
                template: null,
                filterable: false,
                sortable: false,
                emptyTemplate: '<div class=\'k-empty\'>${data}</div>',
                setting: 'columns',
                enabled: true,
                messages: { empty: 'Drop Fields Here' }
            },
            setDataSource: function (dataSource) {
                this.dataSource.unbind(CHANGE, this._refreshHandler);
                this.dataSource = this.options.dataSource = dataSource;
                if (this.fieldMenu) {
                    this.fieldMenu.setDataSource(dataSource);
                }
                dataSource.first(CHANGE, this._refreshHandler);
                this.refresh();
            },
            _sortable: function () {
                var that = this;
                if (that.options.enabled) {
                    this.sortable = this.element.kendoSortable({
                        connectWith: this.options.connectWith,
                        hint: that.options.hint,
                        cursor: 'move',
                        start: function (e) {
                            e.item.focus().blur();
                        },
                        change: function (e) {
                            var name = e.item.attr(kendo.attr('name'));
                            if (e.action == 'receive') {
                                that.add(name);
                            } else if (e.action == 'remove') {
                                that.remove(name);
                            } else if (e.action == 'sort') {
                                that.move(name, e.newIndex);
                            }
                        }
                    }).data('kendoSortable');
                }
            },
            _indexOf: function (name, items) {
                var idx, length, index = -1;
                for (idx = 0, length = items.length; idx < length; idx++) {
                    if (getName(items[idx]) === name) {
                        index = idx;
                        break;
                    }
                }
                return index;
            },
            _isKPI: function (data) {
                return data.type === 'kpi' || data.measure;
            },
            validate: function (data) {
                var isMeasure = data.type == 2 || 'aggregator' in data || this._isKPI(data);
                if (isMeasure) {
                    return this.options.setting === 'measures';
                }
                if (this.options.setting === 'measures') {
                    return isMeasure;
                }
                var items = this.dataSource[this.options.setting]();
                var name = data.defaultHierarchy || data.uniqueName;
                if (this._indexOf(name, items) > -1) {
                    return false;
                }
                items = this.dataSource[this.options.setting === 'columns' ? 'rows' : 'columns']();
                if (this._indexOf(name, items) > -1) {
                    return false;
                }
                return true;
            },
            add: function (name) {
                var items = this.dataSource[this.options.setting]();
                var i, l;
                name = $.isArray(name) ? name.slice(0) : [name];
                for (i = 0, l = name.length; i < l; i++) {
                    if (this._indexOf(name[i], items) !== -1) {
                        name.splice(i, 1);
                        i -= 1;
                        l -= 1;
                    }
                }
                if (name.length) {
                    items = items.concat(name);
                    this.dataSource[this.options.setting](items);
                }
            },
            move: function (name, index) {
                var items = this.dataSource[this.options.setting]();
                var idx = this._indexOf(name, items);
                if (idx > -1) {
                    name = items.splice(idx, 1)[0];
                    items.splice(index, 0, name);
                    this.dataSource[this.options.setting](items);
                }
            },
            remove: function (name) {
                var items = this.dataSource[this.options.setting]();
                var idx = this._indexOf(name, items);
                var sortExpressions = this.dataSource.sort();
                var filter = this.dataSource.filter();
                if (idx > -1) {
                    if (filter) {
                        filter.filters = removeExpr(filter.filters, name);
                        this.dataSource._filter.filters = filter.filters;
                        if (!filter.filters.length) {
                            this.dataSource._filter = null;
                        }
                    }
                    if (sortExpressions) {
                        sortExpressions = removeExpr(sortExpressions, name);
                        this.dataSource._sort = sortExpressions;
                    }
                    items.splice(idx, 1);
                    this.dataSource[this.options.setting](items);
                }
            },
            sort: function (expr) {
                var sortable = this.options.sortable;
                var allowUnsort = sortable === true || sortable.allowUnsort;
                var skipExpr = allowUnsort && expr.dir === 'asc';
                var expressions = this.dataSource.sort() || [];
                var result = removeExpr(expressions, expr.field);
                if (skipExpr && expressions.length !== result.length) {
                    expr = null;
                }
                if (expr) {
                    result.push(expr);
                }
                this.dataSource.sort(result);
            },
            refresh: function () {
                var html = '';
                var items = this.dataSource[this.options.setting]();
                var length = items.length;
                var idx = 0;
                var item;
                if (length) {
                    for (; idx < length; idx++) {
                        item = items[idx];
                        item = item.name === undefined ? { name: item } : item;
                        html += this.template(extend({ sortIcon: this._sortIcon(item.name) }, item));
                    }
                } else {
                    html = this.emptyTemplate(this.options.messages.empty);
                }
                this.element.html(html);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.dataSource.unbind(CHANGE, this._refreshHandler);
                this.element.off(NS);
                if (this.sortable) {
                    this.sortable.destroy();
                }
                if (this.fieldMenu) {
                    this.fieldMenu.destroy();
                }
                this.element = null;
                this._refreshHandler = null;
            },
            _sortIcon: function (name) {
                var expressions = this.dataSource.sort();
                var expr = sortExpr(expressions, getName(name));
                var icon = '';
                if (expr) {
                    icon = 'k-i-sort-' + expr.dir;
                }
                return icon;
            }
        });
        var PivotGrid = Widget.extend({
            init: function (element, options) {
                var that = this;
                var columnBuilder;
                var rowBuilder;
                Widget.fn.init.call(that, element, options);
                that._dataSource();
                that._bindConfigurator();
                that._wrapper();
                that._createLayout();
                that._columnBuilder = columnBuilder = new ColumnBuilder();
                that._rowBuilder = rowBuilder = new RowBuilder();
                that._contentBuilder = new ContentBuilder();
                that._templates();
                that.columnsHeader.add(that.rowsHeader).on('click', 'span.k-icon', function () {
                    var button = $(this);
                    var builder = columnBuilder;
                    var action = 'expandColumn';
                    var eventName;
                    var path = button.attr(kendo.attr('path'));
                    var eventArgs = {
                        axis: 'columns',
                        path: $.parseJSON(path)
                    };
                    if (button.parent().is('td')) {
                        builder = rowBuilder;
                        action = 'expandRow';
                        eventArgs.axis = 'rows';
                    }
                    var expanded = button.hasClass(STATE_EXPANDED);
                    var metadata = builder.metadata[path];
                    var request = metadata.expanded === undefined;
                    eventName = expanded ? COLLAPSEMEMBER : EXPANDMEMBER;
                    eventArgs.childrenLoaded = metadata.maxChildren > metadata.children;
                    if (that.trigger(eventName, eventArgs)) {
                        return;
                    }
                    builder.metadata[path].expanded = !expanded;
                    button.toggleClass(STATE_EXPANDED, !expanded).toggleClass(STATE_COLLAPSED, expanded);
                    if (!expanded && request) {
                        that.dataSource[action](eventArgs.path);
                    } else {
                        that.refresh();
                    }
                });
                that._scrollable();
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
                kendo.notify(that);
            },
            events: [
                DATABINDING,
                DATABOUND,
                EXPANDMEMBER,
                COLLAPSEMEMBER
            ],
            options: {
                name: 'PivotGrid',
                autoBind: true,
                reorderable: true,
                filterable: false,
                sortable: false,
                height: null,
                columnWidth: 100,
                configurator: '',
                columnHeaderTemplate: null,
                rowHeaderTemplate: null,
                dataCellTemplate: null,
                kpiStatusTemplate: null,
                kpiTrendTemplate: null,
                messages: {
                    measureFields: 'Drop Data Fields Here',
                    columnFields: 'Drop Column Fields Here',
                    rowFields: 'Drop Rows Fields Here'
                }
            },
            _templates: function () {
                var columnTemplate = this.options.columnHeaderTemplate;
                var rowTemplate = this.options.rowHeaderTemplate;
                var dataTemplate = this.options.dataCellTemplate;
                var kpiStatusTemplate = this.options.kpiStatusTemplate;
                var kpiTrendTemplate = this.options.kpiTrendTemplate;
                this._columnBuilder.template = kendo.template(columnTemplate || HEADER_TEMPLATE, { useWithBlock: !!columnTemplate });
                this._contentBuilder.dataTemplate = kendo.template(dataTemplate || DATACELL_TEMPLATE, { useWithBlock: !!dataTemplate });
                this._contentBuilder.kpiStatusTemplate = kendo.template(kpiStatusTemplate || KPISTATUS_TEMPLATE, { useWithBlock: !!kpiStatusTemplate });
                this._contentBuilder.kpiTrendTemplate = kendo.template(kpiTrendTemplate || KPITREND_TEMPLATE, { useWithBlock: !!kpiTrendTemplate });
                this._rowBuilder.template = kendo.template(rowTemplate || HEADER_TEMPLATE, { useWithBlock: !!rowTemplate });
            },
            _bindConfigurator: function () {
                var configurator = this.options.configurator;
                if (configurator) {
                    $(configurator).kendoPivotConfigurator('setDataSource', this.dataSource);
                }
            },
            cellInfoByElement: function (element) {
                element = $(element);
                return this.cellInfo(element.index(), element.parent('tr').index());
            },
            cellInfo: function (columnIndex, rowIndex) {
                var contentBuilder = this._contentBuilder;
                var columnInfo = contentBuilder.columnIndexes[columnIndex || 0];
                var rowInfo = contentBuilder.rowIndexes[rowIndex || 0];
                var dataIndex;
                if (!columnInfo || !rowInfo) {
                    return null;
                }
                dataIndex = rowInfo.index * contentBuilder.rowLength + columnInfo.index;
                return {
                    columnTuple: columnInfo.tuple,
                    rowTuple: rowInfo.tuple,
                    measure: columnInfo.measure || rowInfo.measure,
                    dataItem: this.dataSource.view()[dataIndex]
                };
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.measuresTarget) {
                    this.measuresTarget.setDataSource(dataSource);
                }
                if (this.rowsTarget) {
                    this.rowsTarget.setDataSource(dataSource);
                }
                if (this.columnsTarget) {
                    this.columnsTarget.setDataSource(dataSource);
                }
                this._bindConfigurator();
                if (this.options.autoBind) {
                    dataSource.fetch();
                }
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._templates();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                clearTimeout(this._headerReflowTimeout);
            },
            _dataSource: function () {
                var that = this;
                var dataSource = that.options.dataSource;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                if (that.dataSource && this._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(STATERESET, that._stateResetHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
                } else {
                    that._refreshHandler = $.proxy(that.refresh, that);
                    that._progressHandler = $.proxy(that._requestStart, that);
                    that._stateResetHandler = $.proxy(that._stateReset, that);
                    that._errorHandler = $.proxy(that._error, that);
                }
                that.dataSource = kendo.data.PivotDataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(STATERESET, that._stateResetHandler).bind(ERROR, that._errorHandler);
            },
            _error: function () {
                this._progress(false);
            },
            _requestStart: function () {
                this._progress(true);
            },
            _stateReset: function () {
                this._columnBuilder.reset();
                this._rowBuilder.reset();
            },
            _wrapper: function () {
                var height = this.options.height;
                this.wrapper = this.element.addClass('k-widget k-pivot');
                if (height) {
                    this.wrapper.css('height', height);
                }
            },
            _measureFields: function () {
                this.measureFields = $(DIV).addClass('k-pivot-toolbar k-header k-settings-measures');
                this.measuresTarget = this._createSettingTarget(this.measureFields, {
                    setting: 'measures',
                    messages: { empty: this.options.messages.measureFields }
                });
            },
            _createSettingTarget: function (element, options) {
                var template = '<span tabindex="0" class="k-button" data-' + kendo.ns + 'name="${data.name}">${data.name}';
                var sortable = options.sortable;
                var icons = '';
                if (sortable) {
                    icons += '#if (data.sortIcon) {#';
                    icons += '<span class="k-icon ${data.sortIcon}-sm"></span>';
                    icons += '#}#';
                }
                if (options.filterable || sortable) {
                    icons += '<span class="k-icon k-i-more-vertical k-setting-fieldmenu"></span>';
                }
                if (this.options.reorderable) {
                    icons += '<span class="k-icon k-i-close k-setting-delete"></span>';
                }
                if (icons) {
                    template += '<span class="k-field-actions">' + icons + '</span>';
                }
                template += '</span>';
                return new kendo.ui.PivotSettingTarget(element, $.extend({
                    template: template,
                    emptyTemplate: '<span class="k-empty">${data}</span>',
                    enabled: this.options.reorderable,
                    dataSource: this.dataSource
                }, options));
            },
            _initSettingTargets: function () {
                this.columnsTarget = this._createSettingTarget(this.columnFields, {
                    connectWith: this.rowFields,
                    setting: 'columns',
                    filterable: this.options.filterable,
                    sortable: this.options.sortable,
                    messages: {
                        empty: this.options.messages.columnFields,
                        fieldMenu: this.options.messages.fieldMenu
                    }
                });
                this.rowsTarget = this._createSettingTarget(this.rowFields, {
                    connectWith: this.columnFields,
                    setting: 'rows',
                    filterable: this.options.filterable,
                    sortable: this.options.sortable,
                    messages: {
                        empty: this.options.messages.rowFields,
                        fieldMenu: this.options.messages.fieldMenu
                    }
                });
            },
            _createLayout: function () {
                var that = this;
                var layoutTable = $(LAYOUT_TABLE);
                var leftContainer = layoutTable.find('.k-pivot-rowheaders');
                var rightContainer = layoutTable.find('.k-pivot-table');
                var gridWrapper = $(DIV).addClass('k-grid k-widget');
                that._measureFields();
                that.columnFields = $(DIV).addClass('k-pivot-toolbar k-header k-settings-columns');
                that.rowFields = $(DIV).addClass('k-pivot-toolbar k-header k-settings-rows');
                that.columnsHeader = $('<div class="k-grid-header-wrap" />').wrap('<div class="k-grid-header" />');
                that.columnsHeader.parent().css('padding-right', kendo.support.scrollbar());
                that.rowsHeader = $('<div class="k-grid k-widget k-alt"/>');
                that.content = $('<div class="k-grid-content" />');
                leftContainer.append(that.measureFields);
                leftContainer.append(that.rowFields);
                leftContainer.append(that.rowsHeader);
                gridWrapper.append(that.columnsHeader.parent());
                gridWrapper.append(that.content);
                rightContainer.append(that.columnFields);
                rightContainer.append(gridWrapper);
                that.wrapper.append(layoutTable);
                that.columnsHeaderTree = new kendo.dom.Tree(that.columnsHeader[0]);
                that.rowsHeaderTree = new kendo.dom.Tree(that.rowsHeader[0]);
                that.contentTree = new kendo.dom.Tree(that.content[0]);
                that._initSettingTargets();
            },
            _progress: function (toggle) {
                kendo.ui.progress(this.wrapper, toggle);
            },
            _resize: function () {
                if (this.content[0].firstChild) {
                    this._setSectionsWidth();
                    this._setSectionsHeight();
                    this._setContentWidth();
                    this._setContentHeight();
                    this._columnHeaderReflow();
                }
            },
            _columnHeaderReflow: function () {
                var columnTable = this.columnsHeader.children('table');
                if (!kendo.support.browser.mozilla) {
                    return;
                }
                clearTimeout(this._headerReflowTimeout);
                columnTable.css('table-layout', 'auto');
                this._headerReflowTimeout = setTimeout(function () {
                    columnTable.css('table-layout', '');
                });
            },
            _setSectionsWidth: function () {
                var rowsHeader = this.rowsHeader;
                var leftColumn = rowsHeader.parent('.k-pivot-rowheaders').width(AUTO);
                var width;
                width = Math.max(outerWidth(this.measureFields), outerWidth(this.rowFields));
                width = Math.max(rowsHeader.children('table').width(), width);
                leftColumn.width(width);
            },
            _setSectionsHeight: function () {
                var measureFieldsHeight = this.measureFields.height(AUTO).height();
                var columnFieldsHeight = this.columnFields.height(AUTO).height();
                var rowFieldsHeight = this.rowFields.height(AUTO).innerHeight();
                var columnsHeight = this.columnsHeader.height(AUTO).innerHeight();
                var padding = rowFieldsHeight - this.rowFields.height();
                var firstRowHeight = columnFieldsHeight > measureFieldsHeight ? columnFieldsHeight : measureFieldsHeight;
                var secondRowHeight = columnsHeight > rowFieldsHeight ? columnsHeight : rowFieldsHeight;
                this.measureFields.height(firstRowHeight);
                this.columnFields.height(firstRowHeight);
                this.rowFields.height(secondRowHeight - padding);
                this.columnsHeader.height(secondRowHeight);
            },
            _setContentWidth: function () {
                var contentTable = this.content.find('table');
                var columnTable = this.columnsHeader.children('table');
                var rowLength = contentTable.children('colgroup').children().length;
                var calculatedWidth = rowLength * this.options.columnWidth;
                var minWidth = Math.ceil(calculatedWidth / this.content.width() * 100);
                if (minWidth < 100) {
                    minWidth = 100;
                }
                contentTable.add(columnTable).css('width', minWidth + '%');
                this._resetColspan(columnTable);
            },
            _setContentHeight: function () {
                var that = this;
                var content = that.content;
                var rowsHeader = that.rowsHeader;
                var innerHeight = that.wrapper.innerHeight();
                var scrollbar = kendo.support.scrollbar();
                var skipScrollbar = content[0].offsetHeight === content[0].clientHeight;
                var height = that.options.height;
                if (that.wrapper.is(':visible')) {
                    if (!innerHeight || !height) {
                        if (skipScrollbar) {
                            scrollbar = 0;
                        }
                        content.height('auto');
                        rowsHeader.height(content.height() - scrollbar);
                        return;
                    }
                    innerHeight -= outerHeight(that.columnFields);
                    innerHeight -= outerHeight(that.columnsHeader);
                    if (innerHeight <= scrollbar * 2) {
                        innerHeight = scrollbar * 2 + 1;
                        if (!skipScrollbar) {
                            innerHeight += scrollbar;
                        }
                    }
                    content.height(innerHeight);
                    if (skipScrollbar) {
                        scrollbar = 0;
                    }
                    rowsHeader.height(innerHeight - scrollbar);
                }
            },
            _resetColspan: function (columnTable) {
                var that = this;
                var cell = columnTable.children('tbody').children(':first').children(':first');
                if (that._colspan === undefined) {
                    that._colspan = cell.attr('colspan');
                }
                cell.attr('colspan', 1);
                clearTimeout(that._layoutTimeout);
                that._layoutTimeout = setTimeout(function () {
                    cell.attr('colspan', that._colspan);
                    that._colspan = undefined;
                });
            },
            _axisMeasures: function (axis) {
                var result = [];
                var dataSource = this.dataSource;
                var measures = dataSource.measures();
                var hasMeasure = measures.length > 1 || measures[0] && measures[0].type;
                if (dataSource.measuresAxis() === axis) {
                    if (dataSource[axis]().length === 0 || hasMeasure) {
                        result = measures;
                    }
                }
                return result;
            },
            items: function () {
                return [];
            },
            refresh: function () {
                var that = this;
                var dataSource = that.dataSource;
                var axes = dataSource.axes();
                var columns = (axes.columns || {}).tuples || [];
                var rows = (axes.rows || {}).tuples || [];
                var columnBuilder = that._columnBuilder;
                var rowBuilder = that._rowBuilder;
                var columnAxis = {};
                var rowAxis = {};
                if (that.trigger(DATABINDING, { action: 'rebind' })) {
                    return;
                }
                columnBuilder.measures = that._axisMeasures(AXIS_COLUMNS);
                rowBuilder.measures = that._axisMeasures(AXIS_ROWS);
                that.columnsHeaderTree.render(columnBuilder.build(columns));
                that.rowsHeaderTree.render(rowBuilder.build(rows));
                columnAxis = {
                    indexes: columnBuilder._indexes,
                    measures: columnBuilder.measures,
                    metadata: columnBuilder.metadata
                };
                rowAxis = {
                    indexes: rowBuilder._indexes,
                    measures: rowBuilder.measures,
                    metadata: rowBuilder.metadata
                };
                that.contentTree.render(that._contentBuilder.build(dataSource.view(), columnAxis, rowAxis));
                that._resize();
                if (that.touchScroller) {
                    that.touchScroller.contentResized();
                } else {
                    var touchScroller = kendo.touchScroller(that.content);
                    if (touchScroller && touchScroller.movable) {
                        that.touchScroller = touchScroller;
                        touchScroller.movable.bind('change', function (e) {
                            that.columnsHeader.scrollLeft(-e.sender.x);
                            that.rowsHeader.scrollTop(-e.sender.y);
                        });
                    }
                }
                that._progress(false);
                that.trigger(DATABOUND);
            },
            _scrollable: function () {
                var that = this;
                var columnsHeader = that.columnsHeader;
                var rowsHeader = that.rowsHeader;
                that.content.scroll(function () {
                    columnsHeader.scrollLeft(this.scrollLeft);
                    rowsHeader.scrollTop(this.scrollTop);
                });
                rowsHeader.bind('DOMMouseScroll' + NS + ' mousewheel' + NS, $.proxy(that._wheelScroll, that));
            },
            _wheelScroll: function (e) {
                if (e.ctrlKey) {
                    return;
                }
                var delta = kendo.wheelDeltaY(e);
                var scrollTop = this.content.scrollTop();
                if (delta) {
                    e.preventDefault();
                    $(e.currentTarget).one('wheel' + NS, false);
                    this.rowsHeader.scrollTop(scrollTop + -delta);
                    this.content.scrollTop(scrollTop + -delta);
                }
            }
        });
        var element = kendo.dom.element;
        var htmlNode = kendo.dom.html;
        var createMetadata = function (levelNum, memberIdx) {
            return {
                maxChildren: 0,
                children: 0,
                maxMembers: 0,
                members: 0,
                measures: 1,
                levelNum: levelNum,
                parentMember: memberIdx !== 0
            };
        };
        var buildPath = function (tuple, index) {
            var path = [];
            var idx = 0;
            for (; idx <= index; idx++) {
                path.push(tuple.members[idx].name);
            }
            return path;
        };
        var tupleName = function (tuple, index) {
            var name = '';
            var idx = 0;
            for (; idx <= index; idx++) {
                name += tuple.members[idx].name;
            }
            return name;
        };
        var ColumnBuilder = Class.extend({
            init: function () {
                this.measures = 1;
                this.metadata = {};
            },
            build: function (tuples) {
                var tbody = this._tbody(tuples);
                var colgroup = this._colGroup();
                return [element('table', null, [
                        colgroup,
                        tbody
                    ])];
            },
            reset: function () {
                this.metadata = {};
            },
            _colGroup: function () {
                var length = this._rowLength();
                var children = [];
                var idx = 0;
                for (; idx < length; idx++) {
                    children.push(element('col', null));
                }
                return element('colgroup', null, children);
            },
            _tbody: function (tuples) {
                var root = tuples[0];
                this.map = {};
                this.rows = [];
                this.rootTuple = root;
                this._indexes = [];
                if (root) {
                    this._buildRows(root, 0);
                    this._normalize();
                } else {
                    this.rows.push(element('tr', null, [element('th', null, [htmlNode('&nbsp;')])]));
                }
                return element('tbody', null, this.rows);
            },
            _normalize: function () {
                var rows = this.rows;
                var rowsLength = rows.length;
                var rowIdx = 0;
                var row;
                var cellsLength;
                var cellIdx;
                var cells;
                var cell;
                for (; rowIdx < rowsLength; rowIdx++) {
                    row = rows[rowIdx];
                    if (row.rowSpan === 1) {
                        continue;
                    }
                    cells = row.children;
                    cellIdx = 0;
                    cellsLength = cells.length;
                    for (; cellIdx < cellsLength; cellIdx++) {
                        cell = cells[cellIdx];
                        if (cell.tupleAll) {
                            cell.attr.rowSpan = row.rowSpan;
                        }
                    }
                }
            },
            _rowIndex: function (row) {
                var rows = this.rows;
                var length = rows.length;
                var idx = 0;
                for (; idx < length; idx++) {
                    if (rows[idx] === row) {
                        break;
                    }
                }
                return idx;
            },
            _rowLength: function () {
                var cells = this.rows[0] ? this.rows[0].children : [];
                var length = cells.length;
                var rowLength = 0;
                var idx = 0;
                if (length) {
                    for (; idx < length; idx++) {
                        rowLength += cells[idx].attr.colSpan || 1;
                    }
                }
                if (!rowLength) {
                    rowLength = this.measures;
                }
                return rowLength;
            },
            _row: function (tuple, memberIdx, parentMember) {
                var rootName = this.rootTuple.members[memberIdx].name;
                var levelNum = tuple.members[memberIdx].levelNum;
                var rowKey = rootName + levelNum;
                var map = this.map;
                var parentRow;
                var children;
                var row = map[rowKey];
                if (!row) {
                    row = element('tr', null, []);
                    row.parentMember = parentMember;
                    row.collapsed = 0;
                    row.colSpan = 0;
                    row.rowSpan = 1;
                    map[rowKey] = row;
                    parentRow = map[rootName + (Number(levelNum) - 1)];
                    if (parentRow) {
                        children = parentRow.children;
                        if (children[1] && children[1].attr.className.indexOf('k-alt') === -1) {
                            row.notFirst = true;
                        } else {
                            row.notFirst = parentRow.notFirst;
                        }
                    }
                    this.rows.splice(this._rowIndex(parentRow) + 1, 0, row);
                } else {
                    row.notFirst = false;
                    if (!row.parentMember || row.parentMember !== parentMember) {
                        row.parentMember = parentMember;
                        row.collapsed = 0;
                        row.colSpan = 0;
                    }
                }
                return row;
            },
            _measures: function (measures, tuple, className) {
                var map = this.map;
                var row = map.measureRow;
                var measure;
                if (!row) {
                    row = element('tr', null, []);
                    map.measureRow = row;
                    this.rows.push(row);
                }
                for (var idx = 0, length = measures.length; idx < length; idx++) {
                    measure = measures[idx];
                    row.children.push(this._cell(className || '', [this._content(measure, tuple)], measure));
                }
                return length;
            },
            _content: function (member, tuple) {
                return htmlNode(this.template({
                    member: member,
                    tuple: tuple
                }));
            },
            _cell: function (className, children, member) {
                var cell = element('th', { className: 'k-header' + className }, children);
                cell.value = member.caption || member.name;
                return cell;
            },
            _buildRows: function (tuple, memberIdx, parentMember) {
                var members = tuple.members;
                var member = members[memberIdx];
                var nextMember = members[memberIdx + 1];
                var row, childRow, children, childrenLength;
                var cell, allCell, cellAttr;
                var cellChildren = [];
                var path;
                var idx = 0;
                var metadata;
                var colSpan;
                var collapsed = 0;
                var memberCollapsed = 0;
                if (member.measure) {
                    this._measures(member.children, tuple);
                    return;
                }
                path = kendo.stringify(buildPath(tuple, memberIdx));
                row = this._row(tuple, memberIdx, parentMember);
                children = member.children;
                childrenLength = children.length;
                metadata = this.metadata[path];
                if (!metadata) {
                    this.metadata[path] = metadata = createMetadata(Number(member.levelNum), memberIdx);
                    metadata.rootLevelNum = Number(this.rootTuple.members[memberIdx].levelNum);
                }
                this._indexes.push({
                    path: path,
                    tuple: tuple
                });
                if (member.hasChildren) {
                    if (metadata.expanded === false) {
                        collapsed = metadata.maxChildren;
                        row.collapsed += collapsed;
                        metadata.children = 0;
                        childrenLength = 0;
                    }
                    cellAttr = { className: 'k-icon ' + (childrenLength ? STATE_EXPANDED : STATE_COLLAPSED) };
                    cellAttr[kendo.attr('path')] = path;
                    cellChildren.push(element('span', cellAttr));
                }
                cellChildren.push(this._content(member, tuple));
                cell = this._cell(row.notFirst ? ' k-first' : '', cellChildren, member);
                row.children.push(cell);
                row.colSpan += 1;
                if (childrenLength) {
                    allCell = this._cell(' k-alt', [this._content(member, tuple)], member);
                    row.children.push(allCell);
                    for (; idx < childrenLength; idx++) {
                        childRow = this._buildRows(children[idx], memberIdx, member);
                    }
                    colSpan = childRow.colSpan;
                    collapsed = childRow.collapsed;
                    cell.attr.colSpan = colSpan;
                    metadata.children = colSpan;
                    metadata.members = 1;
                    row.colSpan += colSpan;
                    row.collapsed += collapsed;
                    row.rowSpan = childRow.rowSpan + 1;
                    if (nextMember) {
                        if (nextMember.measure) {
                            colSpan = this._measures(nextMember.children, tuple, ' k-alt');
                        } else {
                            childRow = this._buildRows(tuple, memberIdx + 1);
                            colSpan = childRow.colSpan;
                            row.collapsed += childRow.collapsed;
                            memberCollapsed = childRow.collapsed;
                        }
                        allCell.attr.colSpan = colSpan;
                        colSpan -= 1;
                        metadata.members += colSpan;
                        row.colSpan += colSpan;
                    }
                } else if (nextMember) {
                    if (nextMember.measure) {
                        colSpan = this._measures(nextMember.children, tuple);
                    } else {
                        childRow = this._buildRows(tuple, memberIdx + 1);
                        colSpan = childRow.colSpan;
                        row.collapsed += childRow.collapsed;
                        memberCollapsed = childRow.collapsed;
                    }
                    metadata.members = colSpan;
                    if (colSpan > 1) {
                        cell.attr.colSpan = colSpan;
                        row.colSpan += colSpan - 1;
                    }
                }
                if (metadata.maxMembers < metadata.members + memberCollapsed) {
                    metadata.maxMembers = metadata.members + memberCollapsed;
                }
                children = metadata.children + collapsed;
                if (metadata.maxChildren < children) {
                    metadata.maxChildren = children;
                }
                (allCell || cell).tupleAll = true;
                return row;
            }
        });
        var RowBuilder = Class.extend({
            init: function () {
                this.metadata = {};
            },
            build: function (tuples) {
                var tbody = this._tbody(tuples);
                var colgroup = this._colGroup();
                return [element('table', null, [
                        colgroup,
                        tbody
                    ])];
            },
            reset: function () {
                this.metadata = {};
            },
            _rowLength: function () {
                var children = this.rows[0].children;
                var length = 0;
                var idx = 0;
                var cell = children[idx];
                while (cell) {
                    length += cell.attr.colSpan || 1;
                    cell = children[++idx];
                }
                return length;
            },
            _colGroup: function () {
                var length = this._rowLength();
                var children = [];
                var idx = 0;
                for (; idx < length; idx++) {
                    children.push(element('col', null));
                }
                return element('colgroup', null, children);
            },
            _tbody: function (tuples) {
                var root = tuples[0];
                this.rootTuple = root;
                this.rows = [];
                this.map = {};
                this._indexes = [];
                if (root) {
                    this._buildRows(root, 0);
                    this._normalize();
                } else {
                    this.rows.push(element('tr', null, [element('td', null, [htmlNode('&nbsp;')])]));
                }
                return element('tbody', null, this.rows);
            },
            _normalize: function () {
                var rows = this.rows;
                var rowsLength = rows.length;
                var rowIdx = 0;
                var members = this.rootTuple.members;
                var firstMemberName = members[0].name;
                var membersLength = members.length;
                var memberIdx = 0;
                var row;
                var cell;
                var maxcolSpan;
                var map = this.map;
                var allRow;
                for (; rowIdx < rowsLength; rowIdx++) {
                    row = rows[rowIdx];
                    for (memberIdx = 0; memberIdx < membersLength; memberIdx++) {
                        maxcolSpan = this[members[memberIdx].name];
                        cell = row.colSpan['dim' + memberIdx];
                        if (cell && cell.colSpan < maxcolSpan) {
                            cell.attr.colSpan = maxcolSpan - cell.colSpan + 1;
                        }
                    }
                }
                row = map[firstMemberName];
                allRow = map[firstMemberName + 'all'];
                if (row) {
                    row.children[0].attr.className = 'k-first';
                }
                if (allRow) {
                    allRow.children[0].attr.className += ' k-first';
                }
            },
            _row: function (children) {
                var row = element('tr', null, children);
                row.rowSpan = 1;
                row.colSpan = {};
                this.rows.push(row);
                return row;
            },
            _content: function (member, tuple) {
                return htmlNode(this.template({
                    member: member,
                    tuple: tuple
                }));
            },
            _cell: function (className, children, member) {
                var cell = element('td', { className: className }, children);
                cell.value = member.caption || member.name;
                return cell;
            },
            _buildRows: function (tuple, memberIdx) {
                var map = this.map;
                var path;
                var members = tuple.members;
                var member = members[memberIdx];
                var nextMember = members[memberIdx + 1];
                var children = member.children;
                var childrenLength = children.length;
                var levelNum = Number(member.levelNum);
                var rootName = this.rootTuple.members[memberIdx].name;
                var tuplePath = buildPath(tuple, memberIdx - 1).join('');
                var rootLevelNum = Number(this.rootTuple.members[memberIdx].levelNum);
                var parentName = tuplePath + (rootLevelNum === levelNum ? '' : member.parentName || '');
                var row = map[parentName + 'all'] || map[parentName];
                var colSpan = levelNum + 1;
                var cell, allCell;
                var childRow, allRow;
                var metadata;
                var className;
                var cellChildren = [];
                var expandIconAttr;
                var idx;
                if (!row || row.hasChild) {
                    row = this._row();
                } else {
                    row.hasChild = true;
                }
                if (member.measure) {
                    className = row.allCell ? 'k-grid-footer' : '';
                    row.children.push(this._cell(className, [this._content(children[0], tuple)], children[0]));
                    row.rowSpan = childrenLength;
                    for (idx = 1; idx < childrenLength; idx++) {
                        this._row([this._cell(className, [this._content(children[idx], tuple)], children[idx])]);
                    }
                    return row;
                }
                map[tuplePath + member.name] = row;
                path = kendo.stringify(buildPath(tuple, memberIdx));
                metadata = this.metadata[path];
                if (!metadata) {
                    this.metadata[path] = metadata = createMetadata(levelNum, memberIdx);
                    metadata.rootLevelNum = rootLevelNum;
                }
                this._indexes.push({
                    path: path,
                    tuple: tuple
                });
                if (member.hasChildren) {
                    if (metadata.expanded === false) {
                        childrenLength = 0;
                        metadata.children = 0;
                    }
                    expandIconAttr = { className: 'k-icon ' + (childrenLength ? STATE_EXPANDED : STATE_COLLAPSED) };
                    expandIconAttr[kendo.attr('path')] = path;
                    cellChildren.push(element('span', expandIconAttr));
                }
                cellChildren.push(this._content(member, tuple));
                className = row.allCell && !childrenLength ? 'k-grid-footer' : '';
                cell = this._cell(className, cellChildren, member);
                cell.colSpan = colSpan;
                row.children.push(cell);
                row.colSpan['dim' + memberIdx] = cell;
                if (!this[rootName] || this[rootName] < colSpan) {
                    this[rootName] = colSpan;
                }
                if (childrenLength) {
                    row.allCell = false;
                    row.hasChild = false;
                    for (idx = 0; idx < childrenLength; idx++) {
                        childRow = this._buildRows(children[idx], memberIdx);
                        if (row !== childRow) {
                            row.rowSpan += childRow.rowSpan;
                        }
                    }
                    if (row.rowSpan > 1) {
                        cell.attr.rowSpan = row.rowSpan;
                    }
                    metadata.children = row.rowSpan;
                    allCell = this._cell('k-grid-footer', [this._content(member, tuple)], member);
                    allCell.colSpan = colSpan;
                    allRow = this._row([allCell]);
                    allRow.colSpan['dim' + memberIdx] = allCell;
                    allRow.allCell = true;
                    map[tuplePath + member.name + 'all'] = allRow;
                    if (nextMember) {
                        childRow = this._buildRows(tuple, memberIdx + 1);
                        allCell.attr.rowSpan = childRow.rowSpan;
                    }
                    row.rowSpan += allRow.rowSpan;
                    metadata.members = allRow.rowSpan;
                } else if (nextMember) {
                    row.hasChild = false;
                    this._buildRows(tuple, memberIdx + 1);
                    (allCell || cell).attr.rowSpan = row.rowSpan;
                    metadata.members = row.rowSpan;
                }
                if (metadata.maxChildren < metadata.children) {
                    metadata.maxChildren = metadata.children;
                }
                if (metadata.maxMembers < metadata.members) {
                    metadata.maxMembers = metadata.members;
                }
                return row;
            }
        });
        var ContentBuilder = Class.extend({
            init: function () {
                this.columnAxis = {};
                this.rowAxis = {};
            },
            build: function (data, columnAxis, rowAxis) {
                var index = columnAxis.indexes[0];
                var metadata = columnAxis.metadata[index ? index.path : undefined];
                this.columnAxis = columnAxis;
                this.rowAxis = rowAxis;
                this.data = data;
                this.rowLength = metadata ? metadata.maxChildren + metadata.maxMembers : columnAxis.measures.length || 1;
                if (!this.rowLength) {
                    this.rowLength = 1;
                }
                var tbody = this._tbody();
                var colgroup = this._colGroup();
                return [element('table', null, [
                        colgroup,
                        tbody
                    ])];
            },
            _colGroup: function () {
                var length = this.columnAxis.measures.length || 1;
                var children = [];
                var idx = 0;
                if (this.rows[0]) {
                    length = this.rows[0].children.length;
                }
                for (; idx < length; idx++) {
                    children.push(element('col', null));
                }
                return element('colgroup', null, children);
            },
            _tbody: function () {
                this.rows = [];
                if (this.data[0]) {
                    this.columnIndexes = this._indexes(this.columnAxis, this.rowLength);
                    this.rowIndexes = this._indexes(this.rowAxis, Math.ceil(this.data.length / this.rowLength));
                    this._buildRows();
                } else {
                    this.rows.push(element('tr', null, [element('td', null, [htmlNode('&nbsp;')])]));
                }
                return element('tbody', null, this.rows);
            },
            _indexes: function (axisInfo, total) {
                var result = [];
                var axisInfoMember;
                var indexes = axisInfo.indexes;
                var metadata = axisInfo.metadata;
                var measures = axisInfo.measures;
                var measuresLength = measures.length || 1;
                var current;
                var dataIdx = 0;
                var firstEmpty = 0;
                var idx = 0;
                var length = indexes.length;
                var measureIdx;
                var index;
                var children;
                var skipChildren;
                if (!length) {
                    for (measureIdx = 0; measureIdx < measuresLength; measureIdx++) {
                        result[measureIdx] = {
                            index: measureIdx,
                            measure: measures[measureIdx],
                            tuple: null
                        };
                    }
                    return result;
                }
                for (; idx < length; idx++) {
                    axisInfoMember = indexes[idx];
                    current = metadata[axisInfoMember.path];
                    children = current.children + current.members;
                    skipChildren = 0;
                    if (children) {
                        children -= measuresLength;
                    }
                    if (current.expanded === false && current.children !== current.maxChildren) {
                        skipChildren = current.maxChildren;
                    }
                    if (current.parentMember && current.levelNum === current.rootLevelNum) {
                        children = -1;
                    }
                    if (children > -1) {
                        for (measureIdx = 0; measureIdx < measuresLength; measureIdx++) {
                            index = children + measureIdx;
                            if (!current.children) {
                                index += firstEmpty;
                            }
                            result[children + firstEmpty + measureIdx] = {
                                children: children,
                                index: dataIdx,
                                measure: measures[measureIdx],
                                tuple: axisInfoMember.tuple
                            };
                            dataIdx += 1;
                        }
                        while (result[firstEmpty] !== undefined) {
                            firstEmpty += 1;
                        }
                    }
                    if (firstEmpty === total) {
                        break;
                    }
                    dataIdx += skipChildren;
                }
                return result;
            },
            _buildRows: function () {
                var rowIndexes = this.rowIndexes;
                var length = rowIndexes.length;
                var idx = 0;
                for (; idx < length; idx++) {
                    var rowIndex = rowIndexes[idx];
                    if (rowIndex) {
                        this.rows.push(this._buildRow(rowIndex));
                    }
                }
            },
            _buildRow: function (rowInfo) {
                var startIdx = rowInfo.index * this.rowLength;
                var columnIndexes = this.columnIndexes;
                var length = columnIndexes.length;
                var columnInfo;
                var cells = [];
                var idx = 0;
                var templateInfo;
                var cell, cellContent;
                var attr, dataItem, measure;
                for (; idx < length; idx++) {
                    columnInfo = columnIndexes[idx];
                    if (columnInfo === undefined) {
                        continue;
                    }
                    attr = {};
                    if (columnInfo.children) {
                        attr.className = 'k-alt';
                    }
                    cellContent = '';
                    dataItem = this.data[startIdx + columnInfo.index];
                    measure = columnInfo.measure || rowInfo.measure;
                    templateInfo = {
                        columnTuple: columnInfo.tuple,
                        rowTuple: rowInfo.tuple,
                        measure: measure,
                        dataItem: dataItem
                    };
                    if (dataItem.value !== '' && measure && measure.type) {
                        if (measure.type === 'status') {
                            cellContent = this.kpiStatusTemplate(templateInfo);
                        } else if (measure.type === 'trend') {
                            cellContent = this.kpiTrendTemplate(templateInfo);
                        }
                    }
                    if (!cellContent) {
                        cellContent = this.dataTemplate(templateInfo);
                    }
                    cell = element('td', attr, [htmlNode(cellContent)]);
                    cell.value = dataItem.value;
                    cells.push(cell);
                }
                attr = {};
                if (rowInfo.children) {
                    attr.className = 'k-grid-footer';
                }
                return element('tr', attr, cells);
            }
        });
        ui.plugin(PivotGrid);
        kendo.PivotExcelExporter = kendo.Class.extend({
            init: function (options) {
                this.options = options;
                this.widget = options.widget;
                this.dataSource = this.widget.dataSource;
            },
            _columns: function () {
                var columnHeaderTable = this.widget.columnsHeaderTree.children[0];
                var rowHeaderTable = this.widget.rowsHeaderTree.children[0];
                var columnHeaderLength = columnHeaderTable.children[0].children.length;
                var rowHeaderLength = rowHeaderTable.children[0].children.length;
                var width = this.widget.options.columnWidth;
                var result = [];
                var idx;
                if (rowHeaderLength && this.dataSource.data()[0]) {
                    for (idx = 0; idx < rowHeaderLength; idx++) {
                        result.push({ autoWidth: true });
                    }
                }
                for (idx = 0; idx < columnHeaderLength; idx++) {
                    result.push({
                        autoWidth: false,
                        width: width
                    });
                }
                return result;
            },
            _cells: function (rows, type, callback) {
                var result = [];
                var i = 0;
                var length = rows.length;
                var cellsLength;
                var row, cells;
                var j, cell;
                for (; i < length; i++) {
                    row = [];
                    cells = rows[i].children;
                    cellsLength = cells.length;
                    for (j = 0; j < cellsLength; j++) {
                        cell = cells[j];
                        row.push({
                            background: '#7a7a7a',
                            color: '#fff',
                            value: cell.value,
                            colSpan: cell.attr.colSpan || 1,
                            rowSpan: cell.attr.rowSpan || 1
                        });
                    }
                    if (callback) {
                        callback(row, i);
                    }
                    result.push({
                        cells: row,
                        type: type
                    });
                }
                return result;
            },
            _rows: function () {
                var columnHeaderTable = this.widget.columnsHeaderTree.children[0];
                var rowHeaderTable = this.widget.rowsHeaderTree.children[0];
                var columnHeaderLength = columnHeaderTable.children[0].children.length;
                var rowHeaderLength = rowHeaderTable.children[0].children.length;
                var columnHeaderRows = columnHeaderTable.children[1].children;
                var rowHeaderRows = rowHeaderTable.children[1].children;
                var contentRows = this.widget.contentTree.children[0].children[1].children;
                var columnRows = this._cells(columnHeaderRows, 'header');
                if (rowHeaderLength) {
                    columnRows[0].cells.splice(0, 0, {
                        background: '#7a7a7a',
                        color: '#fff',
                        value: '',
                        colSpan: rowHeaderLength,
                        rowSpan: columnHeaderRows.length
                    });
                }
                var dataCallback = function (row, index) {
                    var j = 0;
                    var cell, value;
                    var cells = contentRows[index].children;
                    for (; j < columnHeaderLength; j++) {
                        cell = cells[j];
                        value = Number(cell.value);
                        if (isNaN(value)) {
                            value = cell.value;
                        }
                        row.push({
                            background: '#dfdfdf',
                            color: '#333',
                            value: value,
                            colSpan: 1,
                            rowSpan: 1
                        });
                    }
                };
                var rowRows = this._cells(rowHeaderRows, 'data', dataCallback);
                return columnRows.concat(rowRows);
            },
            _freezePane: function () {
                var columnHeaderTable = this.widget.columnsHeaderTree.children[0];
                var rowHeaderTable = this.widget.rowsHeaderTree.children[0];
                var rowHeaderLength = rowHeaderTable.children[0].children.length;
                var columnHeaderRows = columnHeaderTable.children[1].children;
                return {
                    colSplit: rowHeaderLength,
                    rowSplit: columnHeaderRows.length
                };
            },
            workbook: function () {
                var promise;
                if (this.dataSource.view()[0]) {
                    promise = $.Deferred();
                    promise.resolve();
                } else {
                    promise = this.dataSource.fetch();
                }
                return promise.then($.proxy(function () {
                    return {
                        sheets: [{
                                columns: this._columns(),
                                rows: this._rows(),
                                freezePane: this._freezePane(),
                                filter: null
                            }]
                    };
                }, this));
            }
        });
        var PivotExcelMixin = {
            extend: function (proto) {
                proto.events.push('excelExport');
                proto.options.excel = $.extend(proto.options.excel, this.options);
                proto.saveAsExcel = this.saveAsExcel;
            },
            options: {
                proxyURL: '',
                filterable: false,
                fileName: 'Export.xlsx'
            },
            saveAsExcel: function () {
                var excel = this.options.excel || {};
                var exporter = new kendo.PivotExcelExporter({ widget: this });
                exporter.workbook().then($.proxy(function (book) {
                    if (!this.trigger('excelExport', { workbook: book })) {
                        var workbook = new kendo.ooxml.Workbook(book);
                        kendo.saveAs({
                            dataURI: workbook.toDataURL(),
                            fileName: book.fileName || excel.fileName,
                            proxyURL: excel.proxyURL,
                            forceProxy: excel.forceProxy
                        });
                    }
                }, this));
            }
        };
        kendo.PivotExcelMixin = PivotExcelMixin;
        if (kendo.ooxml && kendo.ooxml.Workbook) {
            PivotExcelMixin.extend(PivotGrid.prototype);
        }
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(PivotGrid.prototype);
            PivotGrid.fn._drawPDF = function () {
                return this._drawPDFShadow({ width: this.wrapper.width() }, { avoidLinks: this.options.pdf.avoidLinks });
            };
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.treeview.draganddrop', [
        'kendo.data',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'treeview.draganddrop',
        name: 'Hierarchical Drag & Drop',
        category: 'framework',
        depends: [
            'core',
            'draganddrop'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var ui = kendo.ui;
        var proxy = $.proxy;
        var extend = $.extend;
        var VISIBILITY = 'visibility';
        var KSTATEHOVER = 'k-state-hover';
        var INPUTSELECTOR = 'input,a,textarea,.k-multiselect-wrap,select,button,a.k-button>.k-icon,button.k-button>.k-icon,span.k-icon.k-i-arrow-60-right,span.k-icon.k-i-arrow-45-down-right';
        ui.HierarchicalDragAndDrop = kendo.Class.extend({
            init: function (element, options) {
                this.element = element;
                this.hovered = element;
                this.options = extend({
                    dragstart: $.noop,
                    drag: $.noop,
                    drop: $.noop,
                    dragend: $.noop
                }, options);
                this._draggable = new ui.Draggable(element, {
                    ignore: INPUTSELECTOR,
                    filter: options.filter,
                    autoScroll: options.autoScroll,
                    cursorOffset: {
                        left: 10,
                        top: kendo.support.mobileOS ? -40 / kendo.support.zoomLevel() : 10
                    },
                    hint: proxy(this._hint, this),
                    dragstart: proxy(this.dragstart, this),
                    dragcancel: proxy(this.dragcancel, this),
                    drag: proxy(this.drag, this),
                    dragend: proxy(this.dragend, this),
                    $angular: options.$angular
                });
            },
            _hint: function (element) {
                return '<div class=\'k-header k-drag-clue\'>' + '<span class=\'k-icon k-drag-status\' />' + this.options.hintText(element) + '</div>';
            },
            _removeTouchHover: function () {
                if (kendo.support.touch && this.hovered) {
                    this.hovered.find('.' + KSTATEHOVER).removeClass(KSTATEHOVER);
                    this.hovered = false;
                }
            },
            _hintStatus: function (newStatus) {
                var statusElement = this._draggable.hint.find('.k-drag-status')[0];
                if (newStatus) {
                    statusElement.className = 'k-icon k-drag-status ' + newStatus;
                } else {
                    return $.trim(statusElement.className.replace(/(p|k)-(icon|drag-status)/g, ''));
                }
            },
            dragstart: function (e) {
                this.source = e.currentTarget.closest(this.options.itemSelector);
                if (this.options.dragstart(this.source)) {
                    e.preventDefault();
                }
                if (this.options.reorderable) {
                    this.dropHint = $('<div class=\'k-i-drag-and-drop\' />').css(VISIBILITY, 'hidden').appendTo(this.element);
                } else {
                    this.dropHint = $();
                }
            },
            drag: function (e) {
                var options = this.options;
                var source = this.source;
                var target = this.dropTarget = $(kendo.eventTarget(e));
                var container = target.closest(options.allowedContainers);
                var hoveredItem, itemHeight, itemTop, itemContent, delta;
                var insertOnTop, insertOnBottom, addChild;
                var itemData, position, status;
                if (!container.length) {
                    status = 'k-i-cancel';
                    this._removeTouchHover();
                } else if (source[0] == target[0] || options.contains(source[0], target[0])) {
                    status = 'k-i-cancel';
                } else {
                    status = 'k-i-insert-middle';
                    itemData = options.itemFromTarget(target);
                    hoveredItem = itemData.item;
                    if (hoveredItem.length) {
                        this._removeTouchHover();
                        itemHeight = kendo._outerHeight(hoveredItem);
                        itemContent = itemData.content;
                        if (options.reorderable) {
                            delta = itemHeight / (itemContent.length > 0 ? 4 : 2);
                            itemTop = kendo.getOffset(hoveredItem).top;
                            insertOnTop = e.y.location < itemTop + delta;
                            insertOnBottom = itemTop + itemHeight - delta < e.y.location;
                            addChild = itemContent.length && !insertOnTop && !insertOnBottom;
                        } else {
                            addChild = true;
                            insertOnTop = false;
                            insertOnBottom = false;
                        }
                        this.hovered = addChild ? container : false;
                        this.dropHint.css(VISIBILITY, addChild ? 'hidden' : 'visible');
                        if (this._lastHover && this._lastHover[0] != itemContent[0]) {
                            this._lastHover.removeClass(KSTATEHOVER);
                        }
                        this._lastHover = itemContent.toggleClass(KSTATEHOVER, addChild);
                        if (addChild) {
                            status = 'k-i-plus';
                        } else {
                            position = hoveredItem.position();
                            position.top += insertOnTop ? 0 : itemHeight;
                            this.dropHint.css(position)[insertOnTop ? 'prependTo' : 'appendTo'](options.dropHintContainer(hoveredItem));
                            if (insertOnTop && itemData.first) {
                                status = 'k-i-insert-up';
                            }
                            if (insertOnBottom && itemData.last) {
                                status = 'k-i-insert-down';
                            }
                        }
                    } else if (target[0] != this.dropHint[0]) {
                        if (this._lastHover) {
                            this._lastHover.removeClass(KSTATEHOVER);
                        }
                        if (!$.contains(this.element[0], container[0])) {
                            status = 'k-i-plus';
                        } else {
                            status = 'k-i-cancel';
                        }
                    }
                }
                this.options.drag({
                    originalEvent: e.originalEvent,
                    source: source,
                    target: target,
                    pageY: e.y.location,
                    pageX: e.x.location,
                    status: status.substring(2),
                    setStatus: function (value) {
                        status = value;
                    }
                });
                if (status.indexOf('k-i-insert') !== 0) {
                    this.dropHint.css(VISIBILITY, 'hidden');
                }
                this._hintStatus(status);
            },
            dragcancel: function () {
                this.dropHint.remove();
            },
            dragend: function (e) {
                var position = 'over', source = this.source, destination, dropHint = this.dropHint, dropTarget = this.dropTarget, eventArgs, dropPrevented;
                if (dropHint.css(VISIBILITY) == 'visible') {
                    position = this.options.dropPositionFrom(dropHint);
                    destination = dropHint.closest(this.options.itemSelector);
                } else if (dropTarget) {
                    destination = dropTarget.closest(this.options.itemSelector);
                    if (!destination.length) {
                        destination = dropTarget.closest(this.options.allowedContainers);
                    }
                }
                eventArgs = {
                    originalEvent: e.originalEvent,
                    source: source[0],
                    destination: destination[0],
                    valid: this._hintStatus() != 'k-i-cancel',
                    setValid: function (newValid) {
                        this.valid = newValid;
                    },
                    dropTarget: dropTarget[0],
                    position: position
                };
                dropPrevented = this.options.drop(eventArgs);
                dropHint.remove();
                this._removeTouchHover();
                if (this._lastHover) {
                    this._lastHover.removeClass(KSTATEHOVER);
                }
                if (!eventArgs.valid || dropPrevented) {
                    this._draggable.dropped = eventArgs.valid;
                    return;
                }
                this._draggable.dropped = true;
                this.options.dragend({
                    originalEvent: e.originalEvent,
                    source: source,
                    destination: destination,
                    position: position
                });
            },
            destroy: function () {
                this._lastHover = this.hovered = null;
                this._draggable.destroy();
            }
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.treeview', [
        'kendo.data',
        'kendo.treeview.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'treeview',
        name: 'TreeView',
        category: 'web',
        description: 'The TreeView widget displays hierarchical data in a traditional tree structure,with support for interactive drag-and-drop operations.',
        depends: ['data'],
        features: [{
                id: 'treeview-dragging',
                name: 'Drag & Drop',
                description: 'Support for drag & drop',
                depends: ['treeview.draganddrop']
            }]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, data = kendo.data, extend = $.extend, template = kendo.template, isArray = $.isArray, Widget = ui.Widget, HierarchicalDataSource = data.HierarchicalDataSource, proxy = $.proxy, keys = kendo.keys, NS = '.kendoTreeView', SELECT = 'select', CHECK = 'check', NAVIGATE = 'navigate', EXPAND = 'expand', CHANGE = 'change', ERROR = 'error', CHECKED = 'checked', INDETERMINATE = 'indeterminate', COLLAPSE = 'collapse', DRAGSTART = 'dragstart', DRAG = 'drag', DROP = 'drop', DRAGEND = 'dragend', DATABOUND = 'dataBound', CLICK = 'click', UNDEFINED = 'undefined', KSTATEHOVER = 'k-state-hover', KTREEVIEW = 'k-treeview', VISIBLE = ':visible', NODE = '.k-item', STRING = 'string', ARIASELECTED = 'aria-selected', ARIADISABLED = 'aria-disabled', TreeView, subGroup, nodeContents, nodeIcon, spriteRe, bindings = {
                text: 'dataTextField',
                url: 'dataUrlField',
                spriteCssClass: 'dataSpriteCssClassField',
                imageUrl: 'dataImageUrlField'
            }, isDomElement = function (o) {
                return typeof HTMLElement === 'object' ? o instanceof HTMLElement : o && typeof o === 'object' && o.nodeType === 1 && typeof o.nodeName === STRING;
            };
        function contentChild(filter) {
            return function (node) {
                var result = node.children('.k-animation-container');
                if (!result.length) {
                    result = node;
                }
                return result.children(filter);
            };
        }
        function templateNoWith(code) {
            return kendo.template(code, { useWithBlock: false });
        }
        subGroup = contentChild('.k-group');
        nodeContents = contentChild('.k-group,.k-content');
        nodeIcon = function (node) {
            return node.children('div').children('.k-icon');
        };
        function checkboxes(node) {
            return node.find('> div .k-checkbox-wrapper [type=checkbox]');
        }
        function insertAction(indexOffset) {
            return function (nodeData, referenceNode) {
                referenceNode = referenceNode.closest(NODE);
                var group = referenceNode.parent(), parentNode;
                if (group.parent().is('li')) {
                    parentNode = group.parent();
                }
                return this._dataSourceMove(nodeData, group, parentNode, function (dataSource, model) {
                    return this._insert(dataSource.data(), model, referenceNode.index() + indexOffset);
                });
            };
        }
        spriteRe = /k-sprite/;
        function moveContents(node, container) {
            var tmp;
            while (node && node.nodeName.toLowerCase() != 'ul') {
                tmp = node;
                node = node.nextSibling;
                if (tmp.nodeType == 3) {
                    tmp.nodeValue = $.trim(tmp.nodeValue);
                }
                if (spriteRe.test(tmp.className)) {
                    container.insertBefore(tmp, container.firstChild);
                } else {
                    container.appendChild(tmp);
                }
            }
        }
        function updateNodeHtml(node) {
            var wrapper = node.children('div'), group = node.children('ul'), toggleButton = wrapper.children('.k-icon'), checkbox = node.children(':checkbox'), innerWrapper = wrapper.children('.k-in');
            if (node.hasClass('k-treeview')) {
                return;
            }
            if (!wrapper.length) {
                wrapper = $('<div />').prependTo(node);
            }
            if (!toggleButton.length && group.length) {
                toggleButton = $('<span class=\'k-icon\' />').prependTo(wrapper);
            } else if (!group.length || !group.children().length) {
                toggleButton.remove();
                group.remove();
            }
            if (checkbox.length) {
                $('<span class=\'k-checkbox-wrapper\' />').appendTo(wrapper).append(checkbox);
            }
            if (!innerWrapper.length) {
                innerWrapper = node.children('a').eq(0).addClass('k-in k-link');
                if (!innerWrapper.length) {
                    innerWrapper = $('<span class=\'k-in\' />');
                }
                innerWrapper.appendTo(wrapper);
                if (wrapper.length) {
                    moveContents(wrapper[0].nextSibling, innerWrapper[0]);
                }
            }
        }
        TreeView = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                var that = this, inferred = false, hasDataSource = options && !!options.dataSource, list;
                if (isArray(options)) {
                    options = { dataSource: options };
                }
                if (options && typeof options.loadOnDemand == UNDEFINED && isArray(options.dataSource)) {
                    options.loadOnDemand = false;
                }
                Widget.prototype.init.call(that, element, options);
                element = that.element;
                options = that.options;
                list = element.is('ul') && element || element.hasClass(KTREEVIEW) && element.children('ul');
                inferred = !hasDataSource && list.length;
                if (inferred) {
                    options.dataSource.list = list;
                }
                that._animation();
                that._accessors();
                that._templates();
                if (!element.hasClass(KTREEVIEW)) {
                    that._wrapper();
                    if (list) {
                        that.root = element;
                        that._group(that.wrapper);
                    }
                } else {
                    that.wrapper = element;
                    that.root = element.children('ul').eq(0);
                }
                that._tabindex();
                that.root.attr('role', 'tree');
                that._dataSource(inferred);
                that._attachEvents();
                that._dragging();
                if (!inferred) {
                    if (options.autoBind) {
                        that._progress(true);
                        that.dataSource.fetch();
                    }
                } else {
                    that._syncHtmlAndDataSource();
                }
                if (options.checkboxes && options.checkboxes.checkChildren) {
                    that.updateIndeterminate();
                }
                if (that.element[0].id) {
                    that._ariaId = kendo.format('{0}_tv_active', that.element[0].id);
                }
                kendo.notify(that);
            },
            _attachEvents: function () {
                var that = this, clickableItems = '.k-in:not(.k-state-selected,.k-state-disabled)', MOUSEENTER = 'mouseenter';
                that.wrapper.on(MOUSEENTER + NS, '.k-in.k-state-selected', function (e) {
                    e.preventDefault();
                }).on(MOUSEENTER + NS, clickableItems, function () {
                    $(this).addClass(KSTATEHOVER);
                }).on('mouseleave' + NS, clickableItems, function () {
                    $(this).removeClass(KSTATEHOVER);
                }).on(CLICK + NS, clickableItems, proxy(that._click, that)).on('dblclick' + NS, '.k-in:not(.k-state-disabled)', proxy(that._toggleButtonClick, that)).on(CLICK + NS, '.k-i-expand,.k-i-collapse', proxy(that._toggleButtonClick, that)).on('keydown' + NS, proxy(that._keydown, that)).on('focus' + NS, proxy(that._focus, that)).on('blur' + NS, proxy(that._blur, that)).on('mousedown' + NS, '.k-in,.k-checkbox-wrapper :checkbox,.k-i-expand,.k-i-collapse', proxy(that._mousedown, that)).on('change' + NS, '.k-checkbox-wrapper :checkbox', proxy(that._checkboxChange, that)).on('click' + NS, '.k-checkbox-wrapper :checkbox', proxy(that._checkboxClick, that)).on('click' + NS, '.k-checkbox-label', proxy(that._checkboxLabelClick, that)).on('click' + NS, '.k-request-retry', proxy(that._retryRequest, that)).on('click' + NS, function (e) {
                    if (!$(e.target).is(':kendoFocusable')) {
                        that.focus();
                    }
                });
            },
            _checkboxClick: function (e) {
                var checkbox = $(e.target);
                if (checkbox.data(INDETERMINATE)) {
                    checkbox.data(INDETERMINATE, false).prop(INDETERMINATE, false).prop(CHECKED, true);
                    this._checkboxChange(e);
                }
            },
            _checkboxLabelClick: function (e) {
                e.target.previousSibling.click();
            },
            _syncHtmlAndDataSource: function (root, dataSource) {
                root = root || this.root;
                dataSource = dataSource || this.dataSource;
                var data = dataSource.view(), uidAttr = kendo.attr('uid'), expandedAttr = kendo.attr('expanded'), checkboxesEnabled = this.options.checkboxes, items = root.children('li'), i, item, dataItem, uid, itemCheckbox;
                for (i = 0; i < items.length; i++) {
                    dataItem = data[i];
                    uid = dataItem.uid;
                    item = items.eq(i);
                    item.attr('role', 'treeitem').attr(uidAttr, uid);
                    dataItem.expanded = item.attr(expandedAttr) === 'true';
                    if (checkboxesEnabled) {
                        itemCheckbox = checkboxes(item);
                        dataItem.checked = itemCheckbox.prop(CHECKED);
                        itemCheckbox.attr('id', '_' + uid);
                        itemCheckbox.next('.k-checkbox-label').attr('for', '_' + uid);
                    }
                    this._syncHtmlAndDataSource(item.children('ul'), dataItem.children);
                }
            },
            _animation: function () {
                var options = this.options, animationOptions = options.animation, hasCollapseAnimation = animationOptions.collapse && 'effects' in animationOptions.collapse, collapse = extend({}, animationOptions.expand, animationOptions.collapse);
                if (!hasCollapseAnimation) {
                    collapse = extend(collapse, { reverse: true });
                }
                if (animationOptions === false) {
                    animationOptions = {
                        expand: { effects: {} },
                        collapse: {
                            hide: true,
                            effects: {}
                        }
                    };
                }
                animationOptions.collapse = extend(collapse, { hide: true });
                options.animation = animationOptions;
            },
            _dragging: function () {
                var enabled = this.options.dragAndDrop;
                var dragging = this.dragging;
                if (enabled && !dragging) {
                    var widget = this;
                    this.dragging = new ui.HierarchicalDragAndDrop(this.element, {
                        reorderable: true,
                        $angular: this.options.$angular,
                        autoScroll: this.options.autoScroll,
                        filter: 'div:not(.k-state-disabled) .k-in',
                        allowedContainers: '.k-treeview',
                        itemSelector: '.k-treeview .k-item',
                        hintText: proxy(this._hintText, this),
                        contains: function (source, destination) {
                            return $.contains(source, destination);
                        },
                        dropHintContainer: function (item) {
                            return item;
                        },
                        itemFromTarget: function (target) {
                            var item = target.closest('.k-top,.k-mid,.k-bot');
                            return {
                                item: item,
                                content: target.closest('.k-in'),
                                first: item.hasClass('k-top'),
                                last: item.hasClass('k-bot')
                            };
                        },
                        dropPositionFrom: function (dropHint) {
                            return dropHint.prevAll('.k-in').length > 0 ? 'after' : 'before';
                        },
                        dragstart: function (source) {
                            return widget.trigger(DRAGSTART, { sourceNode: source[0] });
                        },
                        drag: function (options) {
                            widget.trigger(DRAG, {
                                originalEvent: options.originalEvent,
                                sourceNode: options.source[0],
                                dropTarget: options.target[0],
                                pageY: options.pageY,
                                pageX: options.pageX,
                                statusClass: options.status,
                                setStatusClass: options.setStatus
                            });
                        },
                        drop: function (options) {
                            return widget.trigger(DROP, {
                                originalEvent: options.originalEvent,
                                sourceNode: options.source,
                                destinationNode: options.destination,
                                valid: options.valid,
                                setValid: function (state) {
                                    this.valid = state;
                                    options.setValid(state);
                                },
                                dropTarget: options.dropTarget,
                                dropPosition: options.position
                            });
                        },
                        dragend: function (options) {
                            var source = options.source;
                            var destination = options.destination;
                            var position = options.position;
                            function triggerDragEnd(source) {
                                widget.updateIndeterminate();
                                widget.trigger(DRAGEND, {
                                    originalEvent: options.originalEvent,
                                    sourceNode: source && source[0],
                                    destinationNode: destination[0],
                                    dropPosition: position
                                });
                            }
                            if (position == 'over') {
                                widget.append(source, destination, triggerDragEnd);
                            } else {
                                if (position == 'before') {
                                    source = widget.insertBefore(source, destination);
                                } else if (position == 'after') {
                                    source = widget.insertAfter(source, destination);
                                }
                                triggerDragEnd(source);
                            }
                        }
                    });
                } else if (!enabled && dragging) {
                    dragging.destroy();
                    this.dragging = null;
                }
            },
            _hintText: function (node) {
                return this.templates.dragClue({
                    item: this.dataItem(node),
                    treeview: this.options
                });
            },
            _templates: function () {
                var that = this, options = that.options, fieldAccessor = proxy(that._fieldAccessor, that);
                if (options.template && typeof options.template == STRING) {
                    options.template = template(options.template);
                } else if (!options.template) {
                    options.template = templateNoWith('# var text = ' + fieldAccessor('text') + '(data.item); #' + '# if (typeof data.item.encoded != \'undefined\' && data.item.encoded === false) {#' + '#= text #' + '# } else { #' + '#: text #' + '# } #');
                }
                that._checkboxes();
                that.templates = {
                    wrapperCssClass: function (group, item) {
                        var result = 'k-item', index = item.index;
                        if (group.firstLevel && index === 0) {
                            result += ' k-first';
                        }
                        if (index == group.length - 1) {
                            result += ' k-last';
                        }
                        return result;
                    },
                    cssClass: function (group, item) {
                        var result = '', index = item.index, groupLength = group.length - 1;
                        if (group.firstLevel && index === 0) {
                            result += 'k-top ';
                        }
                        if (index === 0 && index != groupLength) {
                            result += 'k-top';
                        } else if (index == groupLength) {
                            result += 'k-bot';
                        } else {
                            result += 'k-mid';
                        }
                        return result;
                    },
                    textClass: function (item, isLink) {
                        var result = 'k-in';
                        if (isLink) {
                            result += ' k-link';
                        }
                        if (item.enabled === false) {
                            result += ' k-state-disabled';
                        }
                        if (item.selected === true) {
                            result += ' k-state-selected';
                        }
                        return result;
                    },
                    toggleButtonClass: function (item) {
                        var result = 'k-icon';
                        if (item.expanded !== true) {
                            result += ' k-i-expand';
                        } else {
                            result += ' k-i-collapse';
                        }
                        return result;
                    },
                    groupAttributes: function (group) {
                        var attributes = '';
                        if (!group.firstLevel) {
                            attributes = 'role=\'group\'';
                        }
                        return attributes + (group.expanded !== true ? ' style=\'display:none\'' : '');
                    },
                    groupCssClass: function (group) {
                        var cssClass = 'k-group';
                        if (group.firstLevel) {
                            cssClass += ' k-treeview-lines';
                        }
                        return cssClass;
                    },
                    dragClue: templateNoWith('#= data.treeview.template(data) #'),
                    group: templateNoWith('<ul class=\'#= data.r.groupCssClass(data.group) #\'#= data.r.groupAttributes(data.group) #>' + '#= data.renderItems(data) #' + '</ul>'),
                    itemContent: templateNoWith('# var imageUrl = ' + fieldAccessor('imageUrl') + '(data.item); #' + '# var spriteCssClass = ' + fieldAccessor('spriteCssClass') + '(data.item); #' + '# if (imageUrl) { #' + '<img class=\'k-image\' alt=\'\' src=\'#= imageUrl #\'>' + '# } #' + '# if (spriteCssClass) { #' + '<span class=\'k-sprite #= spriteCssClass #\' />' + '# } #' + '#= data.treeview.template(data) #'),
                    itemElement: templateNoWith('# var item = data.item, r = data.r; #' + '# var url = ' + fieldAccessor('url') + '(item); #' + '<div class=\'#= r.cssClass(data.group, item) #\'>' + '# if (item.hasChildren) { #' + '<span class=\'#= r.toggleButtonClass(item) #\'/>' + '# } #' + '# if (data.treeview.checkboxes) { #' + '<span class=\'k-checkbox-wrapper\' role=\'presentation\'>' + '#= data.treeview.checkboxes.template(data) #' + '</span>' + '# } #' + '# var tag = url ? \'a\' : \'span\'; #' + '# var textAttr = url ? \' href=\\\'\' + url + \'\\\'\' : \'\'; #' + '<#=tag# class=\'#= r.textClass(item, !!url) #\'#= textAttr #>' + '#= r.itemContent(data) #' + '</#=tag#>' + '</div>'),
                    item: templateNoWith('# var item = data.item, r = data.r; #' + '<li role=\'treeitem\' class=\'#= r.wrapperCssClass(data.group, item) #\' ' + kendo.attr('uid') + '=\'#= item.uid #\' ' + 'aria-selected=\'#= item.selected ? "true" : "false " #\' ' + '#=item.enabled === false ? "aria-disabled=\'true\'" : \'\'#' + '# if (item.expanded) { #' + 'data-expanded=\'true\' aria-expanded=\'true\'' + '# } #' + '>' + '#= r.itemElement(data) #' + '</li>'),
                    loading: templateNoWith('<div class=\'k-icon k-i-loading\' /> #: data.messages.loading #'),
                    retry: templateNoWith('#: data.messages.requestFailed # ' + '<button class=\'k-button k-request-retry\'>#: data.messages.retry #</button>')
                };
            },
            items: function () {
                return this.element.find('.k-item > div:first-child');
            },
            setDataSource: function (dataSource) {
                var options = this.options;
                options.dataSource = dataSource;
                this._dataSource();
                if (options.checkboxes && options.checkboxes.checkChildren) {
                    this.dataSource.one('change', $.proxy(this.updateIndeterminate, this, null));
                }
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            _bindDataSource: function () {
                this._refreshHandler = proxy(this.refresh, this);
                this._errorHandler = proxy(this._error, this);
                this.dataSource.bind(CHANGE, this._refreshHandler);
                this.dataSource.bind(ERROR, this._errorHandler);
            },
            _unbindDataSource: function () {
                var dataSource = this.dataSource;
                if (dataSource) {
                    dataSource.unbind(CHANGE, this._refreshHandler);
                    dataSource.unbind(ERROR, this._errorHandler);
                }
            },
            _dataSource: function (silentRead) {
                var that = this, options = that.options, dataSource = options.dataSource;
                function recursiveRead(data) {
                    for (var i = 0; i < data.length; i++) {
                        data[i]._initChildren();
                        data[i].children.fetch();
                        recursiveRead(data[i].children.view());
                    }
                }
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                that._unbindDataSource();
                if (!dataSource.fields) {
                    dataSource.fields = [
                        { field: 'text' },
                        { field: 'url' },
                        { field: 'spriteCssClass' },
                        { field: 'imageUrl' }
                    ];
                }
                that.dataSource = dataSource = HierarchicalDataSource.create(dataSource);
                if (silentRead) {
                    dataSource.fetch();
                    recursiveRead(dataSource.view());
                }
                that._bindDataSource();
            },
            events: [
                DRAGSTART,
                DRAG,
                DROP,
                DRAGEND,
                DATABOUND,
                EXPAND,
                COLLAPSE,
                SELECT,
                CHANGE,
                NAVIGATE,
                CHECK
            ],
            options: {
                name: 'TreeView',
                dataSource: {},
                animation: {
                    expand: {
                        effects: 'expand:vertical',
                        duration: 200
                    },
                    collapse: { duration: 100 }
                },
                messages: {
                    loading: 'Loading...',
                    requestFailed: 'Request failed.',
                    retry: 'Retry'
                },
                dragAndDrop: false,
                checkboxes: false,
                autoBind: true,
                autoScroll: false,
                loadOnDemand: true,
                template: '',
                dataTextField: null
            },
            _accessors: function () {
                var that = this, options = that.options, i, field, textField, element = that.element;
                for (i in bindings) {
                    field = options[bindings[i]];
                    textField = element.attr(kendo.attr(i + '-field'));
                    if (!field && textField) {
                        field = textField;
                    }
                    if (!field) {
                        field = i;
                    }
                    if (!isArray(field)) {
                        field = [field];
                    }
                    options[bindings[i]] = field;
                }
            },
            _fieldAccessor: function (fieldName) {
                var fieldBindings = this.options[bindings[fieldName]], count = fieldBindings.length, result = '(function(item) {';
                if (count === 0) {
                    result += 'return item[\'' + fieldName + '\'];';
                } else {
                    result += 'var levels = [' + $.map(fieldBindings, function (x) {
                        return 'function(d){ return ' + kendo.expr(x) + '}';
                    }).join(',') + '];';
                    result += 'return levels[Math.min(item.level(), ' + count + '-1)](item)';
                }
                result += '})';
                return result;
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._animation();
                this._dragging();
                this._templates();
            },
            _trigger: function (eventName, node) {
                return this.trigger(eventName, { node: node.closest(NODE)[0] });
            },
            _setChecked: function (datasource, value) {
                if (!datasource || !$.isFunction(datasource.view)) {
                    return;
                }
                for (var i = 0, nodes = datasource.view(); i < nodes.length; i++) {
                    nodes[i][CHECKED] = value;
                    if (nodes[i].children) {
                        this._setChecked(nodes[i].children, value);
                    }
                }
            },
            _setIndeterminate: function (node) {
                var group = subGroup(node), siblings, length, all = true, i;
                if (!group.length) {
                    return;
                }
                siblings = checkboxes(group.children());
                length = siblings.length;
                if (!length) {
                    return;
                } else if (length > 1) {
                    for (i = 1; i < length; i++) {
                        if (siblings[i].checked != siblings[i - 1].checked || siblings[i].indeterminate || siblings[i - 1].indeterminate) {
                            all = false;
                            break;
                        }
                    }
                } else {
                    all = !siblings[0].indeterminate;
                }
                return checkboxes(node).data(INDETERMINATE, !all).prop(INDETERMINATE, !all).prop(CHECKED, all && siblings[0].checked);
            },
            updateIndeterminate: function (node) {
                node = node || this.wrapper;
                var subnodes = subGroup(node).children();
                var i;
                var checkbox;
                if (subnodes.length) {
                    for (i = 0; i < subnodes.length; i++) {
                        this.updateIndeterminate(subnodes.eq(i));
                    }
                    checkbox = this._setIndeterminate(node);
                    if (checkbox && checkbox.prop(CHECKED)) {
                        this.dataItem(node).checked = true;
                    }
                }
            },
            _bubbleIndeterminate: function (node) {
                if (!node.length) {
                    return;
                }
                var parentNode = this.parent(node), checkbox;
                if (parentNode.length) {
                    this._setIndeterminate(parentNode);
                    checkbox = parentNode.children('div').find('.k-checkbox-wrapper :checkbox');
                    if (checkbox.prop(INDETERMINATE) === false) {
                        this.dataItem(parentNode).set(CHECKED, checkbox.prop(CHECKED));
                    } else {
                        delete this.dataItem(parentNode).checked;
                    }
                    this._bubbleIndeterminate(parentNode);
                }
            },
            _checkboxChange: function (e) {
                var checkbox = $(e.target);
                var isChecked = checkbox.prop(CHECKED);
                var node = checkbox.closest(NODE);
                var dataItem = this.dataItem(node);
                if (dataItem.checked != isChecked) {
                    dataItem.set(CHECKED, isChecked);
                    this._trigger(CHECK, node);
                }
            },
            _toggleButtonClick: function (e) {
                var node = $(e.currentTarget).closest(NODE);
                if (node.is('[aria-disabled=\'true\']')) {
                    return;
                }
                this.toggle($(e.target).closest(NODE));
            },
            _mousedown: function (e) {
                var node = $(e.currentTarget).closest(NODE);
                if (node.is('[aria-disabled=\'true\']')) {
                    return;
                }
                this._clickTarget = node;
                this.current(node);
            },
            _focusable: function (node) {
                return node && node.length && node.is(':visible') && !node.find('.k-in:first').hasClass('k-state-disabled');
            },
            _focus: function () {
                var current = this.select(), clickTarget = this._clickTarget;
                if (kendo.support.touch) {
                    return;
                }
                if (clickTarget && clickTarget.length) {
                    current = clickTarget;
                }
                if (!this._focusable(current)) {
                    current = this.current();
                }
                if (!this._focusable(current)) {
                    current = this._nextVisible($());
                }
                this.current(current);
            },
            focus: function () {
                var wrapper = this.wrapper, scrollContainer = wrapper[0], containers = [], offsets = [], documentElement = document.documentElement, i;
                do {
                    scrollContainer = scrollContainer.parentNode;
                    if (scrollContainer.scrollHeight > scrollContainer.clientHeight) {
                        containers.push(scrollContainer);
                        offsets.push(scrollContainer.scrollTop);
                    }
                } while (scrollContainer != documentElement);
                wrapper.focus();
                for (i = 0; i < containers.length; i++) {
                    containers[i].scrollTop = offsets[i];
                }
            },
            _blur: function () {
                this.current().find('.k-in:first').removeClass('k-state-focused');
            },
            _enabled: function (node) {
                return !node.children('div').children('.k-in').hasClass('k-state-disabled');
            },
            parent: function (node) {
                var wrapperRe = /\bk-treeview\b/, itemRe = /\bk-item\b/, result, skipSelf;
                if (typeof node == STRING) {
                    node = this.element.find(node);
                }
                if (!isDomElement(node)) {
                    node = node[0];
                }
                skipSelf = itemRe.test(node.className);
                do {
                    node = node.parentNode;
                    if (itemRe.test(node.className)) {
                        if (skipSelf) {
                            result = node;
                        } else {
                            skipSelf = true;
                        }
                    }
                } while (!wrapperRe.test(node.className) && !result);
                return $(result);
            },
            _nextVisible: function (node) {
                var that = this, expanded = that._expanded(node), result;
                function nextParent(node) {
                    while (node.length && !node.next().length) {
                        node = that.parent(node);
                    }
                    if (node.next().length) {
                        return node.next();
                    } else {
                        return node;
                    }
                }
                if (!node.length || !node.is(':visible')) {
                    result = that.root.children().eq(0);
                } else if (expanded) {
                    result = subGroup(node).children().first();
                    if (!result.length) {
                        result = nextParent(node);
                    }
                } else {
                    result = nextParent(node);
                }
                if (!that._enabled(result)) {
                    result = that._nextVisible(result);
                }
                return result;
            },
            _previousVisible: function (node) {
                var that = this, lastChild, result;
                if (!node.length || node.prev().length) {
                    if (node.length) {
                        result = node.prev();
                    } else {
                        result = that.root.children().last();
                    }
                    while (that._expanded(result)) {
                        lastChild = subGroup(result).children().last();
                        if (!lastChild.length) {
                            break;
                        }
                        result = lastChild;
                    }
                } else {
                    result = that.parent(node) || node;
                }
                if (!that._enabled(result)) {
                    result = that._previousVisible(result);
                }
                return result;
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, target, focused = that.current(), expanded = that._expanded(focused), checkbox = focused.find('.k-checkbox-wrapper:first :checkbox'), rtl = kendo.support.isRtl(that.element);
                if (e.target != e.currentTarget) {
                    return;
                }
                if (!rtl && key == keys.RIGHT || rtl && key == keys.LEFT) {
                    if (expanded) {
                        target = that._nextVisible(focused);
                    } else {
                        that.expand(focused);
                    }
                } else if (!rtl && key == keys.LEFT || rtl && key == keys.RIGHT) {
                    if (expanded) {
                        that.collapse(focused);
                    } else {
                        target = that.parent(focused);
                        if (!that._enabled(target)) {
                            target = undefined;
                        }
                    }
                } else if (key == keys.DOWN) {
                    target = that._nextVisible(focused);
                } else if (key == keys.UP) {
                    target = that._previousVisible(focused);
                } else if (key == keys.HOME) {
                    target = that._nextVisible($());
                } else if (key == keys.END) {
                    target = that._previousVisible($());
                } else if (key == keys.ENTER) {
                    if (!focused.find('.k-in:first').hasClass('k-state-selected')) {
                        if (!that._trigger(SELECT, focused)) {
                            that.select(focused);
                        }
                    }
                } else if (key == keys.SPACEBAR && checkbox.length) {
                    checkbox.prop(CHECKED, !checkbox.prop(CHECKED)).data(INDETERMINATE, false).prop(INDETERMINATE, false);
                    that._checkboxChange({ target: checkbox });
                    target = focused;
                }
                if (target) {
                    e.preventDefault();
                    if (focused[0] != target[0]) {
                        that._trigger(NAVIGATE, target);
                        that.current(target);
                    }
                }
            },
            _click: function (e) {
                var that = this, node = $(e.currentTarget), contents = nodeContents(node.closest(NODE)), href = node.attr('href'), shouldNavigate;
                if (href) {
                    shouldNavigate = href == '#' || href.indexOf('#' + this.element.id + '-') >= 0;
                } else {
                    shouldNavigate = contents.length && !contents.children().length;
                }
                if (shouldNavigate) {
                    e.preventDefault();
                }
                if (!node.hasClass('.k-state-selected') && !that._trigger(SELECT, node)) {
                    that.select(node);
                }
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper, root, wrapperClasses = 'k-widget k-treeview';
                if (element.is('ul')) {
                    wrapper = element.wrap('<div />').parent();
                    root = element;
                } else {
                    wrapper = element;
                    root = wrapper.children('ul').eq(0);
                }
                that.wrapper = wrapper.addClass(wrapperClasses);
                that.root = root;
            },
            _group: function (item) {
                var that = this, firstLevel = item.hasClass(KTREEVIEW), group = {
                        firstLevel: firstLevel,
                        expanded: firstLevel || that._expanded(item)
                    }, groupElement = item.children('ul');
                groupElement.addClass(that.templates.groupCssClass(group)).css('display', group.expanded ? '' : 'none');
                that._nodes(groupElement, group);
            },
            _nodes: function (groupElement, groupData) {
                var that = this, nodes = groupElement.children('li'), nodeData;
                groupData = extend({ length: nodes.length }, groupData);
                nodes.each(function (i, node) {
                    node = $(node);
                    nodeData = {
                        index: i,
                        expanded: that._expanded(node)
                    };
                    updateNodeHtml(node);
                    that._updateNodeClasses(node, groupData, nodeData);
                    that._group(node);
                });
            },
            _checkboxes: function () {
                var options = this.options;
                var checkboxes = options.checkboxes;
                var defaultTemplate;
                if (checkboxes) {
                    defaultTemplate = '<input aria-label=\'#=item.text#\' type=\'checkbox\' tabindex=\'-1\' #= (item.enabled === false) ? \'disabled\' : \'\' # #= item.checked ? \'checked\' : \'\' #';
                    if (checkboxes.name) {
                        defaultTemplate += ' name=\'' + checkboxes.name + '\'';
                    }
                    defaultTemplate += ' id=\'_#= item.uid #\' class=\'k-checkbox\' /><span class=\'k-checkbox-label\'></span>';
                    checkboxes = extend({ template: defaultTemplate }, options.checkboxes);
                    if (typeof checkboxes.template == STRING) {
                        checkboxes.template = template(checkboxes.template);
                    }
                    options.checkboxes = checkboxes;
                }
            },
            _updateNodeClasses: function (node, groupData, nodeData) {
                var wrapper = node.children('div'), group = node.children('ul'), templates = this.templates;
                if (node.hasClass('k-treeview')) {
                    return;
                }
                nodeData = nodeData || {};
                nodeData.expanded = typeof nodeData.expanded != UNDEFINED ? nodeData.expanded : this._expanded(node);
                nodeData.index = typeof nodeData.index != UNDEFINED ? nodeData.index : node.index();
                nodeData.enabled = typeof nodeData.enabled != UNDEFINED ? nodeData.enabled : !wrapper.children('.k-in').hasClass('k-state-disabled');
                groupData = groupData || {};
                groupData.firstLevel = typeof groupData.firstLevel != UNDEFINED ? groupData.firstLevel : node.parent().parent().hasClass(KTREEVIEW);
                groupData.length = typeof groupData.length != UNDEFINED ? groupData.length : node.parent().children().length;
                node.removeClass('k-first k-last').addClass(templates.wrapperCssClass(groupData, nodeData));
                wrapper.removeClass('k-top k-mid k-bot').addClass(templates.cssClass(groupData, nodeData));
                var textWrap = wrapper.children('.k-in');
                var isLink = textWrap[0] && textWrap[0].nodeName.toLowerCase() == 'a';
                textWrap.removeClass('k-in k-link k-state-default k-state-disabled').addClass(templates.textClass(nodeData, isLink));
                if (group.length || node.attr('data-hasChildren') == 'true') {
                    wrapper.children('.k-icon').removeClass('k-i-expand k-i-collapse').addClass(templates.toggleButtonClass(nodeData));
                    group.addClass('k-group');
                }
            },
            _processNodes: function (nodes, callback) {
                var that = this;
                that.element.find(nodes).each(function (index, item) {
                    callback.call(that, index, $(item).closest(NODE));
                });
            },
            dataItem: function (node) {
                var uid = $(node).closest(NODE).attr(kendo.attr('uid')), dataSource = this.dataSource;
                return dataSource && dataSource.getByUid(uid);
            },
            _insertNode: function (nodeData, index, parentNode, insertCallback, collapsed) {
                var that = this, group = subGroup(parentNode), updatedGroupLength = group.children().length + 1, childrenData, groupData = {
                        firstLevel: parentNode.hasClass(KTREEVIEW),
                        expanded: !collapsed,
                        length: updatedGroupLength
                    }, node, i, item, nodeHtml = '', append = function (item, group) {
                        item.appendTo(group);
                    };
                for (i = 0; i < nodeData.length; i++) {
                    item = nodeData[i];
                    item.index = index + i;
                    nodeHtml += that._renderItem({
                        group: groupData,
                        item: item
                    });
                }
                node = $(nodeHtml);
                if (!node.length) {
                    return;
                }
                that.angular('compile', function () {
                    return {
                        elements: node.get(),
                        data: nodeData.map(function (item) {
                            return { dataItem: item };
                        })
                    };
                });
                if (!group.length) {
                    group = $(that._renderGroup({ group: groupData })).appendTo(parentNode);
                }
                insertCallback(node, group);
                if (parentNode.hasClass('k-item')) {
                    updateNodeHtml(parentNode);
                    that._updateNodeClasses(parentNode);
                }
                that._updateNodeClasses(node.prev().first());
                that._updateNodeClasses(node.next().last());
                for (i = 0; i < nodeData.length; i++) {
                    item = nodeData[i];
                    if (item.hasChildren) {
                        childrenData = item.children.data();
                        if (childrenData.length) {
                            that._insertNode(childrenData, item.index, node.eq(i), append, !that._expanded(node.eq(i)));
                        }
                    }
                }
                return node;
            },
            _updateNodes: function (items, field) {
                var that = this;
                var i, node, nodeWrapper, item, isChecked, isCollapsed;
                var context = {
                    treeview: that.options,
                    item: item
                };
                var render = field != 'expanded' && field != 'checked';
                function setCheckedState(root, state) {
                    root.find('.k-checkbox-wrapper :checkbox').prop(CHECKED, state).data(INDETERMINATE, false).prop(INDETERMINATE, false);
                }
                if (field == 'selected') {
                    item = items[0];
                    node = that.findByUid(item.uid).find('.k-in:first').removeClass('k-state-hover').toggleClass('k-state-selected', item[field]).end();
                    if (item[field]) {
                        that.current(node);
                    }
                    node.attr(ARIASELECTED, !!item[field]);
                } else {
                    var elements = $.map(items, function (item) {
                        return that.findByUid(item.uid).children('div');
                    });
                    if (render) {
                        that.angular('cleanup', function () {
                            return { elements: elements };
                        });
                    }
                    for (i = 0; i < items.length; i++) {
                        context.item = item = items[i];
                        nodeWrapper = elements[i];
                        node = nodeWrapper.parent();
                        if (render) {
                            nodeWrapper.children('.k-in').html(that.templates.itemContent(context));
                        }
                        if (field == CHECKED) {
                            isChecked = item[field];
                            setCheckedState(nodeWrapper, isChecked);
                            if (that.options.checkboxes.checkChildren) {
                                setCheckedState(node.children('.k-group'), isChecked);
                                that._setChecked(item.children, isChecked);
                                that._bubbleIndeterminate(node);
                            }
                        } else if (field == 'expanded') {
                            that._toggle(node, item, item[field]);
                        } else if (field == 'enabled') {
                            node.find('.k-checkbox-wrapper :checkbox').prop('disabled', !item[field]);
                            isCollapsed = !nodeContents(node).is(VISIBLE);
                            node.removeAttr(ARIADISABLED);
                            if (!item[field]) {
                                if (item.selected) {
                                    item.set('selected', false);
                                }
                                if (item.expanded) {
                                    item.set('expanded', false);
                                }
                                isCollapsed = true;
                                node.attr(ARIASELECTED, false).attr(ARIADISABLED, true);
                            }
                            that._updateNodeClasses(node, {}, {
                                enabled: item[field],
                                expanded: !isCollapsed
                            });
                        }
                        if (nodeWrapper.length) {
                            this.trigger('itemChange', {
                                item: nodeWrapper,
                                data: item,
                                ns: ui
                            });
                        }
                    }
                    if (render) {
                        that.angular('compile', function () {
                            return {
                                elements: elements,
                                data: $.map(items, function (item) {
                                    return [{ dataItem: item }];
                                })
                            };
                        });
                    }
                }
            },
            _appendItems: function (index, items, parentNode) {
                var group = subGroup(parentNode);
                var children = group.children();
                var collapsed = !this._expanded(parentNode);
                if (typeof index == UNDEFINED) {
                    index = children.length;
                }
                this._insertNode(items, index, parentNode, function (item, group) {
                    if (index >= children.length) {
                        item.appendTo(group);
                    } else {
                        item.insertBefore(children.eq(index));
                    }
                }, collapsed);
                if (this._expanded(parentNode)) {
                    this._updateNodeClasses(parentNode);
                    subGroup(parentNode).css('display', 'block');
                }
            },
            _refreshChildren: function (parentNode, items, index) {
                var i, children, child;
                var options = this.options;
                var loadOnDemand = options.loadOnDemand;
                var checkChildren = options.checkboxes && options.checkboxes.checkChildren;
                subGroup(parentNode).empty();
                if (!items.length) {
                    updateNodeHtml(parentNode);
                } else {
                    this._appendItems(index, items, parentNode);
                    children = subGroup(parentNode).children();
                    if (loadOnDemand && checkChildren) {
                        this._bubbleIndeterminate(children.last());
                    }
                    for (i = 0; i < children.length; i++) {
                        child = children.eq(i);
                        this.trigger('itemChange', {
                            item: child.children('div'),
                            data: this.dataItem(child),
                            ns: ui
                        });
                    }
                }
            },
            _refreshRoot: function (items) {
                var groupHtml = this._renderGroup({
                    items: items,
                    group: {
                        firstLevel: true,
                        expanded: true
                    }
                });
                if (this.root.length) {
                    this._angularItems('cleanup');
                    var group = $(groupHtml);
                    this.root.attr('class', group.attr('class')).html(group.html());
                } else {
                    this.root = this.wrapper.html(groupHtml).children('ul');
                }
                this.root.attr('role', 'tree');
                var elements = this.root.children('.k-item');
                for (var i = 0; i < items.length; i++) {
                    this.trigger('itemChange', {
                        item: elements.eq(i),
                        data: items[i],
                        ns: ui
                    });
                }
                this._angularItems('compile');
            },
            refresh: function (e) {
                var node = e.node;
                var action = e.action;
                var items = e.items;
                var parentNode = this.wrapper;
                var options = this.options;
                var loadOnDemand = options.loadOnDemand;
                var checkChildren = options.checkboxes && options.checkboxes.checkChildren;
                var i;
                if (e.field) {
                    if (!items[0] || !items[0].level) {
                        return;
                    }
                    return this._updateNodes(items, e.field);
                }
                if (node) {
                    parentNode = this.findByUid(node.uid);
                    this._progress(parentNode, false);
                }
                if (checkChildren && action != 'remove') {
                    var bubble = false;
                    for (i = 0; i < items.length; i++) {
                        if ('checked' in items[i]) {
                            bubble = true;
                            break;
                        }
                    }
                    if (!bubble && node && node.checked) {
                        for (i = 0; i < items.length; i++) {
                            items[i].checked = true;
                        }
                    }
                }
                if (action == 'add') {
                    this._appendItems(e.index, items, parentNode);
                } else if (action == 'remove') {
                    this._remove(this.findByUid(items[0].uid), false);
                } else if (action == 'itemchange') {
                    this._updateNodes(items);
                } else if (action == 'itemloaded') {
                    this._refreshChildren(parentNode, items, e.index);
                } else {
                    this._refreshRoot(items);
                }
                if (action != 'remove') {
                    for (i = 0; i < items.length; i++) {
                        if (!loadOnDemand || items[i].expanded) {
                            items[i].load();
                        }
                    }
                }
                this.trigger(DATABOUND, { node: node ? parentNode : undefined });
            },
            _error: function (e) {
                var node = e.node && this.findByUid(e.node.uid);
                var retryHtml = this.templates.retry({ messages: this.options.messages });
                if (node) {
                    this._progress(node, false);
                    this._expanded(node, false);
                    nodeIcon(node).addClass('k-i-reload');
                    e.node.loaded(false);
                } else {
                    this._progress(false);
                    this.element.html(retryHtml);
                }
            },
            _retryRequest: function (e) {
                e.preventDefault();
                this.dataSource.fetch();
            },
            expand: function (nodes) {
                this._processNodes(nodes, function (index, item) {
                    this.toggle(item, true);
                });
            },
            collapse: function (nodes) {
                this._processNodes(nodes, function (index, item) {
                    this.toggle(item, false);
                });
            },
            enable: function (nodes, enable) {
                enable = arguments.length == 2 ? !!enable : true;
                this._processNodes(nodes, function (index, item) {
                    this.dataItem(item).set('enabled', enable);
                });
            },
            current: function (node) {
                var that = this, current = that._current, element = that.element, id = that._ariaId;
                if (arguments.length > 0 && node && node.length) {
                    if (current) {
                        if (current[0].id === id) {
                            current.removeAttr('id');
                        }
                        current.find('.k-in:first').removeClass('k-state-focused');
                    }
                    current = that._current = $(node, element).closest(NODE);
                    current.find('.k-in:first').addClass('k-state-focused');
                    id = current[0].id || id;
                    if (id) {
                        that.wrapper.removeAttr('aria-activedescendant');
                        current.attr('id', id);
                        that.wrapper.attr('aria-activedescendant', id);
                    }
                    return;
                }
                if (!current) {
                    current = that._nextVisible($());
                }
                return current;
            },
            select: function (node) {
                var that = this, element = that.element;
                if (!arguments.length) {
                    return element.find('.k-state-selected').closest(NODE);
                }
                node = $(node, element).closest(NODE);
                element.find('.k-state-selected').each(function () {
                    var dataItem = that.dataItem(this);
                    if (dataItem) {
                        dataItem.set('selected', false);
                        delete dataItem.selected;
                    } else {
                        $(this).removeClass('k-state-selected');
                    }
                });
                if (node.length) {
                    that.dataItem(node).set('selected', true);
                    that._clickTarget = node;
                }
                that.trigger(CHANGE);
            },
            _toggle: function (node, dataItem, expand) {
                var options = this.options;
                var contents = nodeContents(node);
                var direction = expand ? 'expand' : 'collapse';
                var loaded;
                if (contents.data('animating')) {
                    return;
                }
                if (!this._trigger(direction, node)) {
                    this._expanded(node, expand);
                    loaded = dataItem && dataItem.loaded();
                    if (expand && !loaded) {
                        if (options.loadOnDemand) {
                            this._progress(node, true);
                        }
                        contents.remove();
                        dataItem.load();
                    } else {
                        this._updateNodeClasses(node, {}, { expanded: expand });
                        if (!expand) {
                            contents.css('height', contents.height()).css('height');
                        }
                        contents.kendoStop(true, true).kendoAnimate(extend({ reset: true }, options.animation[direction], {
                            complete: function () {
                                if (expand) {
                                    contents.css('height', '');
                                }
                            }
                        }));
                    }
                }
            },
            toggle: function (node, expand) {
                node = $(node);
                if (!nodeIcon(node).is('.k-i-expand, .k-i-collapse')) {
                    return;
                }
                if (arguments.length == 1) {
                    expand = !this._expanded(node);
                }
                this._expanded(node, expand);
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.wrapper.off(NS);
                that._unbindDataSource();
                if (that.dragging) {
                    that.dragging.destroy();
                }
                kendo.destroy(that.element);
                that.root = that.wrapper = that.element = null;
            },
            _expanded: function (node, value) {
                var expandedAttr = kendo.attr('expanded');
                var dataItem = this.dataItem(node);
                var expanded = value;
                if (arguments.length == 1) {
                    return node.attr(expandedAttr) === 'true' || dataItem && dataItem.expanded;
                }
                if (nodeContents(node).data('animating')) {
                    return;
                }
                if (dataItem) {
                    dataItem.set('expanded', expanded);
                    expanded = dataItem.expanded;
                }
                if (expanded) {
                    node.attr(expandedAttr, 'true');
                    node.attr('aria-expanded', 'true');
                } else {
                    node.removeAttr(expandedAttr);
                    node.attr('aria-expanded', 'false');
                }
            },
            _progress: function (node, showProgress) {
                var element = this.element;
                var loadingText = this.templates.loading({ messages: this.options.messages });
                if (arguments.length == 1) {
                    showProgress = node;
                    if (showProgress) {
                        element.html(loadingText);
                    } else {
                        element.empty();
                    }
                } else {
                    nodeIcon(node).toggleClass('k-i-loading', showProgress).removeClass('k-i-reload');
                }
            },
            text: function (node, text) {
                var dataItem = this.dataItem(node), fieldBindings = this.options[bindings.text], level = dataItem.level(), length = fieldBindings.length, field = fieldBindings[Math.min(level, length - 1)];
                if (text) {
                    dataItem.set(field, text);
                } else {
                    return dataItem[field];
                }
            },
            _objectOrSelf: function (node) {
                return $(node).closest('[data-role=treeview]').data('kendoTreeView') || this;
            },
            _dataSourceMove: function (nodeData, group, parentNode, callback) {
                var referenceDataItem, destTreeview = this._objectOrSelf(parentNode || group), destDataSource = destTreeview.dataSource;
                var loadPromise = $.Deferred().resolve().promise();
                if (parentNode && parentNode[0] != destTreeview.element[0]) {
                    referenceDataItem = destTreeview.dataItem(parentNode);
                    if (!referenceDataItem.loaded()) {
                        destTreeview._progress(parentNode, true);
                        loadPromise = referenceDataItem.load();
                    }
                    if (parentNode != this.root) {
                        destDataSource = referenceDataItem.children;
                        if (!destDataSource || !(destDataSource instanceof HierarchicalDataSource)) {
                            referenceDataItem._initChildren();
                            referenceDataItem.loaded(true);
                            destDataSource = referenceDataItem.children;
                        }
                    }
                }
                nodeData = this._toObservableData(nodeData);
                return callback.call(destTreeview, destDataSource, nodeData, loadPromise);
            },
            _toObservableData: function (node) {
                var dataItem = node, dataSource, uid;
                if (node instanceof window.jQuery || isDomElement(node)) {
                    dataSource = this._objectOrSelf(node).dataSource;
                    uid = $(node).attr(kendo.attr('uid'));
                    dataItem = dataSource.getByUid(uid);
                    if (dataItem) {
                        dataItem = dataSource.remove(dataItem);
                    }
                }
                return dataItem;
            },
            _insert: function (data, model, index) {
                if (!(model instanceof kendo.data.ObservableArray)) {
                    if (!isArray(model)) {
                        model = [model];
                    }
                } else {
                    model = model.toJSON();
                }
                var parentNode = data.parent();
                if (parentNode && parentNode._initChildren) {
                    parentNode.hasChildren = true;
                    parentNode._initChildren();
                }
                data.splice.apply(data, [
                    index,
                    0
                ].concat(model));
                return this.findByUid(data[index].uid);
            },
            insertAfter: insertAction(1),
            insertBefore: insertAction(0),
            append: function (nodeData, parentNode, success) {
                var group = this.root;
                if (parentNode) {
                    group = subGroup(parentNode);
                }
                return this._dataSourceMove(nodeData, group, parentNode, function (dataSource, model, loadModel) {
                    var inserted;
                    var that = this;
                    function add() {
                        if (parentNode) {
                            that._expanded(parentNode, true);
                        }
                        var data = dataSource.data(), index = Math.max(data.length, 0);
                        return that._insert(data, model, index);
                    }
                    loadModel.done(function () {
                        inserted = add();
                        success = success || $.noop;
                        success(inserted);
                    });
                    return inserted || null;
                });
            },
            _remove: function (node, keepData) {
                var that = this, parentNode, prevSibling, nextSibling;
                node = $(node, that.element);
                this.angular('cleanup', function () {
                    return { elements: node.get() };
                });
                parentNode = node.parent().parent();
                prevSibling = node.prev();
                nextSibling = node.next();
                node[keepData ? 'detach' : 'remove']();
                if (parentNode.hasClass('k-item')) {
                    updateNodeHtml(parentNode);
                    that._updateNodeClasses(parentNode);
                }
                that._updateNodeClasses(prevSibling);
                that._updateNodeClasses(nextSibling);
                return node;
            },
            remove: function (node) {
                var dataItem = this.dataItem(node);
                if (dataItem) {
                    this.dataSource.remove(dataItem);
                }
            },
            detach: function (node) {
                return this._remove(node, true);
            },
            findByText: function (text) {
                return $(this.element).find('.k-in').filter(function (i, element) {
                    return $(element).text() == text;
                }).closest(NODE);
            },
            findByUid: function (uid) {
                var items = this.element.find('.k-item');
                var uidAttr = kendo.attr('uid');
                var result;
                for (var i = 0; i < items.length; i++) {
                    if (items[i].getAttribute(uidAttr) == uid) {
                        result = items[i];
                        break;
                    }
                }
                return $(result);
            },
            expandPath: function (path, complete) {
                var treeview = this;
                var nodeIds = path.slice(0);
                var callback = complete || $.noop;
                function proceed() {
                    nodeIds.shift();
                    if (nodeIds.length) {
                        expand(nodeIds[0]).then(proceed);
                    } else {
                        callback.call(treeview);
                    }
                }
                function expand(id) {
                    var result = $.Deferred();
                    var node = treeview.dataSource.get(id);
                    if (node) {
                        if (node.loaded()) {
                            node.set('expanded', true);
                            result.resolve();
                        } else {
                            treeview._progress(treeview.findByUid(node.uid), true);
                            node.load().then(function () {
                                node.set('expanded', true);
                                result.resolve();
                            });
                        }
                    } else {
                        result.resolve();
                    }
                    return result.promise();
                }
                expand(nodeIds[0]).then(proceed);
            },
            _parentIds: function (node) {
                var parent = node && node.parentNode();
                var parents = [];
                while (parent && parent.parentNode) {
                    parents.unshift(parent.id);
                    parent = parent.parentNode();
                }
                return parents;
            },
            expandTo: function (node) {
                if (!(node instanceof kendo.data.Node)) {
                    node = this.dataSource.get(node);
                }
                var parents = this._parentIds(node);
                this.expandPath(parents);
            },
            _renderItem: function (options) {
                if (!options.group) {
                    options.group = {};
                }
                options.treeview = this.options;
                options.r = this.templates;
                return this.templates.item(options);
            },
            _renderGroup: function (options) {
                var that = this;
                options.renderItems = function (options) {
                    var html = '', i = 0, items = options.items, len = items ? items.length : 0, group = options.group;
                    group.length = len;
                    for (; i < len; i++) {
                        options.group = group;
                        options.item = items[i];
                        options.item.index = i;
                        html += that._renderItem(options);
                    }
                    return html;
                };
                options.r = that.templates;
                return that.templates.group(options);
            }
        });
        ui.plugin(TreeView);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pivot.fieldmenu', [
        'kendo.pivotgrid',
        'kendo.menu',
        'kendo.window',
        'kendo.treeview',
        'kendo.dropdownlist'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pivot.fieldmenu',
        name: 'PivotFieldMenu',
        category: 'web',
        description: 'The PivotFieldMenu widget allows the user to filter on fields displayed in PivotGrid',
        depends: [
            'menu',
            'window',
            'treeview',
            'dropdownlist'
        ],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var ui = kendo.ui;
        var MENU = 'kendoContextMenu';
        var proxy = $.proxy;
        var NS = '.kendoPivotFieldMenu';
        var Widget = ui.Widget;
        var FILTER_ITEM = 'k-filter-item';
        var ARIA_LABEL = 'aria-label';
        var PivotFieldMenu = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._dataSource();
                this._layout();
                kendo.notify(this);
            },
            events: [],
            options: {
                name: 'PivotFieldMenu',
                filter: null,
                filterable: true,
                sortable: true,
                messages: {
                    info: 'Show items with value that:',
                    sortAscending: 'Sort Ascending',
                    sortDescending: 'Sort Descending',
                    filterFields: 'Fields Filter',
                    filter: 'Filter',
                    include: 'Include Fields...',
                    title: 'Fields to include',
                    clear: 'Clear',
                    ok: 'OK',
                    cancel: 'Cancel',
                    operators: {
                        contains: 'Contains',
                        doesnotcontain: 'Does not contain',
                        startswith: 'Starts with',
                        endswith: 'Ends with',
                        eq: 'Is equal to',
                        neq: 'Is not equal to'
                    }
                }
            },
            _layout: function () {
                var options = this.options;
                this.wrapper = $(kendo.template(MENUTEMPLATE)({
                    ns: kendo.ns,
                    filterable: options.filterable,
                    sortable: options.sortable,
                    messages: options.messages
                }));
                this.menu = this.wrapper[MENU]({
                    filter: options.filter,
                    target: this.element,
                    orientation: 'vertical',
                    showOn: 'click',
                    closeOnClick: false,
                    open: proxy(this._menuOpen, this),
                    select: proxy(this._select, this),
                    copyAnchorStyles: false
                }).data(MENU);
                this._createWindow();
                if (options.filterable) {
                    this._initFilterForm();
                }
            },
            _initFilterForm: function () {
                var filterForm = this.menu.element.find('.' + FILTER_ITEM);
                var filterProxy = proxy(this._filter, this);
                this._filterOperator = new kendo.ui.DropDownList(filterForm.find('select'));
                this._filterValue = filterForm.find('.k-textbox');
                this._updateFilterAriaLabel();
                filterForm.on('submit' + NS, filterProxy).on('click' + NS, '.k-button-filter', filterProxy).on('click' + NS, '.k-button-clear', proxy(this._reset, this));
            },
            _setFilterForm: function (expression) {
                var filterOperator = this._filterOperator;
                var operator = '';
                var value = '';
                if (expression) {
                    operator = expression.operator;
                    value = expression.value;
                }
                filterOperator.value(operator);
                if (!filterOperator.value()) {
                    filterOperator.select(0);
                }
                this._filterValue.val(value);
            },
            _clearFilters: function (member) {
                var filter = this.dataSource.filter() || {};
                var expressions;
                var idx = 0;
                var length;
                filter.filters = filter.filters || [];
                expressions = findFilters(filter, member);
                for (length = expressions.length; idx < length; idx++) {
                    filter.filters.splice(filter.filters.indexOf(expressions[idx]), 1);
                }
                return filter;
            },
            _convert: function (value) {
                var schema = this.dataSource.options.schema;
                var field = ((schema.model || {}).fields || {})[this.currentMember];
                if (field) {
                    if (field.type === 'number') {
                        value = parseFloat(value);
                    } else if (field.type === 'boolean') {
                        value = Boolean($.parseJSON(value));
                    }
                }
                return value;
            },
            _filter: function (e) {
                var that = this;
                var value = that._convert(that._filterValue.val());
                e.preventDefault();
                if (value === '') {
                    that.menu.close();
                    return;
                }
                var expression = {
                    field: that.currentMember,
                    operator: that._filterOperator.value(),
                    value: value
                };
                var filter = that._clearFilters(that.currentMember);
                filter.filters.push(expression);
                that.dataSource.filter(filter);
                that.menu.close();
            },
            _updateFilterAriaLabel: function () {
                var filterForm = this.menu.element.find('.' + FILTER_ITEM);
                var selectedOperator = this._filterOperator.value();
                var selectedOperatorName = this.options.messages.operators[selectedOperator];
                filterForm.find('select').attr(ARIA_LABEL, selectedOperatorName);
            },
            _reset: function (e) {
                var that = this;
                var filter = that._clearFilters(that.currentMember);
                e.preventDefault();
                if (!filter.filters[0]) {
                    filter = {};
                }
                that.dataSource.filter(filter);
                that._setFilterForm(null);
                that.menu.close();
            },
            _sort: function (dir) {
                var field = this.currentMember;
                var expressions = this.dataSource.sort() || [];
                expressions = removeExpr(expressions, field);
                expressions.push({
                    field: field,
                    dir: dir
                });
                this.dataSource.sort(expressions);
                this.menu.close();
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
            },
            _dataSource: function () {
                this.dataSource = kendo.data.PivotDataSource.create(this.options.dataSource);
            },
            _createWindow: function () {
                var messages = this.options.messages;
                this.includeWindow = $(kendo.template(WINDOWTEMPLATE)({ messages: messages })).on('click' + NS, '.k-button-ok', proxy(this._applyIncludes, this)).on('click' + NS, '.k-button-cancel', proxy(this._closeWindow, this));
                this.includeWindow = new ui.Window(this.includeWindow, {
                    title: messages.title,
                    visible: false,
                    resizable: false,
                    open: proxy(this._windowOpen, this)
                });
            },
            _applyIncludes: function (e) {
                var checkedNodes = [];
                var resultExpression;
                var view = this.treeView.dataSource.view();
                var rootChecked = view[0].checked;
                var filter = this.dataSource.filter();
                var existingExpression = findFilters(filter, this.currentMember, 'in')[0];
                checkedNodeIds(view, checkedNodes);
                if (existingExpression) {
                    if (rootChecked) {
                        filter.filters.splice(filter.filters.indexOf(existingExpression), 1);
                        if (!filter.filters.length) {
                            filter = {};
                        }
                    } else {
                        existingExpression.value = checkedNodes.join(',');
                    }
                    resultExpression = filter;
                }
                if (checkedNodes.length) {
                    if (!resultExpression && !rootChecked) {
                        resultExpression = {
                            field: this.currentMember,
                            operator: 'in',
                            value: checkedNodes.join(',')
                        };
                        if (filter) {
                            filter.filters.push(resultExpression);
                            resultExpression = filter;
                        }
                    }
                }
                if (resultExpression) {
                    this.dataSource.filter(resultExpression);
                }
                this._closeWindow(e);
            },
            _closeWindow: function (e) {
                e.preventDefault();
                this.includeWindow.close();
            },
            _treeViewDataSource: function () {
                var that = this;
                return kendo.data.HierarchicalDataSource.create({
                    schema: {
                        model: {
                            id: 'uniqueName',
                            hasChildren: function (item) {
                                return parseInt(item.childrenCardinality, 10) > 0;
                            }
                        }
                    },
                    transport: {
                        read: function (options) {
                            var restrictions = {};
                            var node = that.treeView.dataSource.get(options.data.uniqueName);
                            var name = options.data.uniqueName;
                            if (!name) {
                                restrictions.levelUniqueName = that.currentMember + '.[(ALL)]';
                            } else {
                                restrictions.memberUniqueName = node.uniqueName.replace(/\&/g, '&amp;');
                                restrictions.treeOp = 1;
                            }
                            that.dataSource.schemaMembers(restrictions).done(function (data) {
                                checkNodes(that.dataSource.filter(), that.currentMember, data);
                                options.success(data);
                            }).fail(options.error);
                        }
                    }
                });
            },
            _createTreeView: function (element) {
                var that = this;
                that.treeView = new ui.TreeView(element, {
                    autoBind: false,
                    dataSource: that._treeViewDataSource(),
                    dataTextField: 'caption',
                    template: '#: data.item.caption || data.item.name #',
                    checkboxes: { checkChildren: true },
                    dataBound: function () {
                        ui.progress(that.includeWindow.element, false);
                    }
                });
            },
            _menuOpen: function (e) {
                if (!e.event) {
                    return;
                }
                var attr = kendo.attr('name');
                this.currentMember = $(e.event.target).closest('[' + attr + ']').attr(attr);
                if (this.options.filterable) {
                    this._setFilterForm(findFilters(this.dataSource.filter(), this.currentMember)[0]);
                }
            },
            _select: function (e) {
                var item = $(e.item);
                $('.k-pivot-filter-window').not(this.includeWindow.element).kendoWindow('close');
                if (item.hasClass('k-include-item')) {
                    this.includeWindow.center().open();
                } else if (item.hasClass('k-sort-asc')) {
                    this._sort('asc');
                } else if (item.hasClass('k-sort-desc')) {
                    this._sort('desc');
                } else if (item.hasClass(FILTER_ITEM)) {
                    this._updateFilterAriaLabel();
                }
            },
            _windowOpen: function () {
                if (!this.treeView) {
                    this._createTreeView(this.includeWindow.element.find('.k-treeview'));
                }
                ui.progress(this.includeWindow.element, true);
                this.treeView.dataSource.read();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this.menu) {
                    this.menu.destroy();
                    this.menu = null;
                }
                if (this.treeView) {
                    this.treeView.destroy();
                    this.treeView = null;
                }
                if (this.includeWindow) {
                    this.includeWindow.destroy();
                    this.includeWindow = null;
                }
                this.wrapper = null;
                this.element = null;
            }
        });
        function removeExpr(expressions, name) {
            var result = [];
            for (var idx = 0, length = expressions.length; idx < length; idx++) {
                if (expressions[idx].field !== name) {
                    result.push(expressions[idx]);
                }
            }
            return result;
        }
        function findFilters(filter, member, operator) {
            if (!filter) {
                return [];
            }
            filter = filter.filters;
            var idx = 0;
            var result = [];
            var length = filter.length;
            var filterOperator;
            for (; idx < length; idx++) {
                filterOperator = filter[idx].operator;
                if ((!operator && filterOperator !== 'in' || filterOperator === operator) && filter[idx].field === member) {
                    result.push(filter[idx]);
                }
            }
            return result;
        }
        function checkNodes(filter, member, nodes) {
            var values, idx = 0, length = nodes.length;
            filter = findFilters(filter, member, 'in')[0];
            if (!filter) {
                for (; idx < length; idx++) {
                    nodes[idx].checked = true;
                }
            } else {
                values = filter.value.split(',');
                for (; idx < length; idx++) {
                    nodes[idx].checked = $.inArray(nodes[idx].uniqueName, values) >= 0;
                }
            }
        }
        function checkedNodeIds(nodes, checkedNodes) {
            var idx, length = nodes.length;
            for (idx = 0; idx < length; idx++) {
                if (nodes[idx].checked && nodes[idx].level() !== 0) {
                    checkedNodes.push(nodes[idx].uniqueName);
                }
                if (nodes[idx].hasChildren) {
                    checkedNodeIds(nodes[idx].children.view(), checkedNodes);
                }
            }
        }
        var LABELMENUTEMPLATE = '<div class="k-filterable k-content" tabindex="-1" data-role="fieldmenu">' + '<form class="k-filter-menu">' + '<div>' + '<div class="k-filter-help-text">#=messages.info#</div>' + '<select>' + '#for(var op in messages.operators){#' + '<option value="#=op#">#=messages.operators[op]#</option>' + '#}#' + '</select>' + '<input class="k-textbox" type="text" ' + ARIA_LABEL + '="#=messages.filter#" />' + '<div>' + '<a class="k-button k-primary k-button-filter" href="\\#">#=messages.filter#</a>' + '<a class="k-button k-button-clear" href="\\#">#=messages.clear#</a>' + '</div>' + '</div>' + '</form>' + '</div>';
        var MENUTEMPLATE = '<ul class="k-pivot-fieldmenu">' + '# if (sortable) {#' + '<li class="k-item k-sort-asc">' + '<span class="k-link">' + '<span class="k-icon k-i-sort-asc-sm"></span>' + '${messages.sortAscending}' + '</span>' + '</li>' + '<li class="k-item k-sort-desc">' + '<span class="k-link">' + '<span class="k-icon k-i-sort-desc-sm"></span>' + '${messages.sortDescending}' + '</span>' + '</li>' + '# if (filterable) {#' + '<li class="k-separator"></li>' + '# } #' + '# } #' + '# if (filterable) {#' + '<li class="k-item k-include-item">' + '<span class="k-link">' + '<span class="k-icon k-i-filter"></span>' + '${messages.include}' + '</span>' + '</li>' + '<li class="k-separator"></li>' + '<li class="k-item ' + FILTER_ITEM + '">' + '<span class="k-link">' + '<span class="k-icon k-i-filter"></span>' + '${messages.filterFields}' + '</span>' + '<ul>' + '<li>' + LABELMENUTEMPLATE + '</li>' + '</ul>' + '</li>' + '# } #' + '</ul>';
        var WINDOWTEMPLATE = '<div class="k-popup-edit-form k-pivot-filter-window"><div class="k-edit-form-container">' + '<div class="k-treeview"></div>' + '<div class="k-edit-buttons k-state-default">' + '<a class="k-button k-primary k-button-ok" href="\\#">' + '${messages.ok}' + '</a>' + '<a class="k-button k-button-cancel" href="\\#">' + '${messages.cancel}' + '</a>' + '</div></div>';
        ui.plugin(PivotFieldMenu);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.filtercell', [
        'kendo.autocomplete',
        'kendo.datepicker',
        'kendo.numerictextbox',
        'kendo.combobox',
        'kendo.dropdownlist'
    ], f);
}(function () {
    var __meta__ = {
        id: 'filtercell',
        name: 'Row filter',
        category: 'framework',
        depends: ['autocomplete'],
        advanced: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, DataSource = kendo.data.DataSource, Widget = ui.Widget, CHANGE = 'change', BOOL = 'boolean', ENUM = 'enums', STRING = 'string', EQ = 'Is equal to', NEQ = 'Is not equal to', proxy = $.proxy, nonValueOperators = [
                'isnull',
                'isnotnull',
                'isempty',
                'isnotempty'
            ];
        function isNonValueFilter(filter) {
            var operator = typeof filter === 'string' ? filter : filter.operator;
            return $.inArray(operator, nonValueOperators) > -1;
        }
        function findFilterForField(filter, field) {
            var filters = [];
            if ($.isPlainObject(filter)) {
                if (filter.hasOwnProperty('filters')) {
                    filters = filter.filters;
                } else if (filter.field == field) {
                    return filter;
                }
            }
            if ($.isArray(filter)) {
                filters = filter;
            }
            for (var i = 0; i < filters.length; i++) {
                var result = findFilterForField(filters[i], field);
                if (result) {
                    return result;
                }
            }
        }
        function removeFiltersForField(expression, field) {
            if (expression.filters) {
                expression.filters = $.grep(expression.filters, function (filter) {
                    removeFiltersForField(filter, field);
                    if (filter.filters) {
                        return filter.filters.length;
                    } else {
                        return filter.field != field;
                    }
                });
            }
        }
        function removeDuplicates(dataSelector, dataTextField) {
            var getter = kendo.getter(dataTextField, true);
            return function (e) {
                var items = dataSelector(e), result = [], index = 0, seen = {};
                while (index < items.length) {
                    var item = items[index++], text = getter(item);
                    if (!seen.hasOwnProperty(text)) {
                        result.push(item);
                        seen[text] = true;
                    }
                }
                return result;
            };
        }
        var FilterCell = Widget.extend({
            init: function (element, options) {
                element = $(element).addClass('k-filtercell');
                var wrapper = this.wrapper = $('<span/>').appendTo(element);
                var that = this, dataSource, viewModel, passedOptions = options, first, type, operators = that.operators = options.operators || {}, input = that.input = $('<input/>').attr(kendo.attr('bind'), 'value: value').appendTo(wrapper);
                var suggestDataSource = options ? options.suggestDataSource : null;
                if (suggestDataSource) {
                    options = $.extend({}, options, { suggestDataSource: {} });
                }
                Widget.fn.init.call(that, element[0], options);
                if (suggestDataSource) {
                    that.options.suggestDataSource = suggestDataSource;
                }
                options = that.options;
                dataSource = that.dataSource = options.dataSource;
                that.model = dataSource.reader.model;
                type = options.type = STRING;
                var fields = kendo.getter('reader.model.fields', true)(dataSource) || {};
                var target = fields[options.field];
                if (target && target.type) {
                    type = options.type = target.type;
                }
                if (options.values) {
                    options.type = type = ENUM;
                }
                operators = operators[type] || options.operators[type];
                if (!passedOptions.operator) {
                    for (first in operators) {
                        options.operator = first;
                        break;
                    }
                }
                that._parse = function (value) {
                    return value != null ? value + '' : value;
                };
                if (that.model && that.model.fields) {
                    var field = that.model.fields[options.field];
                    if (field) {
                        if (field.parse) {
                            that._parse = proxy(field.parse, field);
                        }
                    }
                }
                that.defaultOperator = options.operator;
                that.viewModel = viewModel = kendo.observable({
                    operator: options.operator,
                    value: null,
                    operatorVisible: function () {
                        var val = this.get('value');
                        return val !== null && val !== undefined && val != 'undefined' || isNonValueFilter(this.get('operator')) && !that._clearInProgress;
                    }
                });
                viewModel.bind(CHANGE, proxy(that.updateDsFilter, that));
                if (type == STRING) {
                    that.initSuggestDataSource(options);
                }
                if (options.inputWidth !== null) {
                    input.width(options.inputWidth);
                }
                input.attr('aria-label', that._getColumnTitle());
                that._setInputType(options, type);
                if (type != BOOL && options.showOperators !== false) {
                    that._createOperatorDropDown(operators);
                } else {
                    $('<div unselectable="on" />').css('display', 'none').text('eq').appendTo(wrapper);
                    wrapper.addClass('k-operator-hidden');
                }
                that._createClearIcon();
                kendo.bind(this.wrapper, viewModel);
                if (type == STRING) {
                    if (!options.template) {
                        that.setAutoCompleteSource();
                    }
                }
                if (type == ENUM) {
                    that.setComboBoxSource(that.options.values);
                }
                that._refreshUI();
                that._refreshHandler = proxy(that._refreshUI, that);
                that.dataSource.bind(CHANGE, that._refreshHandler);
            },
            _setInputType: function (options, type) {
                var that = this, input = that.input;
                if (typeof options.template == 'function') {
                    options.template.call(that.viewModel, {
                        element: that.input,
                        dataSource: that.suggestDataSource
                    });
                    that._angularItems('compile');
                } else if (type == STRING) {
                    input.attr(kendo.attr('role'), 'autocomplete').attr(kendo.attr('text-field'), options.dataTextField || options.field).attr(kendo.attr('filter'), options.suggestionOperator).attr(kendo.attr('delay'), options.delay).attr(kendo.attr('min-length'), options.minLength).attr(kendo.attr('value-primitive'), true);
                } else if (type == 'date') {
                    input.attr(kendo.attr('role'), 'datepicker');
                } else if (type == BOOL) {
                    input.remove();
                    var radioInput = $('<input type=\'radio\'/>');
                    var wrapper = that.wrapper;
                    var inputName = kendo.guid();
                    var labelTrue = $('<label/>').text(options.messages.isTrue).append(radioInput);
                    radioInput.attr(kendo.attr('bind'), 'checked:value').attr('name', inputName).val('true');
                    var labelFalse = labelTrue.clone().text(options.messages.isFalse);
                    radioInput.clone().val('false').appendTo(labelFalse);
                    wrapper.append([
                        labelTrue,
                        labelFalse
                    ]);
                } else if (type == 'number') {
                    input.attr(kendo.attr('role'), 'numerictextbox').attr('title', that._getColumnTitle());
                } else if (type == ENUM) {
                    input.attr(kendo.attr('role'), 'combobox').attr(kendo.attr('text-field'), 'text').attr(kendo.attr('suggest'), true).attr(kendo.attr('filter'), 'contains').attr(kendo.attr('value-field'), 'value').attr(kendo.attr('value-primitive'), true);
                }
            },
            _getColumnTitle: function () {
                var column = this.options.column;
                return column ? column.title || column.field : '';
            },
            _createOperatorDropDown: function (operators) {
                var items = [], viewModel = this.viewModel;
                for (var prop in operators) {
                    items.push({
                        text: operators[prop],
                        value: prop
                    });
                }
                var dropdown = $('<input class="k-dropdown-operator" ' + kendo.attr('bind') + '="value: operator"/>').appendTo(this.wrapper);
                this.operatorDropDown = dropdown.kendoDropDownList({
                    dataSource: items,
                    dataTextField: 'text',
                    dataValueField: 'value',
                    open: function () {
                        this.popup.element.width(150);
                    },
                    valuePrimitive: true
                }).data('kendoDropDownList');
                viewModel.bind('change', function () {
                    var ariaLabel = operators[viewModel.operator];
                    dropdown.attr('aria-label', ariaLabel);
                });
                this.operatorDropDown.wrapper.find('.k-i-arrow-60-down').removeClass('k-i-arrow-60-down').addClass('k-i-filter');
            },
            initSuggestDataSource: function (options) {
                var suggestDataSource = options.suggestDataSource;
                if (!(suggestDataSource instanceof DataSource)) {
                    if (!options.customDataSource && suggestDataSource) {
                        suggestDataSource.group = undefined;
                    }
                    suggestDataSource = this.suggestDataSource = DataSource.create(suggestDataSource);
                }
                if (!options.customDataSource) {
                    suggestDataSource._pageSize = undefined;
                    suggestDataSource.reader.data = removeDuplicates(suggestDataSource.reader.data, this.options.field);
                }
                this.suggestDataSource = suggestDataSource;
            },
            setAutoCompleteSource: function () {
                var autoComplete = this.input.data('kendoAutoComplete');
                if (autoComplete) {
                    autoComplete.setDataSource(this.suggestDataSource);
                }
            },
            setComboBoxSource: function (values) {
                var dataSource = DataSource.create({ data: values });
                var comboBox = this.input.data('kendoComboBox');
                if (comboBox) {
                    comboBox.setDataSource(dataSource);
                }
            },
            _refreshUI: function () {
                var that = this, filter = findFilterForField(that.dataSource.filter(), this.options.field) || {}, viewModel = that.viewModel;
                that.manuallyUpdatingVM = true;
                filter = $.extend(true, {}, filter);
                if (that.options.type == BOOL) {
                    if (viewModel.value !== filter.value) {
                        that.wrapper.find(':radio').prop('checked', false);
                    }
                }
                if (filter.operator) {
                    viewModel.set('operator', filter.operator);
                }
                viewModel.set('value', filter.value);
                that.manuallyUpdatingVM = false;
            },
            updateDsFilter: function (e) {
                var that = this, model = that.viewModel;
                if (that.manuallyUpdatingVM || e.field == 'operator' && model.value === undefined && !isNonValueFilter(model)) {
                    return;
                }
                var currentFilter = $.extend({}, that.viewModel.toJSON(), { field: that.options.field });
                var expression = {
                    logic: 'and',
                    filters: []
                };
                var prevented = false;
                if (currentFilter.value !== undefined && currentFilter.value !== null || isNonValueFilter(currentFilter) && !this._clearInProgress) {
                    expression.filters.push(currentFilter);
                    prevented = that.trigger(CHANGE, {
                        filter: expression,
                        field: that.options.field
                    });
                }
                if (that._clearInProgress || currentFilter.value === null) {
                    prevented = that.trigger(CHANGE, {
                        filter: null,
                        field: that.options.field
                    });
                }
                if (prevented) {
                    return;
                }
                var mergeResult = that._merge(expression);
                if (mergeResult.filters.length) {
                    that.dataSource.filter(mergeResult);
                } else {
                    that.dataSource.filter({});
                }
            },
            _merge: function (expression) {
                var that = this, logic = expression.logic || 'and', filters = expression.filters, filter, result = that.dataSource.filter() || {
                        filters: [],
                        logic: 'and'
                    }, idx, length;
                removeFiltersForField(result, that.options.field);
                for (idx = 0, length = filters.length; idx < length; idx++) {
                    filter = filters[idx];
                    filter.value = that._parse(filter.value);
                }
                filters = $.grep(filters, function (filter) {
                    return filter.value !== '' && filter.value !== null || isNonValueFilter(filter);
                });
                if (filters.length) {
                    if (result.filters.length) {
                        expression.filters = filters;
                        if (result.logic !== 'and') {
                            result.filters = [{
                                    logic: result.logic,
                                    filters: result.filters
                                }];
                            result.logic = 'and';
                        }
                        if (filters.length > 1) {
                            result.filters.push(expression);
                        } else {
                            result.filters.push(filters[0]);
                        }
                    } else {
                        result.filters = filters;
                        result.logic = logic;
                    }
                }
                return result;
            },
            _createClearIcon: function () {
                var that = this;
                $('<button type=\'button\' class=\'k-button k-button-icon\' title = ' + that.options.messages.clear + '/>').attr('aria-label', that.options.messages.clear).attr(kendo.attr('bind'), 'visible:operatorVisible').html('<span class=\'k-icon k-i-close\'/>').click(proxy(that.clearFilter, that)).appendTo(that.wrapper);
            },
            clearFilter: function () {
                this._clearInProgress = true;
                if (isNonValueFilter(this.viewModel.operator)) {
                    this.viewModel.set('operator', this.defaultOperator);
                }
                this.viewModel.set('value', null);
                this._clearInProgress = false;
            },
            _angularItems: function (action) {
                var elements = this.wrapper.closest('th').get();
                var column = this.options.column;
                this.angular(action, function () {
                    return {
                        elements: elements,
                        data: [{ column: column }]
                    };
                });
            },
            destroy: function () {
                var that = this;
                that.filterModel = null;
                that.operatorDropDown = null;
                that._angularItems('cleanup');
                if (that._refreshHandler) {
                    that.dataSource.bind(CHANGE, that._refreshHandler);
                    that._refreshHandler = null;
                }
                kendo.unbind(that.element);
                Widget.fn.destroy.call(that);
                kendo.destroy(that.element);
            },
            events: [CHANGE],
            options: {
                name: 'FilterCell',
                delay: 200,
                minLength: 1,
                inputWidth: null,
                values: undefined,
                customDataSource: false,
                field: '',
                dataTextField: '',
                type: 'string',
                suggestDataSource: null,
                suggestionOperator: 'startswith',
                operator: 'eq',
                showOperators: true,
                template: null,
                messages: {
                    isTrue: 'is true',
                    isFalse: 'is false',
                    filter: 'Filter',
                    clear: 'Clear',
                    operator: 'Operator'
                },
                operators: {
                    string: {
                        eq: EQ,
                        neq: NEQ,
                        startswith: 'Starts with',
                        contains: 'Contains',
                        doesnotcontain: 'Does not contain',
                        endswith: 'Ends with',
                        isnull: 'Is null',
                        isnotnull: 'Is not null',
                        isempty: 'Is empty',
                        isnotempty: 'Is not empty'
                    },
                    number: {
                        eq: EQ,
                        neq: NEQ,
                        gte: 'Is greater than or equal to',
                        gt: 'Is greater than',
                        lte: 'Is less than or equal to',
                        lt: 'Is less than',
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    },
                    date: {
                        eq: EQ,
                        neq: NEQ,
                        gte: 'Is after or equal to',
                        gt: 'Is after',
                        lte: 'Is before or equal to',
                        lt: 'Is before',
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    },
                    enums: {
                        eq: EQ,
                        neq: NEQ,
                        isnull: 'Is null',
                        isnotnull: 'Is not null'
                    }
                }
            }
        });
        ui.plugin(FilterCell);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.panelbar', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'panelbar',
        name: 'PanelBar',
        category: 'web',
        description: 'The PanelBar widget displays hierarchical data as a multi-level expandable panel bar.',
        depends: [
            'core',
            'data',
            'data.odata'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, keys = kendo.keys, extend = $.extend, proxy = $.proxy, each = $.each, isArray = $.isArray, template = kendo.template, Widget = ui.Widget, HierarchicalDataSource = kendo.data.HierarchicalDataSource, excludedNodesRegExp = /^(ul|a|div)$/i, NS = '.kendoPanelBar', IMG = 'img', HREF = 'href', LAST = 'k-last', LINK = 'k-link', LINKSELECTOR = '.' + LINK, ERROR = 'error', ITEM = '.k-item', GROUP = '.k-group', VISIBLEGROUP = GROUP + ':visible', IMAGE = 'k-image', FIRST = 'k-first', CHANGE = 'change', EXPAND = 'expand', SELECT = 'select', CONTENT = 'k-content', ACTIVATE = 'activate', COLLAPSE = 'collapse', DATABOUND = 'dataBound', MOUSEENTER = 'mouseenter', MOUSELEAVE = 'mouseleave', CONTENTLOAD = 'contentLoad', UNDEFINED = 'undefined', ACTIVECLASS = 'k-state-active', GROUPS = '> .k-panel', CONTENTS = '> .k-content', STRING = 'string', FOCUSEDCLASS = 'k-state-focused', DISABLEDCLASS = 'k-state-disabled', SELECTEDCLASS = 'k-state-selected', SELECTEDSELECTOR = '.' + SELECTEDCLASS, HIGHLIGHTCLASS = 'k-state-highlight', ACTIVEITEMSELECTOR = ITEM + ':not(.k-state-disabled)', clickableItems = '> ' + ACTIVEITEMSELECTOR + ' > ' + LINKSELECTOR + ', .k-panel > ' + ACTIVEITEMSELECTOR + ' > ' + LINKSELECTOR, disabledItems = ITEM + '.k-state-disabled > .k-link', selectableItems = '> li > ' + SELECTEDSELECTOR + ', .k-panel > li > ' + SELECTEDSELECTOR, defaultState = 'k-state-default', ARIA_DISABLED = 'aria-disabled', ARIA_EXPANDED = 'aria-expanded', ARIA_HIDDEN = 'aria-hidden', ARIA_SELECTED = 'aria-selected', VISIBLE = ':visible', EMPTY = ':empty', SINGLE = 'single', bindings = {
                text: 'dataTextField',
                url: 'dataUrlField',
                spriteCssClass: 'dataSpriteCssClassField',
                imageUrl: 'dataImageUrlField'
            }, itemIcon, rendering = {
                aria: function (item) {
                    var attr = '';
                    if (item.items || item.content || item.contentUrl || item.expanded) {
                        attr += ARIA_EXPANDED + '=\'' + (item.expanded ? 'true' : 'false') + '\' ';
                    }
                    if (item.enabled === false) {
                        attr += ARIA_DISABLED + '=\'true\'';
                    }
                    return attr;
                },
                wrapperCssClass: function (group, item) {
                    var result = 'k-item', index = item.index;
                    if (item.enabled === false) {
                        result += ' ' + DISABLEDCLASS;
                    } else if (item.expanded === true) {
                        result += ' ' + ACTIVECLASS;
                    } else {
                        result += ' k-state-default';
                    }
                    if (index === 0) {
                        result += ' k-first';
                    }
                    if (index == group.length - 1) {
                        result += ' k-last';
                    }
                    if (item.cssClass) {
                        result += ' ' + item.cssClass;
                    }
                    return result;
                },
                textClass: function (item, group) {
                    var result = LINK;
                    if (group.firstLevel) {
                        result += ' k-header';
                    }
                    return result;
                },
                textAttributes: function (url) {
                    return url ? ' href=\'' + url + '\'' : '';
                },
                arrowClass: function (item) {
                    var result = 'k-icon';
                    result += item.expanded ? ' k-panelbar-collapse k-i-arrow-n' : ' k-panelbar-expand k-i-arrow-s';
                    return result;
                },
                text: function (item) {
                    return item.encoded === false ? item.text : kendo.htmlEncode(item.text);
                },
                groupAttributes: function (group) {
                    return group.expanded !== true ? ' style=\'display:none\'' : '';
                },
                groupCssClass: function () {
                    return 'k-group k-panel';
                },
                contentAttributes: function (content) {
                    return content.item.expanded !== true ? ' style=\'display:none\'' : '';
                },
                content: function (item) {
                    return item.content ? item.content : item.contentUrl ? '' : '&nbsp;';
                },
                contentUrl: function (item) {
                    return item.contentUrl ? 'href="' + item.contentUrl + '"' : '';
                }
            };
        function updateFirstLast(items) {
            items = $(items);
            items.filter('.k-first:not(:first-child)').removeClass(FIRST);
            items.filter('.k-last:not(:last-child)').removeClass(LAST);
            items.filter(':first-child').addClass(FIRST);
            items.filter(':last-child').addClass(LAST);
        }
        function updateItemHtml(item) {
            var wrapper = item, group = item.children('ul'), toggleButton = wrapper.children('.k-link').children('.k-icon');
            if (item.hasClass('k-panelbar')) {
                return;
            }
            if (!toggleButton.length && group.length) {
                toggleButton = $('<span class=\'k-icon\' />').appendTo(wrapper);
            } else if (!group.length || !group.children().length) {
                toggleButton.remove();
                group.remove();
            }
        }
        itemIcon = function (item) {
            return item.children('span').children('.k-icon');
        };
        var PanelBar = kendo.ui.DataBoundWidget.extend({
            init: function (element, options) {
                var that = this, content, hasDataSource;
                if (isArray(options)) {
                    options = { dataSource: options };
                }
                hasDataSource = options && !!options.dataSource;
                Widget.fn.init.call(that, element, options);
                element = that.wrapper = that.element.addClass('k-widget k-reset k-header k-panelbar');
                options = that.options;
                if (element[0].id) {
                    that._itemId = element[0].id + '_pb_active';
                }
                that._tabindex();
                that._accessors();
                that._dataSource();
                that._templates();
                that._initData(hasDataSource);
                that._updateClasses();
                that._animations(options);
                element.on('click' + NS, clickableItems, function (e) {
                    if (that._click($(e.currentTarget))) {
                        e.preventDefault();
                    }
                }).on(MOUSEENTER + NS + ' ' + MOUSELEAVE + NS, clickableItems, that._toggleHover).on('click' + NS, disabledItems, false).on('click' + NS, '.k-request-retry', proxy(that._retryRequest, that)).on('keydown' + NS, $.proxy(that._keydown, that)).on('focus' + NS, function () {
                    var item = that.select();
                    that._current(item[0] ? item : that._first());
                }).on('blur' + NS, function () {
                    that._current(null);
                }).attr('role', 'menu');
                content = element.find('li.' + ACTIVECLASS + ' > .' + CONTENT);
                if (content[0]) {
                    that.expand(content.parent(), false);
                }
                if (!options.dataSource) {
                    that._angularCompile();
                }
                kendo.notify(that);
            },
            events: [
                EXPAND,
                COLLAPSE,
                SELECT,
                ACTIVATE,
                CHANGE,
                ERROR,
                DATABOUND,
                CONTENTLOAD
            ],
            options: {
                name: 'PanelBar',
                dataSource: {},
                animation: {
                    expand: {
                        effects: 'expand:vertical',
                        duration: 200
                    },
                    collapse: { duration: 200 }
                },
                messages: {
                    loading: 'Loading...',
                    requestFailed: 'Request failed.',
                    retry: 'Retry'
                },
                autoBind: true,
                loadOnDemand: true,
                expandMode: 'multiple',
                dataTextField: null
            },
            _angularCompile: function () {
                var that = this;
                that.angular('compile', function () {
                    return {
                        elements: that.element.children('li'),
                        data: [{ dataItem: that.options.$angular }]
                    };
                });
            },
            _angularCompileElements: function (html, items) {
                var that = this;
                that.angular('compile', function () {
                    return {
                        elements: html,
                        data: $.map(items, function (item) {
                            return [{ dataItem: item }];
                        })
                    };
                });
            },
            _angularCleanup: function () {
                var that = this;
                that.angular('cleanup', function () {
                    return { elements: that.element.children('li') };
                });
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.off(NS);
                this._angularCleanup();
                kendo.destroy(this.element);
            },
            _initData: function (hasDataSource) {
                var that = this;
                if (hasDataSource) {
                    that.element.empty();
                    if (that.options.autoBind) {
                        that._progress(true);
                        that.dataSource.fetch();
                    }
                }
            },
            _templates: function () {
                var that = this, options = that.options, fieldAccessor = proxy(that._fieldAccessor, that);
                if (options.template && typeof options.template == STRING) {
                    options.template = template(options.template);
                } else if (!options.template) {
                    options.template = template('# var text = ' + fieldAccessor('text') + '(data.item); #' + '# if (typeof data.item.encoded != \'undefined\' && data.item.encoded === false) {#' + '#= text #' + '# } else { #' + '#: text #' + '# } #');
                }
                that.templates = {
                    content: template('<div role=\'region\' class=\'k-content\'#= contentAttributes(data) #>#= content(item) #</div>'),
                    group: template('<ul role=\'group\' aria-hidden=\'true\' class=\'#= groupCssClass(group) #\'#= groupAttributes(group) #>' + '#= renderItems(data) #' + '</ul>'),
                    itemWrapper: template('# var url = ' + fieldAccessor('url') + '(item); #' + '# var imageUrl = ' + fieldAccessor('imageUrl') + '(item); #' + '# var spriteCssClass = ' + fieldAccessor('spriteCssClass') + '(item); #' + '# var contentUrl = contentUrl(item); #' + '# var tag = url||contentUrl ? \'a\' : \'span\'; #' + '<#= tag # class=\'#= textClass(item, group) #\' #= contentUrl ##= textAttributes(url) #>' + '# if (imageUrl) { #' + '<img class=\'k-image\' alt=\'\' src=\'#= imageUrl #\' />' + '# } #' + '# if (spriteCssClass) { #' + '<span class=\'k-sprite #= spriteCssClass #\'></span>' + '# } #' + '#= data.panelBar.options.template(data) #' + '#= arrow(data) #' + '</#= tag #>'),
                    item: template('<li role=\'menuitem\' #=aria(item)#class=\'#= wrapperCssClass(group, item) #\'' + kendo.attr('uid') + '=\'#= item.uid #\'>' + '#= itemWrapper(data) #' + '# if (item.items && item.items.length > 0) { #' + '#= subGroup({ items: item.items, panelBar: panelBar, group: { expanded: item.expanded } }) #' + '# } else if (item.content || item.contentUrl) { #' + '#= renderContent(data) #' + '# } #' + '</li>'),
                    loading: template('<div class=\'k-item\'><span class=\'k-icon k-i-loading\'></span> #: data.messages.loading #</div>'),
                    retry: template('#: data.messages.requestFailed # ' + '<button class=\'k-button k-request-retry\'>#: data.messages.retry #</button>'),
                    arrow: template('<span class=\'#= arrowClass(item) #\'></span>'),
                    empty: template('')
                };
            },
            setOptions: function (options) {
                var animation = this.options.animation;
                this._animations(options);
                options.animation = extend(true, animation, options.animation);
                if ('dataSource' in options) {
                    this.setDataSource(options.dataSource);
                }
                Widget.fn.setOptions.call(this, options);
            },
            expand: function (element, useAnimation) {
                var that = this, animBackup = {};
                element = this.element.find(element);
                if (that._animating && element.find('ul').is(':visible')) {
                    that.one('complete', function () {
                        setTimeout(function () {
                            that.expand(element);
                        });
                    });
                    return;
                }
                that._animating = true;
                useAnimation = useAnimation !== false;
                element.each(function (index, item) {
                    item = $(item);
                    var wrapper = element.children('.k-group,.k-content');
                    if (!wrapper.length) {
                        wrapper = that._addGroupElement(element);
                    }
                    var groups = wrapper.add(item.find(CONTENTS));
                    if (!item.hasClass(DISABLEDCLASS) && groups.length > 0) {
                        if (that.options.expandMode == SINGLE && that._collapseAllExpanded(item)) {
                            return that;
                        }
                        element.find('.' + HIGHLIGHTCLASS).removeClass(HIGHLIGHTCLASS);
                        item.addClass(HIGHLIGHTCLASS);
                        if (!useAnimation) {
                            animBackup = that.options.animation;
                            that.options.animation = {
                                expand: { effects: {} },
                                collapse: {
                                    hide: true,
                                    effects: {}
                                }
                            };
                        }
                        if (!that._triggerEvent(EXPAND, item)) {
                            that._toggleItem(item, false, false);
                        }
                        if (!useAnimation) {
                            that.options.animation = animBackup;
                        }
                    }
                });
                return that;
            },
            collapse: function (element, useAnimation) {
                var that = this, animBackup = {};
                that._animating = true;
                useAnimation = useAnimation !== false;
                element = that.element.find(element);
                element.each(function (index, item) {
                    item = $(item);
                    var groups = item.find(GROUPS).add(item.find(CONTENTS));
                    if (!item.hasClass(DISABLEDCLASS) && groups.is(VISIBLE)) {
                        item.removeClass(HIGHLIGHTCLASS);
                        if (!useAnimation) {
                            animBackup = that.options.animation;
                            that.options.animation = {
                                expand: { effects: {} },
                                collapse: {
                                    hide: true,
                                    effects: {}
                                }
                            };
                        }
                        if (!that._triggerEvent(COLLAPSE, item)) {
                            that._toggleItem(item, true);
                        }
                        if (!useAnimation) {
                            that.options.animation = animBackup;
                        }
                    }
                });
                return that;
            },
            updateArrow: function (items) {
                var that = this;
                items = $(items);
                items.children(LINKSELECTOR).children('.k-panelbar-collapse, .k-panelbar-expand').remove();
                items.filter(function () {
                    var dataItem = that.dataItem(this);
                    if (!dataItem) {
                        return $(this).find('.k-panel').length > 0 || $(this).find('.k-content').length > 0;
                    }
                    return dataItem.hasChildren || dataItem.content || dataItem.contentUrl;
                }).children('.k-link:not(:has([class*=k-i-arrow]))').each(function () {
                    var item = $(this), parent = item.parent();
                    item.append('<span class=\'k-icon ' + (parent.hasClass(ACTIVECLASS) ? ' k-panelbar-collapse k-i-arrow-n' : ' k-panelbar-expand k-i-arrow-s') + '\'/>');
                });
            },
            _accessors: function () {
                var that = this, options = that.options, i, field, textField, element = that.element;
                for (i in bindings) {
                    field = options[bindings[i]];
                    textField = element.attr(kendo.attr(i + '-field'));
                    if (!field && textField) {
                        field = textField;
                    }
                    if (!field) {
                        field = i;
                    }
                    if (!isArray(field)) {
                        field = [field];
                    }
                    options[bindings[i]] = field;
                }
            },
            _progress: function (item, showProgress) {
                var element = this.element;
                var loadingText = this.templates.loading({ messages: this.options.messages });
                if (arguments.length == 1) {
                    showProgress = item;
                    if (showProgress) {
                        element.html(loadingText);
                    } else {
                        element.empty();
                    }
                } else {
                    itemIcon(item).toggleClass('k-i-loading', showProgress).removeClass('k-i-refresh');
                }
            },
            _refreshRoot: function (items) {
                var that = this;
                var parent = that.element;
                var groupData = {
                    firstLevel: true,
                    expanded: true,
                    length: parent.children().length
                };
                this.element.empty();
                var rootItemsHtml = $.map(items, function (value, idx) {
                    if (typeof value === 'string') {
                        return $(value);
                    } else {
                        value.items = [];
                        return $(that.renderItem({
                            group: groupData,
                            item: extend(value, { index: idx })
                        }));
                    }
                });
                this.element.append(rootItemsHtml);
                this._angularCompileElements(rootItemsHtml, items);
            },
            _refreshChildren: function (item, parentNode) {
                var i, children, child;
                parentNode.children('.k-group').empty();
                var items = item.children.data();
                if (!items.length) {
                    updateItemHtml(parentNode);
                    children = parentNode.children('.k-group').children('li');
                    this._angularCompileElements(children, items);
                } else {
                    this.append(item.children, parentNode);
                    if (this.options.loadOnDemand) {
                        this._toggleGroup(parentNode.children('.k-group'), false);
                    }
                    children = parentNode.children('.k-group').children('li');
                    for (i = 0; i < children.length; i++) {
                        child = children.eq(i);
                        this.trigger('itemChange', {
                            item: child,
                            data: this.dataItem(child),
                            ns: ui
                        });
                    }
                }
            },
            findByUid: function (uid) {
                var items = this.element.find('.k-item');
                var uidAttr = kendo.attr('uid');
                var result;
                for (var i = 0; i < items.length; i++) {
                    if (items[i].getAttribute(uidAttr) == uid) {
                        result = items[i];
                        break;
                    }
                }
                return $(result);
            },
            refresh: function (e) {
                var options = this.options;
                var node = e.node;
                var action = e.action;
                var items = e.items;
                var parentNode = this.wrapper;
                var loadOnDemand = options.loadOnDemand;
                if (e.field) {
                    if (!items[0] || !items[0].level) {
                        return;
                    }
                    return this._updateItems(items, e.field);
                }
                if (node) {
                    parentNode = this.findByUid(node.uid);
                    this._progress(parentNode, false);
                }
                if (action == 'add') {
                    this._appendItems(e.index, items, parentNode);
                } else if (action == 'remove') {
                    this.remove(this.findByUid(items[0].uid));
                } else if (action == 'itemchange') {
                    this._updateItems(items);
                } else if (action == 'itemloaded') {
                    this._refreshChildren(node, parentNode);
                } else {
                    this._refreshRoot(items);
                }
                if (action != 'remove') {
                    for (var k = 0; k < items.length; k++) {
                        if (!loadOnDemand || items[k].expanded) {
                            var tempItem = items[k];
                            if (this._hasChildItems(tempItem)) {
                                tempItem.load();
                            }
                        }
                    }
                }
                this.trigger(DATABOUND, { node: node ? parentNode : undefined });
            },
            _error: function (e) {
                var node = e.node && this.findByUid(e.node.uid);
                var retryHtml = this.templates.retry({ messages: this.options.messages });
                if (node) {
                    this._progress(node, false);
                    this._expanded(node, false);
                    itemIcon(node).addClass('k-i-refresh');
                    e.node.loaded(false);
                } else {
                    this._progress(false);
                    this.element.html(retryHtml);
                }
            },
            _retryRequest: function (e) {
                e.preventDefault();
                this.dataSource.fetch();
            },
            items: function () {
                return this.element.find('.k-item > span:first-child');
            },
            setDataSource: function (dataSource) {
                var options = this.options;
                options.dataSource = dataSource;
                this._dataSource();
                if (this.options.autoBind) {
                    this._progress(true);
                    this.dataSource.fetch();
                }
            },
            _bindDataSource: function () {
                this._refreshHandler = proxy(this.refresh, this);
                this._errorHandler = proxy(this._error, this);
                this.dataSource.bind(CHANGE, this._refreshHandler);
                this.dataSource.bind(ERROR, this._errorHandler);
            },
            _unbindDataSource: function () {
                var dataSource = this.dataSource;
                if (dataSource) {
                    dataSource.unbind(CHANGE, this._refreshHandler);
                    dataSource.unbind(ERROR, this._errorHandler);
                }
            },
            _fieldAccessor: function (fieldName) {
                var fieldBindings = this.options[bindings[fieldName]] || [], count = fieldBindings.length, result = '(function(item) {';
                if (count === 0) {
                    result += 'return item[\'' + fieldName + '\'];';
                } else {
                    result += 'var levels = [' + $.map(fieldBindings, function (x) {
                        return 'function(d){ return ' + kendo.expr(x) + '}';
                    }).join(',') + '];';
                    result += 'if(item.level){return levels[Math.min(item.level(), ' + count + '-1)](item);}else';
                    result += '{return levels[' + count + '-1](item)}';
                }
                result += '})';
                return result;
            },
            _dataSource: function () {
                var that = this, options = that.options, dataSource = options.dataSource;
                if (!dataSource) {
                    return;
                }
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                that._unbindDataSource();
                if (!dataSource.fields) {
                    dataSource.fields = [
                        { field: 'text' },
                        { field: 'url' },
                        { field: 'spriteCssClass' },
                        { field: 'imageUrl' }
                    ];
                }
                that.dataSource = HierarchicalDataSource.create(dataSource);
                that._bindDataSource();
            },
            _appendItems: function (index, items, parentNode) {
                var that = this, children, wrapper;
                if (parentNode.hasClass('k-panelbar')) {
                    children = parentNode.children('li');
                    wrapper = parentNode;
                } else {
                    wrapper = parentNode.children('.k-group');
                    if (!wrapper.length) {
                        wrapper = that._addGroupElement(parentNode);
                    }
                    children = wrapper.children('li');
                }
                var groupData = {
                    firstLevel: parentNode.hasClass('k-panelbar'),
                    expanded: true,
                    length: children.length
                };
                var itemsHtml = $.map(items, function (value, idx) {
                    if (typeof value === 'string') {
                        return $(value);
                    } else {
                        return $(that.renderItem({
                            group: groupData,
                            item: extend(value, { index: idx })
                        }));
                    }
                });
                if (typeof index == UNDEFINED) {
                    index = children.length;
                }
                for (var i = 0; i < itemsHtml.length; i++) {
                    if (children.length === 0 || index === 0) {
                        wrapper.append(itemsHtml[i]);
                    } else {
                        itemsHtml[i].insertAfter(children[index - 1]);
                    }
                }
                that._angularCompileElements(itemsHtml, items);
                if (that.dataItem(parentNode)) {
                    that.dataItem(parentNode).hasChildren = true;
                    that.updateArrow(parentNode);
                }
            },
            _updateItems: function (items, field) {
                var that = this;
                var i, node, nodeWrapper, item;
                var context = {
                    panelBar: that.options,
                    item: item,
                    group: {}
                };
                var render = field != 'expanded';
                if (field == 'selected') {
                    if (items[0][field]) {
                        var currentNode = that.findByUid(items[0].uid);
                        if (!currentNode.hasClass(DISABLEDCLASS)) {
                            that.select(currentNode, true);
                        }
                    } else {
                        that.clearSelection();
                    }
                } else {
                    var elements = $.map(items, function (item) {
                        return that.findByUid(item.uid);
                    });
                    if (render) {
                        that.angular('cleanup', function () {
                            return { elements: elements };
                        });
                    }
                    for (i = 0; i < items.length; i++) {
                        context.item = item = items[i];
                        context.panelBar = that;
                        nodeWrapper = elements[i];
                        node = nodeWrapper.parent();
                        if (render) {
                            context.group = {
                                firstLevel: node.hasClass('k-panelbar'),
                                expanded: nodeWrapper.parent().hasClass(ACTIVECLASS),
                                length: nodeWrapper.children().length
                            };
                            nodeWrapper.children('.k-link').remove();
                            nodeWrapper.prepend(that.templates.itemWrapper(extend(context, { arrow: item.hasChildren || item.content || item.contentUrl ? that.templates.arrow : that.templates.empty }, rendering)));
                        }
                        if (field == 'expanded') {
                            that._toggleItem(nodeWrapper, !item[field], item[field] ? 'true' : true);
                        } else if (field == 'enabled') {
                            that.enable(nodeWrapper, item[field]);
                            if (!item[field]) {
                                if (item.selected) {
                                    item.set('selected', false);
                                }
                            }
                        }
                        if (nodeWrapper.length) {
                            this.trigger('itemChange', {
                                item: nodeWrapper,
                                data: item,
                                ns: ui
                            });
                        }
                    }
                    if (render) {
                        that.angular('compile', function () {
                            return {
                                elements: elements,
                                data: $.map(items, function (item) {
                                    return [{ dataItem: item }];
                                })
                            };
                        });
                    }
                }
            },
            _toggleDisabled: function (element, enable) {
                element = this.element.find(element);
                element.toggleClass(defaultState, enable).toggleClass(DISABLEDCLASS, !enable).attr(ARIA_DISABLED, !enable);
            },
            dataItem: function (item) {
                var uid = $(item).closest(ITEM).attr(kendo.attr('uid')), dataSource = this.dataSource;
                return dataSource && dataSource.getByUid(uid);
            },
            select: function (element, skipChange) {
                var that = this;
                if (element === undefined) {
                    return that.element.find(selectableItems).parent();
                }
                element = that.element.find(element);
                if (!element.length) {
                    this._updateSelected(element);
                } else {
                    element.each(function () {
                        var item = $(this), link = item.children(LINKSELECTOR);
                        if (item.hasClass(DISABLEDCLASS)) {
                            return that;
                        }
                        that._updateSelected(link, skipChange);
                    });
                }
                return that;
            },
            clearSelection: function () {
                this.select($());
            },
            enable: function (element, state) {
                this._toggleDisabled(element, state !== false);
                return this;
            },
            disable: function (element) {
                this._toggleDisabled(element, false);
                return this;
            },
            append: function (item, referenceItem) {
                referenceItem = this.element.find(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.length ? referenceItem.find(GROUPS) : null);
                each(inserted.items, function () {
                    inserted.group.append(this);
                    updateFirstLast(this);
                });
                this.updateArrow(referenceItem);
                updateFirstLast(inserted.group.find('.k-first, .k-last'));
                inserted.group.height('auto');
                return this;
            },
            insertBefore: function (item, referenceItem) {
                referenceItem = this.element.find(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.parent());
                each(inserted.items, function () {
                    referenceItem.before(this);
                    updateFirstLast(this);
                });
                updateFirstLast(referenceItem);
                inserted.group.height('auto');
                return this;
            },
            insertAfter: function (item, referenceItem) {
                referenceItem = this.element.find(referenceItem);
                var inserted = this._insert(item, referenceItem, referenceItem.parent());
                each(inserted.items, function () {
                    referenceItem.after(this);
                    updateFirstLast(this);
                });
                updateFirstLast(referenceItem);
                inserted.group.height('auto');
                return this;
            },
            remove: function (element) {
                element = this.element.find(element);
                var that = this, parent = element.parentsUntil(that.element, ITEM), group = element.parent('ul');
                element.remove();
                if (group && !group.hasClass('k-panelbar') && !group.children(ITEM).length) {
                    group.remove();
                }
                if (parent.length) {
                    parent = parent.eq(0);
                    that.updateArrow(parent);
                    updateFirstLast(parent);
                }
                return that;
            },
            reload: function (element) {
                var that = this;
                element = that.element.find(element);
                element.each(function () {
                    var item = $(this);
                    that._ajaxRequest(item, item.children('.' + CONTENT), !item.is(VISIBLE));
                });
            },
            _first: function () {
                return this.element.children(ACTIVEITEMSELECTOR).first();
            },
            _last: function () {
                var item = this.element.children(ACTIVEITEMSELECTOR).last(), group = item.children(VISIBLEGROUP);
                if (group[0]) {
                    return group.children(ACTIVEITEMSELECTOR).last();
                }
                return item;
            },
            _current: function (candidate) {
                var that = this, focused = that._focused, id = that._itemId;
                if (candidate === undefined) {
                    return focused;
                }
                that.element.removeAttr('aria-activedescendant');
                if (focused && focused.length) {
                    if (focused[0].id === id) {
                        focused.removeAttr('id');
                    }
                    focused.children(LINKSELECTOR).removeClass(FOCUSEDCLASS);
                }
                if ($(candidate).length) {
                    id = candidate[0].id || id;
                    candidate.attr('id', id).children(LINKSELECTOR).addClass(FOCUSEDCLASS);
                    that.element.attr('aria-activedescendant', id);
                }
                that._focused = candidate;
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, current = that._current();
                if (e.target != e.currentTarget) {
                    return;
                }
                if (key == keys.DOWN || key == keys.RIGHT) {
                    that._current(that._nextItem(current));
                    e.preventDefault();
                } else if (key == keys.UP || key == keys.LEFT) {
                    that._current(that._prevItem(current));
                    e.preventDefault();
                } else if (key == keys.ENTER || key == keys.SPACEBAR) {
                    that._click(current.children(LINKSELECTOR));
                    e.preventDefault();
                } else if (key == keys.HOME) {
                    that._current(that._first());
                    e.preventDefault();
                } else if (key == keys.END) {
                    that._current(that._last());
                    e.preventDefault();
                }
            },
            _nextItem: function (item) {
                if (!item) {
                    return this._first();
                }
                var group = item.children(VISIBLEGROUP), next = item.nextAll(':visible').first();
                if (group[0]) {
                    next = group.children('.' + FIRST);
                }
                if (!next[0]) {
                    next = item.parent(VISIBLEGROUP).parent(ITEM).next();
                }
                if (!next[0]) {
                    next = this._first();
                }
                if (next.hasClass(DISABLEDCLASS)) {
                    next = this._nextItem(next);
                }
                return next;
            },
            _prevItem: function (item) {
                if (!item) {
                    return this._last();
                }
                var prev = item.prevAll(':visible').first(), result;
                if (!prev[0]) {
                    prev = item.parent(VISIBLEGROUP).parent(ITEM);
                    if (!prev[0]) {
                        prev = this._last();
                    }
                } else {
                    result = prev;
                    while (result[0]) {
                        result = result.children(VISIBLEGROUP).children('.' + LAST);
                        if (result[0]) {
                            prev = result;
                        }
                    }
                }
                if (prev.hasClass(DISABLEDCLASS)) {
                    prev = this._prevItem(prev);
                }
                return prev;
            },
            _insert: function (item, referenceItem, parent) {
                var that = this, items, plain = $.isPlainObject(item), isReferenceItem = referenceItem && referenceItem[0], groupData;
                if (!isReferenceItem) {
                    parent = that.element;
                }
                groupData = {
                    firstLevel: parent.hasClass('k-panelbar'),
                    expanded: $(referenceItem).hasClass(ACTIVECLASS),
                    length: parent.children().length
                };
                if (isReferenceItem && !parent.length) {
                    parent = $(that.renderGroup({
                        group: groupData,
                        options: that.options
                    })).appendTo(referenceItem);
                }
                if (plain || $.isArray(item) || item instanceof HierarchicalDataSource) {
                    if (item instanceof HierarchicalDataSource) {
                        item = item.data();
                    }
                    items = $.map(plain ? [item] : item, function (value, idx) {
                        if (typeof value === 'string') {
                            return $(value);
                        } else {
                            return $(that.renderItem({
                                group: groupData,
                                item: extend(value, { index: idx })
                            }));
                        }
                    });
                    if (isReferenceItem) {
                        var dataItem = that.dataItem(referenceItem);
                        if (dataItem) {
                            dataItem.hasChildren = true;
                        }
                        referenceItem.attr(ARIA_EXPANDED, false);
                    }
                } else {
                    if (typeof item == 'string' && item.charAt(0) != '<') {
                        items = that.element.find(item);
                    } else {
                        items = $(item);
                    }
                    that._updateItemsClasses(items);
                }
                if (!item.length) {
                    item = [item];
                }
                that._angularCompileElements(items, item);
                return {
                    items: items,
                    group: parent
                };
            },
            _toggleHover: function (e) {
                var target = $(e.currentTarget);
                if (!target.parents('li.' + DISABLEDCLASS).length) {
                    target.toggleClass('k-state-hover', e.type == MOUSEENTER);
                }
            },
            _updateClasses: function () {
                var that = this, panels, items;
                panels = that.element.find('li > ul').not(function () {
                    return $(this).parentsUntil('.k-panelbar', 'div').length;
                }).addClass('k-group k-panel').attr('role', 'group');
                panels.parent().attr(ARIA_EXPANDED, false).not('.' + ACTIVECLASS).children('ul').attr(ARIA_HIDDEN, true).hide();
                items = that.element.add(panels).children();
                that._updateItemsClasses(items);
                that.updateArrow(items);
                updateFirstLast(items);
            },
            _updateItemsClasses: function (items) {
                var length = items.length, idx = 0;
                for (; idx < length; idx++) {
                    this._updateItemClasses(items[idx], idx);
                }
            },
            _updateItemClasses: function (item, index) {
                var selected = this._selected, contentUrls = this.options.contentUrls, url = contentUrls && contentUrls[index], root = this.element[0], wrapElement, link;
                item = $(item).addClass('k-item').attr('role', 'menuitem');
                if (kendo.support.browser.msie) {
                    item.css('list-style-position', 'inside').css('list-style-position', '');
                }
                item.children(IMG).addClass(IMAGE);
                link = item.children('a').addClass(LINK);
                if (link[0]) {
                    link.attr('href', url);
                    link.children(IMG).addClass(IMAGE);
                }
                item.filter(':not([disabled]):not([class*=k-state])').addClass('k-state-default');
                item.filter('li[disabled]').addClass('k-state-disabled').attr(ARIA_DISABLED, true).removeAttr('disabled');
                item.children('div').addClass(CONTENT).attr('role', 'region').attr(ARIA_HIDDEN, true).hide().parent().attr(ARIA_EXPANDED, false);
                link = item.children(SELECTEDSELECTOR);
                if (link[0]) {
                    if (selected) {
                        selected.removeAttr(ARIA_SELECTED).children(SELECTEDSELECTOR).removeClass(SELECTEDCLASS);
                    }
                    link.addClass(SELECTEDCLASS);
                    this._selected = item.attr(ARIA_SELECTED, true);
                }
                if (!item.children(LINKSELECTOR)[0]) {
                    wrapElement = '<span class=\'' + LINK + '\'/>';
                    if (contentUrls && contentUrls[index] && item[0].parentNode == root) {
                        wrapElement = '<a class="k-link k-header" href="' + contentUrls[index] + '"/>';
                    }
                    item.contents().filter(function () {
                        return !this.nodeName.match(excludedNodesRegExp) && !(this.nodeType == 3 && !$.trim(this.nodeValue));
                    }).wrapAll(wrapElement);
                }
                if (item.parent('.k-panelbar')[0]) {
                    item.children(LINKSELECTOR).addClass('k-header');
                }
            },
            _click: function (target) {
                var that = this, element = that.element, prevent, contents, href, isAnchor;
                if (target.parents('li.' + DISABLEDCLASS).length) {
                    return;
                }
                if (target.closest('.k-widget')[0] != element[0]) {
                    return;
                }
                var link = target.closest(LINKSELECTOR), item = link.closest(ITEM);
                that._updateSelected(link);
                var wrapper = item.children('.k-group,.k-content');
                var dataItem = this.dataItem(item);
                if (!wrapper.length && (that.options.loadOnDemand && dataItem && dataItem.hasChildren || this._hasChildItems(item) || item.content || item.contentUrl)) {
                    wrapper = that._addGroupElement(item);
                }
                contents = item.find(GROUPS).add(item.find(CONTENTS));
                href = link.attr(HREF);
                isAnchor = href && (href.charAt(href.length - 1) == '#' || href.indexOf('#' + that.element[0].id + '-') != -1);
                prevent = !!(isAnchor || contents.length);
                if (contents.data('animating')) {
                    return prevent;
                }
                if (that._triggerEvent(SELECT, item)) {
                    prevent = true;
                }
                if (prevent === false) {
                    return;
                }
                if (that.options.expandMode == SINGLE) {
                    if (that._collapseAllExpanded(item)) {
                        return prevent;
                    }
                }
                if (contents.length) {
                    var visibility = contents.is(VISIBLE);
                    if (!that._triggerEvent(!visibility ? EXPAND : COLLAPSE, item)) {
                        prevent = that._toggleItem(item, visibility);
                    }
                }
                return prevent;
            },
            _hasChildItems: function (item) {
                return item.items && item.items.length > 0 || item.hasChildren;
            },
            _toggleItem: function (element, isVisible, expanded) {
                var that = this, childGroup = element.find(GROUPS), link = element.find(LINKSELECTOR), url = link.attr(HREF), prevent, content, dataItem = that.dataItem(element);
                var loaded = dataItem && dataItem.loaded();
                if (dataItem && !expanded) {
                    dataItem.set('expanded', !isVisible);
                    prevent = dataItem.hasChildren || !!dataItem.content || !!dataItem.contentUrl;
                    return prevent;
                }
                if (dataItem && (!expanded || expanded === 'true') && !loaded && !dataItem.content && !dataItem.contentUrl) {
                    if (that.options.loadOnDemand) {
                        this._progress(element, true);
                    }
                    element.children('.k-group,.k-content').remove();
                    prevent = dataItem.hasChildren;
                    dataItem.load();
                } else {
                    if (childGroup.length) {
                        this._toggleGroup(childGroup, isVisible);
                        prevent = true;
                    } else {
                        content = element.children('.' + CONTENT);
                        if (content.length) {
                            prevent = true;
                            if (!content.is(EMPTY) || url === undefined) {
                                that._toggleGroup(content, isVisible);
                            } else {
                                that._ajaxRequest(element, content, isVisible);
                            }
                        }
                    }
                }
                return prevent;
            },
            _toggleGroup: function (element, visibility) {
                var that = this, animationSettings = that.options.animation, animation = animationSettings.expand, hasCollapseAnimation = animationSettings.collapse && 'effects' in animationSettings.collapse, collapse = extend({}, animationSettings.expand, animationSettings.collapse);
                if (!hasCollapseAnimation) {
                    collapse = extend(collapse, { reverse: true });
                }
                if (element.is(VISIBLE) != visibility) {
                    that._animating = false;
                    return;
                }
                element.parent().attr(ARIA_EXPANDED, !visibility).attr(ARIA_HIDDEN, visibility).toggleClass(ACTIVECLASS, !visibility).find('> .k-link > .k-panelbar-collapse,> .k-link > .k-panelbar-expand').toggleClass('k-i-arrow-n', !visibility).toggleClass('k-panelbar-collapse', !visibility).toggleClass('k-i-arrow-s', visibility).toggleClass('k-panelbar-expand', visibility);
                if (visibility) {
                    animation = extend(collapse, { hide: true });
                    animation.complete = function () {
                        that._animationCallback();
                    };
                } else {
                    animation = extend({
                        complete: function (element) {
                            that._triggerEvent(ACTIVATE, element.closest(ITEM));
                            that._animationCallback();
                        }
                    }, animation);
                }
                element.kendoStop(true, true).kendoAnimate(animation);
            },
            _animationCallback: function () {
                var that = this;
                that.trigger('complete');
                that._animating = false;
            },
            _addGroupElement: function (element) {
                var group = $('<ul role="group" aria-hidden="true" class="k-group k-panel" style="display:none"></ul>');
                element.append(group);
                return group;
            },
            _collapseAllExpanded: function (item) {
                var that = this, children, stopExpand = false;
                var groups = item.find(GROUPS).add(item.find(CONTENTS));
                if (groups.is(VISIBLE)) {
                    stopExpand = true;
                }
                if (!(groups.is(VISIBLE) || groups.length === 0)) {
                    children = item.siblings();
                    children.find(GROUPS).add(children.find(CONTENTS)).filter(function () {
                        return $(this).is(VISIBLE);
                    }).each(function (index, content) {
                        content = $(content);
                        stopExpand = that._triggerEvent(COLLAPSE, content.closest(ITEM));
                        if (!stopExpand) {
                            that._toggleGroup(content, true);
                        }
                    });
                    that.one('complete', function () {
                        setTimeout(function () {
                            children.each(function (index, child) {
                                var dataItem = that.dataItem(child);
                                if (dataItem) {
                                    dataItem.set('expanded', false);
                                }
                            });
                        });
                    });
                }
                return stopExpand;
            },
            _ajaxRequest: function (element, contentElement, isVisible) {
                var that = this, statusIcon = element.find('.k-panelbar-collapse, .k-panelbar-expand'), link = element.find(LINKSELECTOR), loadingIconTimeout = setTimeout(function () {
                        statusIcon.addClass('k-i-loading');
                    }, 100), data = {}, url = link.attr(HREF);
                $.ajax({
                    type: 'GET',
                    cache: false,
                    url: url,
                    dataType: 'html',
                    data: data,
                    error: function (xhr, status) {
                        statusIcon.removeClass('k-i-loading');
                        if (that.trigger(ERROR, {
                                xhr: xhr,
                                status: status
                            })) {
                            this.complete();
                        }
                    },
                    complete: function () {
                        clearTimeout(loadingIconTimeout);
                        statusIcon.removeClass('k-i-loading');
                    },
                    success: function (data) {
                        function getElements() {
                            return { elements: contentElement.get() };
                        }
                        try {
                            that.angular('cleanup', getElements);
                            contentElement.html(data);
                            that.angular('compile', getElements);
                        } catch (e) {
                            var console = window.console;
                            if (console && console.error) {
                                console.error(e.name + ': ' + e.message + ' in ' + url);
                            }
                            this.error(this.xhr, 'error');
                        }
                        that._toggleGroup(contentElement, isVisible);
                        that.trigger(CONTENTLOAD, {
                            item: element[0],
                            contentElement: contentElement[0]
                        });
                    }
                });
            },
            _triggerEvent: function (eventName, element) {
                var that = this;
                return that.trigger(eventName, { item: element[0] });
            },
            _updateSelected: function (link, skipChange) {
                var that = this, element = that.element, item = link.parent(ITEM), selected = that._selected, dataItem = that.dataItem(item);
                if (selected) {
                    selected.removeAttr(ARIA_SELECTED);
                }
                that._selected = item.attr(ARIA_SELECTED, true);
                element.find(selectableItems).removeClass(SELECTEDCLASS);
                element.find('> .' + HIGHLIGHTCLASS + ', .k-panel > .' + HIGHLIGHTCLASS).removeClass(HIGHLIGHTCLASS);
                link.addClass(SELECTEDCLASS);
                link.parentsUntil(element, ITEM).filter(':has(.k-header)').addClass(HIGHLIGHTCLASS);
                that._current(item[0] ? item : null);
                if (dataItem) {
                    dataItem.set('selected', true);
                }
                if (!skipChange) {
                    that.trigger(CHANGE);
                }
            },
            _animations: function (options) {
                if (options && 'animation' in options && !options.animation) {
                    options.animation = {
                        expand: { effects: {} },
                        collapse: {
                            hide: true,
                            effects: {}
                        }
                    };
                }
            },
            renderItem: function (options) {
                var that = this;
                options = extend({
                    panelBar: that,
                    group: {}
                }, options);
                var empty = that.templates.empty, item = options.item;
                return that.templates.item(extend(options, {
                    itemWrapper: that.templates.itemWrapper,
                    renderContent: that.renderContent,
                    arrow: that._hasChildItems(item) || item.content || item.contentUrl ? that.templates.arrow : empty,
                    subGroup: !options.loadOnDemand || item.expanded ? that.renderGroup : empty
                }, rendering));
            },
            renderGroup: function (options) {
                var that = this;
                var templates = that.templates || options.panelBar.templates;
                return templates.group(extend({
                    renderItems: function (options) {
                        var html = '', i = 0, items = options.items, len = items ? items.length : 0, group = extend({ length: len }, options.group);
                        for (; i < len; i++) {
                            html += options.panelBar.renderItem(extend(options, {
                                group: group,
                                item: extend({ index: i }, items[i])
                            }));
                        }
                        return html;
                    }
                }, options, rendering));
            },
            renderContent: function (options) {
                return options.panelBar.templates.content(extend(options, rendering));
            }
        });
        kendo.ui.plugin(PanelBar);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.responsivepanel', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'responsive-panel',
        name: 'Responsive Panel',
        category: 'web',
        description: 'The Responsive Panel widget allows a panel of content to be hidden on mobile devices, available through a toggle button.',
        depends: ['core']
    };
    (function ($, undefined) {
        var proxy = $.proxy;
        var NS = '.kendoResponsivePanel';
        var OPEN = 'open';
        var CLOSE = 'close';
        var ACTIVATE_EVENTS = 'click' + NS + ' touchstart' + NS;
        var Widget = kendo.ui.Widget;
        var ResponsivePanel = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._guid = '_' + kendo.guid();
                this._toggleHandler = proxy(this._toggleButtonClick, this);
                this._closeHandler = proxy(this._close, this);
                $(document.documentElement).on(ACTIVATE_EVENTS, this.options.toggleButton, this._toggleHandler);
                this._registerBreakpoint();
                this.element.addClass('k-rpanel k-rpanel-' + this.options.orientation + ' ' + this._guid);
                this._resizeHandler = proxy(this.resize, this, true);
                $(window).on('resize' + NS, this._resizeHandler);
            },
            _mediaQuery: '@media (max-width: #= breakpoint-1 #px) {' + '.#= guid #.k-rpanel-animate.k-rpanel-left,' + '.#= guid #.k-rpanel-animate.k-rpanel-right {' + '-webkit-transition: -webkit-transform .2s ease-out;' + '-ms-transition: -ms-transform .2s ease-out;' + 'transition: transform .2s ease-out;' + '} ' + '.#= guid #.k-rpanel-top {' + 'overflow: hidden;' + '}' + '.#= guid #.k-rpanel-animate.k-rpanel-top {' + '-webkit-transition: max-height .2s linear;' + '-ms-transition: max-height .2s linear;' + 'transition: max-height .2s linear;' + '}' + '} ' + '@media (min-width: #= breakpoint #px) {' + '#= toggleButton # { display: none; } ' + '.#= guid #.k-rpanel-left { float: left; } ' + '.#= guid #.k-rpanel-right { float: right; } ' + '.#= guid #.k-rpanel-left, .#= guid #.k-rpanel-right {' + 'position: relative;' + '-webkit-transform: translateX(0);' + '-ms-transform: translateX(0);' + 'transform: translateX(0);' + '-webkit-transform: translateX(0) translateZ(0);' + '-ms-transform: translateX(0) translateZ(0);' + 'transform: translateX(0) translateZ(0);' + '} ' + '.k-ie9 .#= guid #.k-rpanel-left { left: 0; } ' + '.#= guid #.k-rpanel-top { max-height: none; }' + '}',
            _registerBreakpoint: function () {
                var options = this.options;
                this._registerStyle(kendo.template(this._mediaQuery)({
                    breakpoint: options.breakpoint,
                    toggleButton: options.toggleButton,
                    guid: this._guid
                }));
            },
            _registerStyle: function (cssText) {
                var head = $('head,body')[0];
                var style = document.createElement('style');
                head.appendChild(style);
                if (style.styleSheet) {
                    style.styleSheet.cssText = cssText;
                } else {
                    style.appendChild(document.createTextNode(cssText));
                }
            },
            options: {
                name: 'ResponsivePanel',
                orientation: 'left',
                toggleButton: '.k-rpanel-toggle',
                breakpoint: 640,
                autoClose: true
            },
            events: [
                OPEN,
                CLOSE
            ],
            _resize: function () {
                this.element.removeClass('k-rpanel-animate k-rpanel-expanded');
                $(document.documentElement).off(ACTIVATE_EVENTS, this._closeHandler);
            },
            _toggleButtonClick: function (e) {
                e.preventDefault();
                if (this.element.hasClass('k-rpanel-expanded')) {
                    this.close();
                } else {
                    this.open();
                }
            },
            open: function () {
                if (!this.trigger(OPEN)) {
                    this.element.addClass('k-rpanel-animate k-rpanel-expanded');
                    if (this.options.autoClose) {
                        $(document.documentElement).on(ACTIVATE_EVENTS, this._closeHandler);
                    }
                }
            },
            close: function () {
                if (!this.trigger(CLOSE)) {
                    this.element.addClass('k-rpanel-animate').removeClass('k-rpanel-expanded');
                    $(document.documentElement).off(ACTIVATE_EVENTS, this._closeHandler);
                }
            },
            _close: function (e) {
                var prevented = e.isDefaultPrevented();
                var container = $(e.target).closest(this.options.toggleButton + ',.k-rpanel');
                if (!container.length && !prevented) {
                    this.close();
                }
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                $(window).off('resize' + NS, this._resizeHandler);
                $(document.documentElement).off(ACTIVATE_EVENTS, this._closeHandler);
            }
        });
        kendo.ui.plugin(ResponsivePanel);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.timepicker', ['kendo.popup'], f);
}(function () {
    var __meta__ = {
        id: 'timepicker',
        name: 'TimePicker',
        category: 'web',
        description: 'The TimePicker widget allows the end user to select a value from a list of predefined values or to type a new value.',
        depends: ['popup']
    };
    (function ($, undefined) {
        var kendo = window.kendo, keys = kendo.keys, parse = kendo.parseDate, activeElement = kendo._activeElement, extractFormat = kendo._extractFormat, support = kendo.support, browser = support.browser, ui = kendo.ui, Widget = ui.Widget, OPEN = 'open', CLOSE = 'close', CHANGE = 'change', ns = '.kendoTimePicker', CLICK = 'click' + ns, DEFAULT = 'k-state-default', DISABLED = 'disabled', READONLY = 'readonly', LI = 'li', SPAN = '<span/>', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, MOUSEDOWN = 'mousedown' + ns, MS_PER_MINUTE = 60000, MS_PER_DAY = 86400000, SELECTED = 'k-state-selected', STATEDISABLED = 'k-state-disabled', ARIA_SELECTED = 'aria-selected', ARIA_EXPANDED = 'aria-expanded', ARIA_HIDDEN = 'aria-hidden', ARIA_DISABLED = 'aria-disabled', ARIA_ACTIVEDESCENDANT = 'aria-activedescendant', ID = 'id', isArray = $.isArray, extend = $.extend, proxy = $.proxy, DATE = Date, TODAY = new DATE();
        TODAY = new DATE(TODAY.getFullYear(), TODAY.getMonth(), TODAY.getDate(), 0, 0, 0);
        var TimeView = function (options) {
            var that = this, id = options.id;
            that.options = options;
            that._dates = [];
            that.ul = $('<ul tabindex="-1" role="listbox" aria-hidden="true" unselectable="on" class="k-list k-reset"/>').css({ overflow: support.kineticScrollNeeded ? '' : 'auto' }).on(CLICK, LI, proxy(that._click, that)).on('mouseenter' + ns, LI, function () {
                $(this).addClass(HOVER);
            }).on('mouseleave' + ns, LI, function () {
                $(this).removeClass(HOVER);
            });
            that.list = $('<div class=\'k-list-container k-list-scroller\' unselectable=\'on\'/>').append(that.ul).on(MOUSEDOWN, preventDefault);
            if (id) {
                that._timeViewID = id + '_timeview';
                that._optionID = id + '_option_selected';
                that.ul.attr(ID, that._timeViewID);
            }
            that._popup();
            that._heightHandler = proxy(that._height, that);
            that.template = kendo.template('<li tabindex="-1" role="option" class="k-item" unselectable="on">#=data#</li>', { useWithBlock: false });
        };
        TimeView.prototype = {
            current: function (candidate) {
                var that = this, active = that.options.active;
                if (candidate !== undefined) {
                    if (that._current) {
                        that._current.removeClass(SELECTED).removeAttr(ARIA_SELECTED).removeAttr(ID);
                    }
                    if (candidate) {
                        candidate = $(candidate).addClass(SELECTED).attr(ID, that._optionID).attr(ARIA_SELECTED, true);
                        that.scroll(candidate[0]);
                    }
                    that._current = candidate;
                    if (active) {
                        active(candidate);
                    }
                } else {
                    return that._current;
                }
            },
            close: function () {
                this.popup.close();
            },
            destroy: function () {
                var that = this;
                that.ul.off(ns);
                that.list.off(ns);
                that.popup.destroy();
            },
            open: function () {
                var that = this;
                if (!that.ul[0].firstChild) {
                    that.bind();
                }
                that.popup.open();
                if (that._current) {
                    that.scroll(that._current[0]);
                }
            },
            dataBind: function (dates) {
                var that = this, options = that.options, format = options.format, toString = kendo.toString, template = that.template, length = dates.length, idx = 0, date, html = '';
                for (; idx < length; idx++) {
                    date = dates[idx];
                    if (isInRange(date, options.min, options.max)) {
                        html += template(toString(date, format, options.culture));
                    }
                }
                that._html(html);
            },
            refresh: function () {
                var that = this, options = that.options, format = options.format, offset = dst(), ignoreDST = offset < 0, min = options.min, max = options.max, msMin = getMilliseconds(min), msMax = getMilliseconds(max), msInterval = options.interval * MS_PER_MINUTE, toString = kendo.toString, template = that.template, start = new DATE(+min), startDay = start.getDate(), msStart, lastIdx, idx = 0, length, html = '';
                if (ignoreDST) {
                    length = (MS_PER_DAY + offset * MS_PER_MINUTE) / msInterval;
                } else {
                    length = MS_PER_DAY / msInterval;
                }
                if (msMin != msMax) {
                    if (msMin > msMax) {
                        msMax += MS_PER_DAY;
                    }
                    length = (msMax - msMin) / msInterval + 1;
                }
                lastIdx = parseInt(length, 10);
                for (; idx < length; idx++) {
                    if (idx) {
                        setTime(start, msInterval, ignoreDST);
                    }
                    if (msMax && lastIdx == idx) {
                        msStart = getMilliseconds(start);
                        if (startDay < start.getDate()) {
                            msStart += MS_PER_DAY;
                        }
                        if (msStart > msMax) {
                            start = new DATE(+max);
                        }
                    }
                    that._dates.push(getMilliseconds(start));
                    html += template(toString(start, format, options.culture));
                }
                that._html(html);
            },
            bind: function () {
                var that = this, dates = that.options.dates;
                if (dates && dates[0]) {
                    that.dataBind(dates);
                } else {
                    that.refresh();
                }
            },
            _html: function (html) {
                var that = this;
                that.ul[0].innerHTML = html;
                that.popup.unbind(OPEN, that._heightHandler);
                that.popup.one(OPEN, that._heightHandler);
                that.current(null);
                that.select(that._value);
            },
            scroll: function (item) {
                if (!item) {
                    return;
                }
                var content = this.list[0], itemOffsetTop = item.offsetTop, itemOffsetHeight = item.offsetHeight, contentScrollTop = content.scrollTop, contentOffsetHeight = content.clientHeight, bottomDistance = itemOffsetTop + itemOffsetHeight;
                if (contentScrollTop > itemOffsetTop) {
                    contentScrollTop = itemOffsetTop;
                } else if (bottomDistance > contentScrollTop + contentOffsetHeight) {
                    contentScrollTop = bottomDistance - contentOffsetHeight;
                }
                content.scrollTop = contentScrollTop;
            },
            select: function (li) {
                var that = this, options = that.options, current = that._current, selection;
                if (li instanceof Date) {
                    li = kendo.toString(li, options.format, options.culture);
                }
                if (typeof li === 'string') {
                    if (!current || current.text() !== li) {
                        li = $.grep(that.ul[0].childNodes, function (node) {
                            return (node.textContent || node.innerText) == li;
                        });
                        li = li[0] ? li : null;
                    } else {
                        li = current;
                    }
                }
                selection = that._distinctSelection(li);
                that.current(selection);
            },
            _distinctSelection: function (selection) {
                var that = this, currentValue, selectionIndex;
                if (selection && selection.length > 1) {
                    currentValue = getMilliseconds(that._value);
                    selectionIndex = $.inArray(currentValue, that._dates);
                    selection = that.ul.children()[selectionIndex];
                }
                return selection;
            },
            setOptions: function (options) {
                var old = this.options;
                options.min = parse(options.min);
                options.max = parse(options.max);
                this.options = extend(old, options, {
                    active: old.active,
                    change: old.change,
                    close: old.close,
                    open: old.open
                });
                this.bind();
            },
            toggle: function () {
                var that = this;
                if (that.popup.visible()) {
                    that.close();
                } else {
                    that.open();
                }
            },
            value: function (value) {
                var that = this;
                that._value = value;
                if (that.ul[0].firstChild) {
                    that.select(value);
                }
            },
            _click: function (e) {
                var that = this, li = $(e.currentTarget), date = li.text(), dates = that.options.dates;
                if (dates && dates.length > 0) {
                    date = dates[li.index()];
                }
                if (!e.isDefaultPrevented()) {
                    that.select(li);
                    that.options.change(date, true);
                    that.close();
                }
            },
            _height: function () {
                var that = this;
                var list = that.list;
                var parent = list.parent('.k-animation-container');
                var height = that.options.height;
                if (that.ul[0].children.length) {
                    list.add(parent).show().height(that.ul[0].scrollHeight > height ? height : 'auto').hide();
                }
            },
            _parse: function (value) {
                var that = this, options = that.options, current = that._value || TODAY;
                if (value instanceof DATE) {
                    return value;
                }
                value = parse(value, options.parseFormats, options.culture);
                if (value) {
                    value = new DATE(current.getFullYear(), current.getMonth(), current.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), value.getMilliseconds());
                }
                return value;
            },
            _adjustListWidth: function () {
                var list = this.list, width = list[0].style.width, wrapper = this.options.anchor, computedStyle, computedWidth, outerWidth = kendo._outerWidth;
                if (!list.data('width') && width) {
                    return;
                }
                computedStyle = window.getComputedStyle ? window.getComputedStyle(wrapper[0], null) : 0;
                computedWidth = computedStyle ? parseFloat(computedStyle.width) : outerWidth(wrapper);
                if (computedStyle && (browser.mozilla || browser.msie)) {
                    computedWidth += parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
                }
                width = computedWidth - (outerWidth(list) - list.width());
                list.css({
                    fontFamily: wrapper.css('font-family'),
                    width: width
                }).data('width', width);
            },
            _popup: function () {
                var that = this, list = that.list, options = that.options, anchor = options.anchor;
                that.popup = new ui.Popup(list, extend(options.popup, {
                    anchor: anchor,
                    open: options.open,
                    close: options.close,
                    animation: options.animation,
                    isRtl: support.isRtl(options.anchor)
                }));
            },
            move: function (e) {
                var that = this, key = e.keyCode, ul = that.ul[0], current = that._current, down = key === keys.DOWN;
                if (key === keys.UP || down) {
                    if (e.altKey) {
                        that.toggle(down);
                        return;
                    } else if (down) {
                        current = current ? current[0].nextSibling : ul.firstChild;
                    } else {
                        current = current ? current[0].previousSibling : ul.lastChild;
                    }
                    if (current) {
                        that.select(current);
                    }
                    that.options.change(that._current.text());
                    e.preventDefault();
                } else if (key === keys.ENTER || key === keys.TAB || key === keys.ESC) {
                    e.preventDefault();
                    if (current) {
                        that.options.change(current.text(), true);
                    }
                    that.close();
                }
            }
        };
        function setTime(date, time, ignoreDST) {
            var offset = date.getTimezoneOffset(), offsetDiff;
            date.setTime(date.getTime() + time);
            if (!ignoreDST) {
                offsetDiff = date.getTimezoneOffset() - offset;
                date.setTime(date.getTime() + offsetDiff * MS_PER_MINUTE);
            }
        }
        function dst() {
            var today = new DATE(), midnight = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0), noon = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), 12, 0, 0);
            return -1 * (midnight.getTimezoneOffset() - noon.getTimezoneOffset());
        }
        function getMilliseconds(date) {
            return date.getHours() * 60 * MS_PER_MINUTE + date.getMinutes() * MS_PER_MINUTE + date.getSeconds() * 1000 + date.getMilliseconds();
        }
        function isInRange(value, min, max) {
            var msMin = getMilliseconds(min), msMax = getMilliseconds(max), msValue;
            if (!value || msMin == msMax) {
                return true;
            }
            msValue = getMilliseconds(value);
            if (msMin > msValue) {
                msValue += MS_PER_DAY;
            }
            if (msMax < msMin) {
                msMax += MS_PER_DAY;
            }
            return msValue >= msMin && msValue <= msMax;
        }
        TimeView.getMilliseconds = getMilliseconds;
        kendo.TimeView = TimeView;
        var TimePicker = Widget.extend({
            init: function (element, options) {
                var that = this, ul, timeView, disabled;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.min = parse(element.attr('min')) || parse(options.min);
                options.max = parse(element.attr('max')) || parse(options.max);
                normalize(options);
                that._initialOptions = extend({}, options);
                that._wrapper();
                that.timeView = timeView = new TimeView(extend({}, options, {
                    id: element.attr(ID),
                    anchor: that.wrapper,
                    format: options.format,
                    change: function (value, trigger) {
                        if (trigger) {
                            that._change(value);
                        } else {
                            element.val(value);
                        }
                    },
                    open: function (e) {
                        that.timeView._adjustListWidth();
                        if (that.trigger(OPEN)) {
                            e.preventDefault();
                        } else {
                            element.attr(ARIA_EXPANDED, true);
                            ul.attr(ARIA_HIDDEN, false);
                        }
                    },
                    close: function (e) {
                        if (that.trigger(CLOSE)) {
                            e.preventDefault();
                        } else {
                            element.attr(ARIA_EXPANDED, false);
                            ul.attr(ARIA_HIDDEN, true);
                        }
                    },
                    active: function (current) {
                        element.removeAttr(ARIA_ACTIVEDESCENDANT);
                        if (current) {
                            element.attr(ARIA_ACTIVEDESCENDANT, timeView._optionID);
                        }
                    }
                }));
                ul = timeView.ul;
                that._icon();
                that._reset();
                try {
                    element[0].setAttribute('type', 'text');
                } catch (e) {
                    element[0].type = 'text';
                }
                element.addClass('k-input').attr({
                    'role': 'combobox',
                    'aria-expanded': false,
                    'aria-owns': timeView._timeViewID
                });
                disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                if (options.dateInput) {
                    that._dateInput = new ui.DateInput(element, {
                        culture: options.culture,
                        format: options.format,
                        min: options.min,
                        max: options.max,
                        value: options.value
                    });
                }
                that._old = that._update(options.value || that.element.val());
                that._oldText = element.val();
                kendo.notify(that);
            },
            options: {
                name: 'TimePicker',
                min: TODAY,
                max: TODAY,
                format: '',
                dates: [],
                parseFormats: [],
                value: null,
                interval: 30,
                height: 200,
                animation: {}
            },
            events: [
                OPEN,
                CLOSE,
                CHANGE
            ],
            setOptions: function (options) {
                var that = this;
                var value = that._value;
                Widget.fn.setOptions.call(that, options);
                options = that.options;
                normalize(options);
                that.timeView.setOptions(options);
                if (value) {
                    that.element.val(kendo.toString(value, options.format, options.culture));
                }
            },
            dataBind: function (dates) {
                if (isArray(dates)) {
                    this.timeView.dataBind(dates);
                }
            },
            _editable: function (options) {
                var that = this, disable = options.disable, readonly = options.readonly, arrow = that._arrow.off(ns), element = that.element.off(ns), wrapper = that._inputWrapper.off(ns);
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    element.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false).on('keydown' + ns, proxy(that._keydown, that)).on('focusout' + ns, proxy(that._blur, that)).on('focus' + ns, function () {
                        that._inputWrapper.addClass(FOCUSED);
                    });
                    arrow.on(CLICK, proxy(that._click, that)).on(MOUSEDOWN, preventDefault);
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    element.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.timeView.destroy();
                that.element.off(ns);
                that._arrow.off(ns);
                that._inputWrapper.off(ns);
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
            },
            close: function () {
                this.timeView.close();
            },
            open: function () {
                this.timeView.open();
            },
            min: function (value) {
                return this._option('min', value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            value: function (value) {
                var that = this;
                if (value === undefined) {
                    return that._value;
                }
                that._old = that._update(value);
                if (that._old === null) {
                    that.element.val('');
                }
                that._oldText = that.element.val();
            },
            _blur: function () {
                var that = this, value = that.element.val();
                that.close();
                if (value !== that._oldText) {
                    that._change(value);
                }
                that._inputWrapper.removeClass(FOCUSED);
            },
            _click: function () {
                var that = this, element = that.element;
                that.timeView.toggle();
                if (!support.touch && element[0] !== activeElement()) {
                    element.focus();
                }
            },
            _change: function (value) {
                var that = this;
                value = that._update(value);
                if (+that._old != +value) {
                    that._old = value;
                    that._oldText = that.element.val();
                    if (!that._typing) {
                        that.element.trigger(CHANGE);
                    }
                    that.trigger(CHANGE);
                }
                that._typing = false;
            },
            _icon: function () {
                var that = this, element = that.element, arrow;
                arrow = element.next('span.k-select');
                if (!arrow[0]) {
                    arrow = $('<span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-clock"></span></span>').insertAfter(element);
                }
                that._arrow = arrow.attr({
                    'role': 'button',
                    'aria-controls': that.timeView._timeViewID
                });
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, timeView = that.timeView, value = that.element.val();
                if (timeView.popup.visible() || e.altKey) {
                    timeView.move(e);
                    if (that._dateInput && e.stopImmediatePropagation) {
                        e.stopImmediatePropagation();
                    }
                } else if (key === keys.ENTER && value !== that._oldText) {
                    that._change(value);
                } else {
                    that._typing = true;
                }
            },
            _option: function (option, value) {
                var that = this, options = that.options;
                if (value === undefined) {
                    return options[option];
                }
                value = that.timeView._parse(value);
                if (!value) {
                    return;
                }
                value = new DATE(+value);
                options[option] = value;
                that.timeView.options[option] = value;
                that.timeView.bind();
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _update: function (value) {
                var that = this, options = that.options, timeView = that.timeView, date = timeView._parse(value);
                if (!isInRange(date, options.min, options.max)) {
                    date = null;
                }
                that._value = date;
                if (that._dateInput) {
                    that._dateInput.value(date || value);
                } else {
                    that.element.val(kendo.toString(date || value, options.format, options.culture));
                }
                timeView.value(date);
                return date;
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper;
                wrapper = element.parents('.k-timepicker');
                if (!wrapper[0]) {
                    wrapper = element.wrap(SPAN).parent().addClass('k-picker-wrap k-state-default');
                    wrapper = wrapper.wrap(SPAN).parent();
                }
                wrapper[0].style.cssText = element[0].style.cssText;
                that.wrapper = wrapper.addClass('k-widget k-timepicker k-header').addClass(element[0].className);
                element.css({
                    width: '100%',
                    height: element[0].style.height
                });
                that._inputWrapper = $(wrapper[0].firstChild);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        that.value(element[0].defaultValue);
                        that.max(that._initialOptions.max);
                        that.min(that._initialOptions.min);
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            }
        });
        function normalize(options) {
            var parseFormats = options.parseFormats;
            options.format = extractFormat(options.format || kendo.getCulture(options.culture).calendars.standard.patterns.t);
            parseFormats = isArray(parseFormats) ? parseFormats : [parseFormats];
            parseFormats.splice(0, 0, options.format);
            options.parseFormats = parseFormats;
        }
        function preventDefault(e) {
            e.preventDefault();
        }
        ui.plugin(TimePicker);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.datetimepicker', [
        'kendo.datepicker',
        'kendo.timepicker'
    ], f);
}(function () {
    var __meta__ = {
        id: 'datetimepicker',
        name: 'DateTimePicker',
        category: 'web',
        description: 'The DateTimePicker allows the end user to select a value from a calendar or a time drop-down list.',
        depends: [
            'datepicker',
            'timepicker'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, TimeView = kendo.TimeView, parse = kendo.parseDate, activeElement = kendo._activeElement, extractFormat = kendo._extractFormat, calendar = kendo.calendar, isInRange = calendar.isInRange, restrictValue = calendar.restrictValue, isEqualDatePart = calendar.isEqualDatePart, getMilliseconds = TimeView.getMilliseconds, ui = kendo.ui, Widget = ui.Widget, OPEN = 'open', CLOSE = 'close', CHANGE = 'change', ns = '.kendoDateTimePicker', CLICK = 'click' + ns, DISABLED = 'disabled', READONLY = 'readonly', DEFAULT = 'k-state-default', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', STATEDISABLED = 'k-state-disabled', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, MOUSEDOWN = 'mousedown' + ns, MONTH = 'month', SPAN = '<span/>', ARIA_ACTIVEDESCENDANT = 'aria-activedescendant', ARIA_EXPANDED = 'aria-expanded', ARIA_HIDDEN = 'aria-hidden', ARIA_OWNS = 'aria-owns', ARIA_DISABLED = 'aria-disabled', DATE = Date, MIN = new DATE(1800, 0, 1), MAX = new DATE(2099, 11, 31), dateViewParams = { view: 'date' }, timeViewParams = { view: 'time' }, extend = $.extend;
        var DateTimePicker = Widget.extend({
            init: function (element, options) {
                var that = this, disabled;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                options = that.options;
                options.disableDates = kendo.calendar.disabled(options.disableDates);
                options.min = parse(element.attr('min')) || parse(options.min);
                options.max = parse(element.attr('max')) || parse(options.max);
                normalize(options);
                that._initialOptions = extend({}, options);
                that._wrapper();
                that._views();
                that._icons();
                that._reset();
                that._template();
                try {
                    element[0].setAttribute('type', 'text');
                } catch (e) {
                    element[0].type = 'text';
                }
                element.addClass('k-input').attr({
                    'role': 'combobox',
                    'aria-expanded': false
                });
                that._midnight = that._calculateMidnight(options.min, options.max);
                disabled = element.is('[disabled]') || $(that.element).parents('fieldset').is(':disabled');
                if (disabled) {
                    that.enable(false);
                } else {
                    that.readonly(element.is('[readonly]'));
                }
                if (options.dateInput) {
                    that._dateInput = new ui.DateInput(element, {
                        culture: options.culture,
                        format: options.format,
                        min: options.min,
                        max: options.max,
                        value: options.value
                    });
                }
                that._old = that._update(options.value || that.element.val());
                that._oldText = element.val();
                kendo.notify(that);
            },
            options: {
                name: 'DateTimePicker',
                value: null,
                format: '',
                timeFormat: '',
                culture: '',
                parseFormats: [],
                dates: [],
                min: new DATE(MIN),
                max: new DATE(MAX),
                interval: 30,
                height: 200,
                footer: '',
                start: MONTH,
                depth: MONTH,
                animation: {},
                month: {},
                ARIATemplate: 'Current focused date is #=kendo.toString(data.current, "d")#',
                dateButtonText: 'Open the date view',
                timeButtonText: 'Open the time view'
            },
            events: [
                OPEN,
                CLOSE,
                CHANGE
            ],
            setOptions: function (options) {
                var that = this, value = that._value, min, max, currentValue;
                Widget.fn.setOptions.call(that, options);
                options = that.options;
                options.min = min = parse(options.min);
                options.max = max = parse(options.max);
                normalize(options);
                that._midnight = that._calculateMidnight(options.min, options.max);
                currentValue = options.value || that._value || that.dateView._current;
                if (min && !isEqualDatePart(min, currentValue)) {
                    min = new DATE(MIN);
                }
                if (max && !isEqualDatePart(max, currentValue)) {
                    max = new DATE(MAX);
                }
                that.dateView.setOptions(options);
                that.timeView.setOptions(extend({}, options, {
                    format: options.timeFormat,
                    min: min,
                    max: max
                }));
                if (value) {
                    that.element.val(kendo.toString(value, options.format, options.culture));
                    that._updateARIA(value);
                }
            },
            _editable: function (options) {
                var that = this, element = that.element.off(ns), dateIcon = that._dateIcon.off(ns), timeIcon = that._timeIcon.off(ns), wrapper = that._inputWrapper.off(ns), readonly = options.readonly, disable = options.disable;
                if (!readonly && !disable) {
                    wrapper.addClass(DEFAULT).removeClass(STATEDISABLED).on(HOVEREVENTS, that._toggleHover);
                    element.removeAttr(DISABLED).removeAttr(READONLY).attr(ARIA_DISABLED, false).on('keydown' + ns, $.proxy(that._keydown, that)).on('focus' + ns, function () {
                        that._inputWrapper.addClass(FOCUSED);
                    }).on('focusout' + ns, function () {
                        that._inputWrapper.removeClass(FOCUSED);
                        if (element.val() !== that._oldText) {
                            that._change(element.val());
                        }
                        that.close('date');
                        that.close('time');
                    });
                    dateIcon.on(MOUSEDOWN, preventDefault).on(CLICK, function () {
                        that.toggle('date');
                        if (!kendo.support.touch && element[0] !== activeElement()) {
                            element.focus();
                        }
                    });
                    timeIcon.on(MOUSEDOWN, preventDefault).on(CLICK, function () {
                        that.toggle('time');
                        if (!kendo.support.touch && element[0] !== activeElement()) {
                            element.focus();
                        }
                    });
                } else {
                    wrapper.addClass(disable ? STATEDISABLED : DEFAULT).removeClass(disable ? DEFAULT : STATEDISABLED);
                    element.attr(DISABLED, disable).attr(READONLY, readonly).attr(ARIA_DISABLED, disable);
                }
            },
            readonly: function (readonly) {
                this._editable({
                    readonly: readonly === undefined ? true : readonly,
                    disable: false
                });
            },
            enable: function (enable) {
                this._editable({
                    readonly: false,
                    disable: !(enable = enable === undefined ? true : enable)
                });
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                that.dateView.destroy();
                that.timeView.destroy();
                that.element.off(ns);
                that._dateIcon.off(ns);
                that._timeIcon.off(ns);
                that._inputWrapper.off(ns);
                if (that._form) {
                    that._form.off('reset', that._resetHandler);
                }
            },
            close: function (view) {
                if (view !== 'time') {
                    view = 'date';
                }
                this[view + 'View'].close();
            },
            open: function (view) {
                if (view !== 'time') {
                    view = 'date';
                }
                this[view + 'View'].open();
            },
            min: function (value) {
                return this._option('min', value);
            },
            max: function (value) {
                return this._option('max', value);
            },
            toggle: function (view) {
                var secondView = 'timeView';
                if (view !== 'time') {
                    view = 'date';
                } else {
                    secondView = 'dateView';
                }
                this[view + 'View'].toggle();
                this[secondView].close();
            },
            value: function (value) {
                var that = this;
                if (value === undefined) {
                    return that._value;
                }
                that._old = that._update(value);
                if (that._old === null) {
                    that.element.val('');
                }
                that._oldText = that.element.val();
            },
            _change: function (value) {
                var that = this, oldValue = that.element.val(), dateChanged;
                value = that._update(value);
                dateChanged = +that._old != +value;
                var valueUpdated = dateChanged && !that._typing;
                var textFormatted = oldValue !== that.element.val();
                if (valueUpdated || textFormatted) {
                    that.element.trigger(CHANGE);
                }
                if (dateChanged) {
                    that._old = value;
                    that._oldText = that.element.val();
                    that.trigger(CHANGE);
                }
                that._typing = false;
            },
            _option: function (option, value) {
                var that = this;
                var options = that.options;
                var timeView = that.timeView;
                var timeViewOptions = timeView.options;
                var current = that._value || that._old;
                var minDateEqual;
                var maxDateEqual;
                if (value === undefined) {
                    return options[option];
                }
                value = parse(value, options.parseFormats, options.culture);
                if (!value) {
                    return;
                }
                if (options.min.getTime() === options.max.getTime()) {
                    timeViewOptions.dates = [];
                }
                options[option] = new DATE(value.getTime());
                that.dateView[option](value);
                that._midnight = that._calculateMidnight(options.min, options.max);
                if (current) {
                    minDateEqual = isEqualDatePart(options.min, current);
                    maxDateEqual = isEqualDatePart(options.max, current);
                }
                if (minDateEqual || maxDateEqual) {
                    timeViewOptions[option] = value;
                    if (minDateEqual && !maxDateEqual) {
                        timeViewOptions.max = lastTimeOption(options.interval);
                    }
                    if (maxDateEqual) {
                        if (that._midnight) {
                            timeView.dataBind([MAX]);
                            return;
                        } else if (!minDateEqual) {
                            timeViewOptions.min = MIN;
                        }
                    }
                } else {
                    timeViewOptions.max = MAX;
                    timeViewOptions.min = MIN;
                }
                timeView.bind();
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _update: function (value) {
                var that = this, options = that.options, min = options.min, max = options.max, dates = options.dates, timeView = that.timeView, current = that._value, date = parse(value, options.parseFormats, options.culture), isSameType = date === null && current === null || date instanceof Date && current instanceof Date, rebind, timeViewOptions, old, skip, formattedValue;
                if (options.disableDates && options.disableDates(date)) {
                    date = null;
                    if (!that._old && !that.element.val()) {
                        value = null;
                    }
                }
                if (+date === +current && isSameType) {
                    formattedValue = kendo.toString(date, options.format, options.culture);
                    if (formattedValue !== value) {
                        that.element.val(date === null ? value : formattedValue);
                        if (value instanceof String) {
                            that.element.trigger(CHANGE);
                        }
                    }
                    return date;
                }
                if (date !== null && isEqualDatePart(date, min)) {
                    date = restrictValue(date, min, max);
                } else if (!isInRange(date, min, max)) {
                    date = null;
                }
                that._value = date;
                timeView.value(date);
                that.dateView.value(date);
                if (date) {
                    old = that._old;
                    timeViewOptions = timeView.options;
                    if (dates[0]) {
                        dates = $.grep(dates, function (d) {
                            return isEqualDatePart(date, d);
                        });
                        if (dates[0]) {
                            timeView.dataBind(dates);
                            skip = true;
                        }
                    }
                    if (!skip) {
                        if (isEqualDatePart(date, min)) {
                            timeViewOptions.min = min;
                            timeViewOptions.max = lastTimeOption(options.interval);
                            rebind = true;
                        }
                        if (isEqualDatePart(date, max)) {
                            if (that._midnight) {
                                timeView.dataBind([MAX]);
                                skip = true;
                            } else {
                                timeViewOptions.max = max;
                                if (!rebind) {
                                    timeViewOptions.min = MIN;
                                }
                                rebind = true;
                            }
                        }
                    }
                    if (!skip && (!old && rebind || old && !isEqualDatePart(old, date))) {
                        if (!rebind) {
                            timeViewOptions.max = MAX;
                            timeViewOptions.min = MIN;
                        }
                        timeView.bind();
                    }
                }
                if (that._dateInput) {
                    that._dateInput.value(date || value);
                } else {
                    that.element.val(kendo.toString(date || value, options.format, options.culture));
                }
                that._updateARIA(date);
                return date;
            },
            _keydown: function (e) {
                var that = this, dateView = that.dateView, timeView = that.timeView, value = that.element.val(), isDateViewVisible = dateView.popup.visible();
                var stopPropagation = that._dateInput && e.stopImmediatePropagation;
                if (e.altKey && e.keyCode === kendo.keys.DOWN) {
                    that.toggle(isDateViewVisible ? 'time' : 'date');
                } else if (isDateViewVisible) {
                    dateView.move(e);
                    that._updateARIA(dateView._current);
                } else if (timeView.popup.visible()) {
                    timeView.move(e);
                } else if (e.keyCode === kendo.keys.ENTER && value !== that._oldText) {
                    that._change(value);
                } else {
                    that._typing = true;
                    stopPropagation = false;
                }
                if (stopPropagation) {
                    e.stopImmediatePropagation();
                }
            },
            _views: function () {
                var that = this, element = that.element, options = that.options, id = element.attr('id'), dateView, timeView, div, ul, msMin, date;
                that.dateView = dateView = new kendo.DateView(extend({}, options, {
                    id: id,
                    anchor: that.wrapper,
                    change: function () {
                        var value = dateView.calendar.value(), msValue = +value, msMin = +options.min, msMax = +options.max, current, adjustedDate;
                        if (msValue === msMin || msValue === msMax) {
                            current = msValue === msMin ? msMin : msMax;
                            current = new DATE(that._value || current);
                            current.setFullYear(value.getFullYear(), value.getMonth(), value.getDate());
                            if (isInRange(current, msMin, msMax)) {
                                value = current;
                            }
                        }
                        if (that._value) {
                            adjustedDate = kendo.date.setHours(new Date(value), that._value);
                            if (isInRange(adjustedDate, msMin, msMax)) {
                                value = adjustedDate;
                            }
                        }
                        that._change(value);
                        that.close('date');
                    },
                    close: function (e) {
                        if (that.trigger(CLOSE, dateViewParams)) {
                            e.preventDefault();
                        } else {
                            element.attr(ARIA_EXPANDED, false);
                            div.attr(ARIA_HIDDEN, true);
                            if (!timeView.popup.visible()) {
                                element.removeAttr(ARIA_OWNS);
                            }
                        }
                    },
                    open: function (e) {
                        if (that.trigger(OPEN, dateViewParams)) {
                            e.preventDefault();
                        } else {
                            if (element.val() !== that._oldText) {
                                date = parse(element.val(), options.parseFormats, options.culture);
                                that.dateView[date ? 'current' : 'value'](date);
                            }
                            div.attr(ARIA_HIDDEN, false);
                            element.attr(ARIA_EXPANDED, true).attr(ARIA_OWNS, dateView._dateViewID);
                            that._updateARIA(date);
                        }
                    }
                }));
                div = dateView.div;
                msMin = options.min.getTime();
                that.timeView = timeView = new TimeView({
                    id: id,
                    value: options.value,
                    anchor: that.wrapper,
                    animation: options.animation,
                    format: options.timeFormat,
                    culture: options.culture,
                    height: options.height,
                    interval: options.interval,
                    min: new DATE(MIN),
                    max: new DATE(MAX),
                    dates: msMin === options.max.getTime() ? [new Date(msMin)] : [],
                    parseFormats: options.parseFormats,
                    change: function (value, trigger) {
                        value = timeView._parse(value);
                        if (value < options.min) {
                            value = new DATE(+options.min);
                            timeView.options.min = value;
                        } else if (value > options.max) {
                            value = new DATE(+options.max);
                            timeView.options.max = value;
                        }
                        if (trigger) {
                            that._timeSelected = true;
                            that._change(value);
                        } else {
                            element.val(kendo.toString(value, options.format, options.culture));
                            dateView.value(value);
                            that._updateARIA(value);
                        }
                    },
                    close: function (e) {
                        if (that.trigger(CLOSE, timeViewParams)) {
                            e.preventDefault();
                        } else {
                            ul.attr(ARIA_HIDDEN, true);
                            element.attr(ARIA_EXPANDED, false);
                            if (!dateView.popup.visible()) {
                                element.removeAttr(ARIA_OWNS);
                            }
                        }
                    },
                    open: function (e) {
                        timeView._adjustListWidth();
                        if (that.trigger(OPEN, timeViewParams)) {
                            e.preventDefault();
                        } else {
                            if (element.val() !== that._oldText) {
                                date = parse(element.val(), options.parseFormats, options.culture);
                                that.timeView.value(date);
                            }
                            ul.attr(ARIA_HIDDEN, false);
                            element.attr(ARIA_EXPANDED, true).attr(ARIA_OWNS, timeView._timeViewID);
                            timeView.options.active(timeView.current());
                        }
                    },
                    active: function (current) {
                        element.removeAttr(ARIA_ACTIVEDESCENDANT);
                        if (current) {
                            element.attr(ARIA_ACTIVEDESCENDANT, timeView._optionID);
                        }
                    }
                });
                ul = timeView.ul;
            },
            _icons: function () {
                var that = this;
                var element = that.element;
                var options = that.options;
                var icons;
                icons = element.next('span.k-select');
                if (!icons[0]) {
                    icons = $('<span unselectable="on" class="k-select">' + '<span class="k-link k-link-date" aria-label="' + options.dateButtonText + '"><span unselectable="on" class="k-icon k-i-calendar"></span></span>' + '<span class="k-link k-link-time" aria-label="' + options.timeButtonText + '"><span unselectable="on" class="k-icon k-i-clock"></span></span>' + '</span>').insertAfter(element);
                }
                icons = icons.children();
                icons = icons.children();
                that._dateIcon = icons.eq(0).attr('aria-controls', that.dateView._dateViewID);
                that._timeIcon = icons.eq(1).attr('aria-controls', that.timeView._timeViewID);
            },
            _wrapper: function () {
                var that = this, element = that.element, wrapper;
                wrapper = element.parents('.k-datetimepicker');
                if (!wrapper[0]) {
                    wrapper = element.wrap(SPAN).parent().addClass('k-picker-wrap k-state-default');
                    wrapper = wrapper.wrap(SPAN).parent();
                }
                wrapper[0].style.cssText = element[0].style.cssText;
                element.css({
                    width: '100%',
                    height: element[0].style.height
                });
                that.wrapper = wrapper.addClass('k-widget k-datetimepicker k-header').addClass(element[0].className);
                that._inputWrapper = $(wrapper[0].firstChild);
            },
            _reset: function () {
                var that = this, element = that.element, formId = element.attr('form'), form = formId ? $('#' + formId) : element.closest('form');
                if (form[0]) {
                    that._resetHandler = function () {
                        that.value(element[0].defaultValue);
                        that.max(that._initialOptions.max);
                        that.min(that._initialOptions.min);
                    };
                    that._form = form.on('reset', that._resetHandler);
                }
            },
            _template: function () {
                this._ariaTemplate = kendo.template(this.options.ARIATemplate);
            },
            _calculateMidnight: function (min, max) {
                return getMilliseconds(min) + getMilliseconds(max) === 0;
            },
            _updateARIA: function (date) {
                var cell;
                var that = this;
                var calendar = that.dateView.calendar;
                that.element.removeAttr(ARIA_ACTIVEDESCENDANT);
                if (calendar) {
                    cell = calendar._cell;
                    cell.attr('aria-label', that._ariaTemplate({ current: date || calendar.current() }));
                    that.element.attr(ARIA_ACTIVEDESCENDANT, cell.attr('id'));
                }
            }
        });
        function lastTimeOption(interval) {
            var date = new Date(2100, 0, 1);
            date.setMinutes(-interval);
            return date;
        }
        function preventDefault(e) {
            e.preventDefault();
        }
        function normalize(options) {
            var patterns = kendo.getCulture(options.culture).calendars.standard.patterns, parseFormats = !options.parseFormats.length, timeFormat;
            options.format = extractFormat(options.format || patterns.g);
            options.timeFormat = timeFormat = extractFormat(options.timeFormat || patterns.t);
            kendo.DateView.normalize(options);
            if (parseFormats) {
                options.parseFormats.unshift('yyyy-MM-ddTHH:mm:ss');
            }
            if ($.inArray(timeFormat, options.parseFormats) === -1) {
                options.parseFormats.push(timeFormat);
            }
        }
        ui.plugin(DateTimePicker);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.splitter', ['kendo.resizable'], f);
}(function () {
    var __meta__ = {
        id: 'splitter',
        name: 'Splitter',
        category: 'web',
        description: 'The Splitter widget provides an easy way to create a dynamic layout of resizable and collapsible panes.',
        depends: ['resizable']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, keys = kendo.keys, extend = $.extend, proxy = $.proxy, Widget = ui.Widget, pxUnitsRegex = /^\d+(\.\d+)?px$/i, percentageUnitsRegex = /^\d+(\.\d+)?%$/i, NS = '.kendoSplitter', EXPAND = 'expand', COLLAPSE = 'collapse', CONTENTLOAD = 'contentLoad', ERROR = 'error', RESIZE = 'resize', LAYOUTCHANGE = 'layoutChange', HORIZONTAL = 'horizontal', VERTICAL = 'vertical', MOUSEENTER = 'mouseenter', CLICK = 'click', PANE = 'pane', MOUSELEAVE = 'mouseleave', FOCUSED = 'k-state-focused', KPANE = 'k-' + PANE, PANECLASS = '.' + KPANE;
        function isPercentageSize(size) {
            return percentageUnitsRegex.test(size);
        }
        function isPixelSize(size) {
            return pxUnitsRegex.test(size) || /^\d+$/.test(size);
        }
        function isFluid(size) {
            return !isPercentageSize(size) && !isPixelSize(size);
        }
        function calculateSize(size, total) {
            var output = parseInt(size, 10);
            if (isPercentageSize(size)) {
                output = Math.floor(output * total / 100);
            }
            return output;
        }
        function panePropertyAccessor(propertyName, triggersResize) {
            return function (pane, value) {
                var paneConfig = this.element.find(pane).data(PANE);
                if (arguments.length == 1) {
                    return paneConfig[propertyName];
                }
                paneConfig[propertyName] = value;
                if (triggersResize) {
                    var splitter = this.element.data('kendo' + this.options.name);
                    splitter.resize(true);
                }
            };
        }
        var Splitter = Widget.extend({
            init: function (element, options) {
                var that = this, isHorizontal;
                Widget.fn.init.call(that, element, options);
                that.wrapper = that.element;
                isHorizontal = that.options.orientation.toLowerCase() != VERTICAL;
                that.orientation = isHorizontal ? HORIZONTAL : VERTICAL;
                that._dimension = isHorizontal ? 'width' : 'height';
                that._keys = {
                    decrease: isHorizontal ? keys.LEFT : keys.UP,
                    increase: isHorizontal ? keys.RIGHT : keys.DOWN
                };
                that._resizeStep = 10;
                that._marker = kendo.guid().substring(0, 8);
                that._initPanes();
                that.resizing = new PaneResizing(that);
                that.element.triggerHandler('init' + NS);
            },
            events: [
                EXPAND,
                COLLAPSE,
                CONTENTLOAD,
                ERROR,
                RESIZE,
                LAYOUTCHANGE
            ],
            _addOverlays: function () {
                this._panes().append('<div class=\'k-splitter-overlay k-overlay\' />');
            },
            _removeOverlays: function () {
                this._panes().children('.k-splitter-overlay').remove();
            },
            _attachEvents: function () {
                var that = this, orientation = that.options.orientation;
                that.element.children('.k-splitbar-draggable-' + orientation).on('keydown' + NS, proxy(that._keydown, that)).on('mousedown' + NS, function (e) {
                    e.currentTarget.focus();
                }).on('focus' + NS, function (e) {
                    $(e.currentTarget).addClass(FOCUSED);
                }).on('blur' + NS, function (e) {
                    $(e.currentTarget).removeClass(FOCUSED);
                    if (that.resizing) {
                        that.resizing.end();
                    }
                }).on(MOUSEENTER + NS, function () {
                    $(this).addClass('k-splitbar-' + that.orientation + '-hover');
                }).on(MOUSELEAVE + NS, function () {
                    $(this).removeClass('k-splitbar-' + that.orientation + '-hover');
                }).on('mousedown' + NS, proxy(that._addOverlays, that)).end().children('.k-splitbar').on('dblclick' + NS, proxy(that._togglePane, that)).children('.k-collapse-next, .k-collapse-prev').on(CLICK + NS, that._arrowClick(COLLAPSE)).end().children('.k-expand-next, .k-expand-prev').on(CLICK + NS, that._arrowClick(EXPAND)).end().end();
                $(window).on('resize' + NS + that._marker, proxy(that.resize, that, false));
                $(document).on('mouseup' + NS + that._marker, proxy(that._removeOverlays, that));
            },
            _detachEvents: function () {
                var that = this;
                that.element.children('.k-splitbar-draggable-' + that.orientation).off(NS).end().children('.k-splitbar').off('dblclick' + NS).children('.k-collapse-next, .k-collapse-prev, .k-expand-next, .k-expand-prev').off(NS);
                $(window).off(NS + that._marker);
                $(document).off(NS + that._marker);
            },
            options: {
                name: 'Splitter',
                orientation: HORIZONTAL,
                panes: []
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this._detachEvents();
                if (this.resizing) {
                    this.resizing.destroy();
                }
                kendo.destroy(this.element);
                this.wrapper = this.element = null;
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, resizing = that.resizing, target = $(e.currentTarget), navigationKeys = that._keys, increase = key === navigationKeys.increase, decrease = key === navigationKeys.decrease, pane;
                if (increase || decrease) {
                    if (e.ctrlKey) {
                        pane = target[decrease ? 'next' : 'prev']();
                        if (resizing && resizing.isResizing()) {
                            resizing.end();
                        }
                        if (!pane[that._dimension]()) {
                            that._triggerAction(EXPAND, pane);
                        } else {
                            that._triggerAction(COLLAPSE, target[decrease ? 'prev' : 'next']());
                        }
                    } else if (resizing) {
                        resizing.move((decrease ? -1 : 1) * that._resizeStep, target);
                    }
                    e.preventDefault();
                } else if (key === keys.ENTER && resizing) {
                    resizing.end();
                    e.preventDefault();
                }
            },
            _initPanes: function () {
                var panesConfig = this.options.panes || [];
                var that = this;
                this.element.addClass('k-widget').addClass('k-splitter').children().each(function (i, pane) {
                    if (pane.nodeName.toLowerCase() != 'script') {
                        that._initPane(pane, panesConfig[i]);
                    }
                });
                this.resize();
            },
            _initPane: function (pane, config) {
                pane = $(pane).attr('role', 'group').addClass(KPANE);
                pane.data(PANE, config ? config : {}).toggleClass('k-scrollable', config ? config.scrollable !== false : true);
                this.ajaxRequest(pane);
            },
            ajaxRequest: function (pane, url, data) {
                var that = this, paneConfig;
                pane = that.element.find(pane);
                paneConfig = pane.data(PANE);
                url = url || paneConfig.contentUrl;
                if (url) {
                    pane.append('<span class=\'k-icon k-i-loading k-pane-loading\' />');
                    if (kendo.isLocalUrl(url)) {
                        jQuery.ajax({
                            url: url,
                            data: data || {},
                            type: 'GET',
                            dataType: 'html',
                            success: function (data) {
                                that.angular('cleanup', function () {
                                    return { elements: pane.get() };
                                });
                                pane.html(data);
                                that.angular('compile', function () {
                                    return { elements: pane.get() };
                                });
                                that.trigger(CONTENTLOAD, { pane: pane[0] });
                            },
                            error: function (xhr, status) {
                                that.trigger(ERROR, {
                                    pane: pane[0],
                                    status: status,
                                    xhr: xhr
                                });
                            }
                        });
                    } else {
                        pane.removeClass('k-scrollable').html('<iframe src=\'' + url + '\' frameborder=\'0\' class=\'k-content-frame\'>' + 'This page requires frames in order to show content' + '</iframe>');
                    }
                }
            },
            _triggerAction: function (type, pane) {
                if (!this.trigger(type, { pane: pane[0] })) {
                    this[type](pane[0]);
                }
            },
            _togglePane: function (e) {
                var that = this, target = $(e.target), arrow;
                if (target.closest('.k-splitter')[0] != that.element[0]) {
                    return;
                }
                arrow = target.children('.k-icon:not(.k-resize-handle)');
                if (arrow.length !== 1) {
                    return;
                }
                if (arrow.is('.k-collapse-prev')) {
                    that._triggerAction(COLLAPSE, target.prev());
                } else if (arrow.is('.k-collapse-next')) {
                    that._triggerAction(COLLAPSE, target.next());
                } else if (arrow.is('.k-expand-prev')) {
                    that._triggerAction(EXPAND, target.prev());
                } else if (arrow.is('.k-expand-next')) {
                    that._triggerAction(EXPAND, target.next());
                }
            },
            _arrowClick: function (arrowType) {
                var that = this;
                return function (e) {
                    var target = $(e.target), pane;
                    if (target.closest('.k-splitter')[0] != that.element[0]) {
                        return;
                    }
                    if (target.is('.k-' + arrowType + '-prev')) {
                        pane = target.parent().prev();
                    } else {
                        pane = target.parent().next();
                    }
                    that._triggerAction(arrowType, pane);
                };
            },
            _updateSplitBar: function (splitbar, previousPane, nextPane) {
                var catIconIf = function (iconType, condition) {
                        return condition ? '<div class=\'k-icon ' + iconType + '\' />' : '';
                    }, orientation = this.orientation, draggable = previousPane.resizable !== false && nextPane.resizable !== false, prevCollapsible = previousPane.collapsible, prevCollapsed = previousPane.collapsed, nextCollapsible = nextPane.collapsible, nextCollapsed = nextPane.collapsed;
                splitbar.addClass('k-splitbar k-state-default k-splitbar-' + orientation).attr('role', 'separator').attr('aria-expanded', !(prevCollapsed || nextCollapsed)).removeClass('k-splitbar-' + orientation + '-hover').toggleClass('k-splitbar-draggable-' + orientation, draggable && !prevCollapsed && !nextCollapsed).toggleClass('k-splitbar-static-' + orientation, !draggable && !prevCollapsible && !nextCollapsible).html(catIconIf('k-collapse-prev k-i-arrow-60-up', prevCollapsible && !prevCollapsed && !nextCollapsed && orientation == VERTICAL) + catIconIf('k-collapse-prev k-i-arrow-60-left', prevCollapsible && !prevCollapsed && !nextCollapsed && orientation == HORIZONTAL) + catIconIf('k-expand-prev k-i-arrow-60-down', prevCollapsible && prevCollapsed && !nextCollapsed && orientation == VERTICAL) + catIconIf('k-expand-prev k-i-arrow-60-right', prevCollapsible && prevCollapsed && !nextCollapsed && orientation == HORIZONTAL) + catIconIf('k-resize-handle k-i-hbar', draggable && orientation == VERTICAL) + catIconIf('k-resize-handle k-i-vbar', draggable && orientation == HORIZONTAL) + catIconIf('k-collapse-next k-i-arrow-60-down', nextCollapsible && !nextCollapsed && !prevCollapsed && orientation == VERTICAL) + catIconIf('k-collapse-next k-i-arrow-60-right', nextCollapsible && !nextCollapsed && !prevCollapsed && orientation == HORIZONTAL) + catIconIf('k-expand-next k-i-arrow-60-up', nextCollapsible && nextCollapsed && !prevCollapsed && orientation == VERTICAL) + catIconIf('k-expand-next k-i-arrow-60-left', nextCollapsible && nextCollapsed && !prevCollapsed && orientation == HORIZONTAL));
                if (!draggable && !prevCollapsible && !nextCollapsible) {
                    splitbar.removeAttr('tabindex');
                }
            },
            _updateSplitBars: function () {
                var that = this;
                this.element.children('.k-splitbar').each(function () {
                    var splitbar = $(this), previousPane = splitbar.prevAll(PANECLASS).first().data(PANE), nextPane = splitbar.nextAll(PANECLASS).first().data(PANE);
                    if (!nextPane) {
                        return;
                    }
                    that._updateSplitBar(splitbar, previousPane, nextPane);
                });
            },
            _removeSplitBars: function () {
                this.element.children('.k-splitbar').remove();
            },
            _panes: function () {
                if (!this.element) {
                    return $();
                }
                return this.element.children(PANECLASS);
            },
            _resize: function () {
                var that = this, element = that.element, panes = element.children(PANECLASS), isHorizontal = that.orientation == HORIZONTAL, splitBars = element.children('.k-splitbar'), splitBarsCount = splitBars.length, sizingProperty = isHorizontal ? 'width' : 'height', totalSize = element[sizingProperty]();
                that.wrapper.addClass('k-splitter-resizing');
                if (splitBarsCount === 0) {
                    splitBarsCount = panes.length - 1;
                    panes.slice(0, splitBarsCount).after('<div tabindex=\'0\' class=\'k-splitbar\' data-marker=\'' + that._marker + '\' />');
                    that._updateSplitBars();
                    splitBars = element.children('.k-splitbar');
                } else {
                    that._updateSplitBars();
                }
                splitBars.each(function () {
                    totalSize -= this[isHorizontal ? 'offsetWidth' : 'offsetHeight'];
                });
                var sizedPanesWidth = 0, sizedPanesCount = 0, freeSizedPanes = $();
                panes.css({
                    position: 'absolute',
                    top: 0
                })[sizingProperty](function () {
                    var element = $(this), config = element.data(PANE) || {}, size;
                    element.removeClass('k-state-collapsed');
                    if (config.collapsed) {
                        size = config.collapsedSize ? calculateSize(config.collapsedSize, totalSize) : 0;
                        element.css('overflow', 'hidden').addClass('k-state-collapsed');
                    } else if (isFluid(config.size)) {
                        freeSizedPanes = freeSizedPanes.add(this);
                        return;
                    } else {
                        size = calculateSize(config.size, totalSize);
                    }
                    sizedPanesCount++;
                    sizedPanesWidth += size;
                    return size;
                });
                totalSize -= sizedPanesWidth;
                var freeSizePanesCount = freeSizedPanes.length, freeSizePaneWidth = Math.floor(totalSize / freeSizePanesCount);
                freeSizedPanes.slice(0, freeSizePanesCount - 1).css(sizingProperty, freeSizePaneWidth).end().eq(freeSizePanesCount - 1).css(sizingProperty, totalSize - (freeSizePanesCount - 1) * freeSizePaneWidth);
                var sum = 0, alternateSizingProperty = isHorizontal ? 'height' : 'width', positioningProperty = isHorizontal ? 'left' : 'top', sizingDomProperty = isHorizontal ? 'offsetWidth' : 'offsetHeight';
                if (freeSizePanesCount === 0) {
                    var lastNonCollapsedPane = panes.filter(function () {
                        return !($(this).data(PANE) || {}).collapsed;
                    }).last();
                    lastNonCollapsedPane[sizingProperty](totalSize + lastNonCollapsedPane[0][sizingDomProperty]);
                }
                element.children().css(alternateSizingProperty, element[alternateSizingProperty]()).each(function (i, child) {
                    if (child.tagName.toLowerCase() != 'script') {
                        child.style[positioningProperty] = Math.floor(sum) + 'px';
                        sum += child[sizingDomProperty];
                    }
                });
                that._detachEvents();
                that._attachEvents();
                that.wrapper.removeClass('k-splitter-resizing');
                kendo.resize(panes);
                that.trigger(LAYOUTCHANGE);
            },
            toggle: function (pane, expand) {
                var that = this, paneConfig;
                pane = that.element.find(pane);
                paneConfig = pane.data(PANE);
                if (!expand && !paneConfig.collapsible) {
                    return;
                }
                if (arguments.length == 1) {
                    expand = paneConfig.collapsed === undefined ? false : paneConfig.collapsed;
                }
                paneConfig.collapsed = !expand;
                if (paneConfig.collapsed) {
                    pane.css('overflow', 'hidden');
                } else {
                    pane.css('overflow', '');
                }
                that.resize(true);
            },
            collapse: function (pane) {
                this.toggle(pane, false);
            },
            expand: function (pane) {
                this.toggle(pane, true);
            },
            _addPane: function (config, idx, paneElement) {
                var that = this;
                if (paneElement.length) {
                    that.options.panes.splice(idx, 0, config);
                    that._initPane(paneElement, config);
                    that._removeSplitBars();
                    that.resize(true);
                }
                return paneElement;
            },
            append: function (config) {
                config = config || {};
                var that = this, paneElement = $('<div />').appendTo(that.element);
                return that._addPane(config, that.options.panes.length, paneElement);
            },
            insertBefore: function (config, referencePane) {
                referencePane = $(referencePane);
                config = config || {};
                var that = this, idx = that.wrapper.children('.k-pane').index(referencePane), paneElement = $('<div />').insertBefore($(referencePane));
                return that._addPane(config, idx, paneElement);
            },
            insertAfter: function (config, referencePane) {
                referencePane = $(referencePane);
                config = config || {};
                var that = this, idx = that.wrapper.children('.k-pane').index(referencePane), paneElement = $('<div />').insertAfter($(referencePane));
                return that._addPane(config, idx + 1, paneElement);
            },
            remove: function (pane) {
                pane = $(pane);
                var that = this;
                if (pane.length) {
                    kendo.destroy(pane);
                    pane.each(function (idx, element) {
                        that.options.panes.splice(that.wrapper.children('.k-pane').index(element), 1);
                        $(element).remove();
                    });
                    that._removeSplitBars();
                    if (that.options.panes.length) {
                        that.resize(true);
                    }
                }
                return that;
            },
            size: panePropertyAccessor('size', true),
            min: panePropertyAccessor('min'),
            max: panePropertyAccessor('max')
        });
        ui.plugin(Splitter);
        var verticalDefaults = {
            sizingProperty: 'height',
            sizingDomProperty: 'offsetHeight',
            alternateSizingProperty: 'width',
            positioningProperty: 'top',
            mousePositioningProperty: 'pageY'
        };
        var horizontalDefaults = {
            sizingProperty: 'width',
            sizingDomProperty: 'offsetWidth',
            alternateSizingProperty: 'height',
            positioningProperty: 'left',
            mousePositioningProperty: 'pageX'
        };
        function PaneResizing(splitter) {
            var that = this, orientation = splitter.orientation;
            that.owner = splitter;
            that._element = splitter.element;
            that.orientation = orientation;
            extend(that, orientation === HORIZONTAL ? horizontalDefaults : verticalDefaults);
            that._resizable = new kendo.ui.Resizable(splitter.element, {
                orientation: orientation,
                handle: '.k-splitbar-draggable-' + orientation + '[data-marker=' + splitter._marker + ']',
                hint: proxy(that._createHint, that),
                start: proxy(that._start, that),
                max: proxy(that._max, that),
                min: proxy(that._min, that),
                invalidClass: 'k-restricted-size-' + orientation,
                resizeend: proxy(that._stop, that)
            });
        }
        PaneResizing.prototype = {
            press: function (target) {
                this._resizable.press(target);
            },
            move: function (delta, target) {
                if (!this.pressed) {
                    this.press(target);
                    this.pressed = true;
                }
                if (!this._resizable.target) {
                    this._resizable.press(target);
                }
                this._resizable.move(delta);
            },
            end: function () {
                this._resizable.end();
                this.pressed = false;
            },
            destroy: function () {
                this._resizable.destroy();
                this._resizable = this._element = this.owner = null;
            },
            isResizing: function () {
                return this._resizable.resizing;
            },
            _createHint: function (handle) {
                var that = this;
                return $('<div class=\'k-ghost-splitbar k-ghost-splitbar-' + that.orientation + ' k-state-default\' />').css(that.alternateSizingProperty, handle[that.alternateSizingProperty]());
            },
            _start: function (e) {
                var that = this, splitbar = $(e.currentTarget), previousPane = splitbar.prev(), nextPane = splitbar.next(), previousPaneConfig = previousPane.data(PANE), nextPaneConfig = nextPane.data(PANE), prevBoundary = parseInt(previousPane[0].style[that.positioningProperty], 10), nextBoundary = parseInt(nextPane[0].style[that.positioningProperty], 10) + nextPane[0][that.sizingDomProperty] - splitbar[0][that.sizingDomProperty], totalSize = parseInt(that._element.css(that.sizingProperty), 10), toPx = function (value) {
                        var val = parseInt(value, 10);
                        return (isPixelSize(value) ? val : totalSize * val / 100) || 0;
                    }, prevMinSize = toPx(previousPaneConfig.min), prevMaxSize = toPx(previousPaneConfig.max) || nextBoundary - prevBoundary, nextMinSize = toPx(nextPaneConfig.min), nextMaxSize = toPx(nextPaneConfig.max) || nextBoundary - prevBoundary;
                that.previousPane = previousPane;
                that.nextPane = nextPane;
                that._maxPosition = Math.min(nextBoundary - nextMinSize, prevBoundary + prevMaxSize);
                that._minPosition = Math.max(prevBoundary + prevMinSize, nextBoundary - nextMaxSize);
            },
            _max: function () {
                return this._maxPosition;
            },
            _min: function () {
                return this._minPosition;
            },
            _stop: function (e) {
                var that = this, splitbar = $(e.currentTarget), owner = that.owner;
                owner._panes().children('.k-splitter-overlay').remove();
                if (e.keyCode !== kendo.keys.ESC) {
                    var ghostPosition = e.position, previousPane = splitbar.prev(), nextPane = splitbar.next(), previousPaneConfig = previousPane.data(PANE), nextPaneConfig = nextPane.data(PANE), previousPaneNewSize = ghostPosition - parseInt(previousPane[0].style[that.positioningProperty], 10), nextPaneNewSize = parseInt(nextPane[0].style[that.positioningProperty], 10) + nextPane[0][that.sizingDomProperty] - ghostPosition - splitbar[0][that.sizingDomProperty], fluidPanesCount = that._element.children(PANECLASS).filter(function () {
                            return isFluid($(this).data(PANE).size);
                        }).length;
                    if (!isFluid(previousPaneConfig.size) || fluidPanesCount > 1) {
                        if (isFluid(previousPaneConfig.size)) {
                            fluidPanesCount--;
                        }
                        previousPaneConfig.size = previousPaneNewSize + 'px';
                    }
                    if (!isFluid(nextPaneConfig.size) || fluidPanesCount > 1) {
                        nextPaneConfig.size = nextPaneNewSize + 'px';
                    }
                    owner.resize(true);
                }
                return false;
            }
        };
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dialog', [
        'kendo.core',
        'kendo.popup'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dialog',
        name: 'Dialog',
        category: 'web',
        description: 'The dialog widget is a modal popup that brings information to the user.',
        depends: [
            'core',
            'popup'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, TabKeyTrap = kendo.ui.Popup.TabKeyTrap, proxy = $.proxy, template = kendo.template, keys = kendo.keys, isFunction = $.isFunction, NS = 'kendoWindow', KDIALOG = '.k-dialog', KWINDOW = '.k-window', KICONCLOSE = '.k-dialog-close', KCONTENTCLASS = 'k-content k-window-content k-dialog-content', KCONTENT = '.k-content', KTITLELESS = 'k-dialog-titleless', KDIALOGTITLE = '.k-dialog-title', KDIALOGTITLEBAR = KDIALOGTITLE + 'bar', KBUTTONGROUP = '.k-dialog-buttongroup', KBUTTON = '.k-button', KALERT = 'k-alert', KCONFIRM = 'k-confirm', KPROMPT = 'k-prompt', KTEXTBOX = '.k-textbox', KOVERLAY = '.k-overlay', VISIBLE = ':visible', ZINDEX = 'zIndex', BODY = 'body', INITOPEN = 'initOpen', OPEN = 'open', CLOSE = 'close', SHOW = 'show', HIDE = 'hide', WIDTH = 'width', HUNDREDPERCENT = 100, messages = {
                okText: 'OK',
                cancel: 'Cancel',
                promptInput: 'Input'
            }, ceil = Math.ceil, templates, overlaySelector = ':not(link,meta,script,style)';
        function defined(x) {
            return typeof x != 'undefined';
        }
        function constrain(value, low, high) {
            return Math.max(Math.min(parseInt(value, 10), high === Infinity ? high : parseInt(high, 10)), parseInt(low, 10));
        }
        function buttonKeyTrigger(e) {
            return e.keyCode == keys.ENTER || e.keyCode == keys.SPACEBAR;
        }
        var DialogBase = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._init(that.element, that.options);
                kendo.notify(that);
            },
            _init: function (element, options) {
                var that = this, wrapper;
                that._centerCallback = proxy(that._center, that);
                that.appendTo = $(BODY);
                if (!defined(options.visible) || options.visible === null) {
                    options.visible = element.is(VISIBLE);
                }
                if (that.wrapperTemplate === undefined) {
                    that.wrapperTemplate = templates.wrapper;
                }
                that._createDialog();
                wrapper = that.wrapper = element.closest(KDIALOG);
                if (options._defaultFocus === undefined) {
                    that._defaultFocus = element[0];
                }
                that._tabindex(element);
                that._dimensions();
                this._tabKeyTrap = new TabKeyTrap(wrapper);
                if (!that.options.visible) {
                    that.wrapper.hide();
                } else {
                    that.toFront();
                    that._triggerInitOpen();
                    that.trigger(OPEN);
                    if (options.modal) {
                        that._overlay(wrapper.is(VISIBLE)).css({ opacity: 0.5 });
                        that._focusDialog();
                    }
                }
                if (options.closable) {
                    wrapper.autoApplyNS(NS);
                    element.autoApplyNS(NS);
                    wrapper.find(KICONCLOSE).on('click', proxy(that._closeClick, that)).on('keydown', proxy(that._closeKeyHandler, that));
                    element.on('keydown', proxy(that._keydown, that));
                }
            },
            _dimensions: function () {
                var that = this, wrapper = that.wrapper, options = that.options, width = options.width, height = options.height, dimensions = [
                        'minWidth',
                        'minHeight',
                        'maxWidth',
                        'maxHeight'
                    ];
                for (var i = 0; i < dimensions.length; i++) {
                    var value = options[dimensions[i]];
                    if (value && value != Infinity) {
                        wrapper.css(dimensions[i], value);
                    }
                }
                this._setElementMaxHeight();
                if (width) {
                    if (width.toString().indexOf('%') > 0) {
                        wrapper.width(width);
                    } else {
                        wrapper.width(constrain(width, options.minWidth, options.maxWidth));
                    }
                }
                if (height) {
                    if (height.toString().indexOf('%') > 0) {
                        wrapper.height(height);
                    } else {
                        wrapper.height(constrain(height, options.minHeight, options.maxHeight));
                    }
                    this._setElementHeight();
                }
            },
            _setElementMaxHeight: function () {
                var that = this, element = that.element, maxHeight = that.options.maxHeight, paddingBox, elementMaxHeight;
                if (maxHeight != Infinity) {
                    paddingBox = that._paddingBox(element);
                    elementMaxHeight = parseFloat(maxHeight, 10) - that._uiHeight() - paddingBox.vertical;
                    if (elementMaxHeight > 0) {
                        element.css({
                            maxHeight: ceil(elementMaxHeight) + 'px',
                            overflow: 'hidden'
                        });
                    }
                }
            },
            _paddingBox: function (element) {
                var paddingTop = parseFloat(element.css('padding-top'), 10), paddingLeft = parseFloat(element.css('padding-left'), 10), paddingBottom = parseFloat(element.css('padding-bottom'), 10), paddingRight = parseFloat(element.css('padding-right'), 10);
                return {
                    vertical: paddingTop + paddingBottom,
                    horizontal: paddingLeft + paddingRight
                };
            },
            _setElementHeight: function () {
                var that = this, element = that.element, height = that.options.height, paddingBox = that._paddingBox(element), elementHeight = parseFloat(height, 10) - that._uiHeight() - paddingBox.vertical;
                if (elementHeight > 0) {
                    that.element.css({
                        height: ceil(elementHeight) + 'px',
                        overflow: 'hidden'
                    });
                }
            },
            _uiHeight: function () {
                var that = this, wrapper = that.wrapper, actionbar = wrapper.children(KBUTTONGROUP), actionbarHeight = actionbar[0] && actionbar[0].offsetHeight || 0, titlebar = wrapper.children(KDIALOGTITLEBAR), titlebarHeight = titlebar[0] && titlebar[0].offsetHeight || 0;
                return actionbarHeight + titlebarHeight;
            },
            _overlay: function (visible) {
                var overlay = this.appendTo.children(KOVERLAY), wrapper = this.wrapper;
                if (!overlay.length) {
                    overlay = $(templates.overlay);
                }
                overlay.insertBefore(wrapper[0]).toggle(visible).css(ZINDEX, parseInt(wrapper.css(ZINDEX), 10) - 1);
                if (visible) {
                    this._waiAriaOverlay();
                } else {
                    this._removeWaiAriaOverlay();
                }
                return overlay;
            },
            _waiAriaOverlay: function () {
                var node = this.wrapper;
                this._overlayedNodes = node.prevAll(overlaySelector).add(node.nextAll(overlaySelector)).each(function () {
                    var jthis = $(this);
                    jthis.data('ariaHidden', jthis.attr('aria-hidden'));
                    jthis.attr('aria-hidden', 'true');
                });
            },
            _removeWaiAriaOverlay: function () {
                return this._overlayedNodes && this._overlayedNodes.each(function () {
                    var node = $(this);
                    var hiddenValue = node.data('ariaHidden');
                    if (hiddenValue) {
                        node.attr('aria-hidden', hiddenValue);
                    } else {
                        node.removeAttr('aria-hidden');
                    }
                });
            },
            _closeClick: function (e) {
                e.preventDefault();
                this.close();
            },
            _closeKeyHandler: function (e) {
                if (buttonKeyTrigger(e) || e.keyCode == keys.ESC) {
                    this.close();
                }
            },
            _keydown: function (e) {
                var that = this, options = that.options, keyCode = e.keyCode;
                if (keyCode == keys.ESC && !that._closing && options.closable) {
                    that.close();
                }
            },
            _createDialog: function () {
                var that = this, content = that.element, options = that.options, isRtl = kendo.support.isRtl(content), titlebar = $(templates.titlebar(options)), titlebarActions = titlebar.find('.k-window-actions'), titleId = (content.id || kendo.guid()) + '_title', wrapper = $(that.wrapperTemplate(options));
                wrapper.toggleClass('k-rtl', isRtl);
                content.addClass(KCONTENTCLASS);
                that.appendTo.append(wrapper);
                if (options.closable !== false) {
                    if (options.title !== false) {
                        titlebarActions.append(templates.close(options));
                    } else {
                        wrapper.append(templates.close(options));
                    }
                }
                if (options.title !== false) {
                    wrapper.append(titlebar);
                    titlebar.attr('id', titleId);
                    wrapper.attr('aria-labelledby', titleId);
                } else {
                    wrapper.addClass(KTITLELESS);
                }
                wrapper.append(content);
                if (options.content) {
                    kendo.destroy(content.children());
                    content.html(options.content);
                }
                if (options.actions.length) {
                    that._createActionbar(wrapper);
                }
            },
            _createActionbar: function (wrapper) {
                var isStretchedLayout = this.options.buttonLayout === 'stretched';
                var buttonLayout = isStretchedLayout ? 'stretched' : 'normal';
                var actionbar = $(templates.actionbar({ buttonLayout: buttonLayout }));
                this._addButtons(actionbar);
                if (isStretchedLayout) {
                    this._normalizeButtonSize(actionbar);
                }
                wrapper.append(actionbar);
            },
            _addButtons: function (actionbar) {
                var that = this, o = that.options, actionClick = proxy(that._actionClick, that), actionKeyHandler = proxy(that._actionKeyHandler, that), actions = that.options.actions, length = actions.length, buttonSize = HUNDREDPERCENT / length, action, text;
                for (var i = 0; i < length; i++) {
                    action = actions[i];
                    text = that._mergeTextWithOptions(action);
                    var btn = $(templates.action(action)).autoApplyNS(NS).html(text).appendTo(actionbar).data('action', action.action).on('click', actionClick).on('keydown', actionKeyHandler);
                    if (o.buttonLayout === 'stretched') {
                        btn.css(WIDTH, buttonSize + '%');
                    }
                }
            },
            _mergeTextWithOptions: function (action) {
                var text = action.text;
                return text ? template(text)(this.options) : '';
            },
            _normalizeButtonSize: function (actionbar) {
                var that = this, options = that.options, lastButton = actionbar.children(KBUTTON + ':last'), currentSize = parseFloat(lastButton[0].style[WIDTH]), difference = HUNDREDPERCENT - options.actions.length * currentSize;
                if (difference > 0) {
                    lastButton.css(WIDTH, currentSize + difference + '%');
                }
            },
            _tabindex: function (target) {
                var that = this;
                var wrapper = that.wrapper;
                var closeBtn = wrapper.find(KICONCLOSE);
                var actionButtons = wrapper.find(KBUTTONGROUP + ' ' + KBUTTON);
                Widget.fn._tabindex.call(this, target);
                var tabIndex = target.attr('tabindex');
                closeBtn.attr('tabIndex', tabIndex);
                actionButtons.attr('tabIndex', tabIndex);
            },
            _actionClick: function (e) {
                this._runActionBtn(e.currentTarget);
            },
            _actionKeyHandler: function (e) {
                if (buttonKeyTrigger(e)) {
                    this._runActionBtn(e.currentTarget);
                } else if (e.keyCode == keys.ESC) {
                    this.close();
                }
            },
            _runActionBtn: function (target) {
                var that = this;
                if (that._closing) {
                    return;
                }
                var action = $(target).data('action'), preventClose = isFunction(action) && action({ sender: that }) === false;
                if (!preventClose) {
                    that.close();
                }
            },
            open: function () {
                var that = this, wrapper = that.wrapper, showOptions = this._animationOptions(OPEN), options = that.options, overlay, otherModalsVisible;
                this._triggerInitOpen();
                if (!that.trigger(OPEN)) {
                    if (that._closing) {
                        wrapper.kendoStop(true, true);
                    }
                    that._closing = false;
                    that.toFront();
                    options.visible = true;
                    if (options.modal) {
                        otherModalsVisible = !!that._modals().length;
                        overlay = that._overlay(otherModalsVisible);
                        overlay.kendoStop(true, true);
                        if (showOptions.duration && kendo.effects.Fade && !otherModalsVisible) {
                            var overlayFx = kendo.fx(overlay).fadeIn();
                            overlayFx.duration(showOptions.duration || 0);
                            overlayFx.endValue(0.5);
                            overlayFx.play();
                        } else {
                            overlay.css('opacity', 0.5);
                        }
                        overlay.show();
                    }
                    wrapper.show().kendoStop().kendoAnimate({
                        effects: showOptions.effects,
                        duration: showOptions.duration,
                        complete: proxy(that._openAnimationEnd, that)
                    });
                    wrapper.show();
                }
                return that;
            },
            _animationOptions: function (id) {
                var animation = this.options.animation;
                var basicAnimation = {
                    open: { effects: {} },
                    close: {
                        hide: true,
                        effects: {}
                    }
                };
                return animation && animation[id] || basicAnimation[id];
            },
            _openAnimationEnd: function () {
                if (this.options.modal) {
                    this._focusDialog();
                }
                this.trigger(SHOW);
            },
            _triggerInitOpen: function () {
                if (!defined(this._initOpenTriggered)) {
                    this._initOpenTriggered = true;
                    this.trigger(INITOPEN);
                }
            },
            toFront: function () {
                var that = this, wrapper = that.wrapper, zIndex = +wrapper.css(ZINDEX), originalZIndex = zIndex;
                that.center();
                $(KWINDOW).each(function (i, element) {
                    var windowObject = $(element), zIndexNew = windowObject.css(ZINDEX);
                    if (!isNaN(zIndexNew)) {
                        zIndex = Math.max(+zIndexNew, zIndex);
                    }
                });
                if (!wrapper[0].style.zIndex || originalZIndex < zIndex) {
                    wrapper.css(ZINDEX, zIndex + 2);
                }
                that.element.find('> .k-overlay').remove();
                wrapper = null;
                return that;
            },
            close: function () {
                this._close(true);
                this._stopCenterOnResize();
                return this;
            },
            _close: function (systemTriggered) {
                var that = this, wrapper = that.wrapper, options = that.options, showOptions = this._animationOptions('open'), hideOptions = this._animationOptions('close');
                if (wrapper.is(VISIBLE) && !that.trigger(CLOSE, { userTriggered: !systemTriggered })) {
                    if (that._closing) {
                        return;
                    }
                    that._closing = true;
                    options.visible = false;
                    this._removeOverlay();
                    wrapper.kendoStop().kendoAnimate({
                        effects: hideOptions.effects || showOptions.effects,
                        reverse: hideOptions.reverse === true,
                        duration: hideOptions.duration,
                        complete: proxy(this._closeAnimationEnd, this)
                    });
                }
                return that;
            },
            center: function () {
                this._center();
                this._centerOnResize();
            },
            _center: function () {
                var that = this, wrapper = that.wrapper, documentWindow = $(window), scrollTop = 0, scrollLeft = 0, newLeft = scrollLeft + Math.max(0, (documentWindow.width() - wrapper.width()) / 2), newTop = scrollTop + Math.max(0, (documentWindow.height() - wrapper.height() - parseInt(wrapper.css('paddingTop'), 10)) / 2);
                wrapper.css({
                    left: newLeft,
                    top: newTop
                });
                return that;
            },
            _centerOnResize: function () {
                if (this._trackResize) {
                    return;
                }
                kendo.onResize(this._centerCallback);
                this._trackResize = true;
            },
            _stopCenterOnResize: function () {
                kendo.unbindResize(this._centerCallback);
                this._trackResize = false;
            },
            _removeOverlay: function () {
                var modals = this._modals();
                var options = this.options;
                var hideOverlay = options.modal && !modals.length;
                if (hideOverlay) {
                    this._overlay(false).remove();
                } else if (modals.length) {
                    this._object(modals.last())._overlay(true);
                }
            },
            _closeAnimationEnd: function () {
                var that = this;
                that._closing = false;
                that.wrapper.hide().css('opacity', '');
                that.trigger(HIDE);
                if (that.options.modal) {
                    var lastModal = that._object(that._modals().last());
                    if (lastModal) {
                        lastModal.toFront();
                    }
                }
            },
            _modals: function () {
                var that = this;
                var zStack = $(KWINDOW).filter(function () {
                    var dom = $(this);
                    var object = that._object(dom);
                    var options = object && object.options;
                    return options && options.modal && that.options.appendTo == options.appendTo && options.visible && dom.is(VISIBLE);
                }).sort(function (a, b) {
                    return +$(a).css('zIndex') - +$(b).css('zIndex');
                });
                that = null;
                return zStack;
            },
            _object: function (element) {
                var content = element.children(KCONTENT);
                var widget = kendo.widgetInstance(content);
                if (widget) {
                    return widget;
                }
                return undefined;
            },
            destroy: function () {
                var that = this;
                that._destroy();
                Widget.fn.destroy.call(that);
                that.wrapper.remove();
                that.wrapper = that.element = $();
            },
            _destroy: function () {
                var that = this;
                var ns = '.' + NS;
                that.wrapper.off(ns);
                that.element.off(ns);
                that.wrapper.find(KICONCLOSE + ',' + KBUTTONGROUP + ' > ' + KBUTTON).off(ns);
                that._stopCenterOnResize();
            },
            title: function (html) {
                var that = this, wrapper = that.wrapper, options = that.options, titlebar = wrapper.children(KDIALOGTITLEBAR), title = titlebar.children(KDIALOGTITLE), encodedHtml = kendo.htmlEncode(html);
                if (!arguments.length) {
                    return title.html();
                }
                if (html === false) {
                    titlebar.remove();
                    wrapper.addClass(KTITLELESS);
                } else {
                    if (!titlebar.length) {
                        titlebar = $(templates.titlebar(options)).prependTo(wrapper);
                        title = titlebar.children(KDIALOGTITLE);
                        wrapper.removeClass(KTITLELESS);
                    }
                    title.html(encodedHtml);
                }
                that.options.title = encodedHtml;
                return that;
            },
            content: function (html, data) {
                var that = this, content = that.wrapper.children(KCONTENT);
                if (!defined(html)) {
                    return content.html();
                }
                this.angular('cleanup', function () {
                    return { elements: content.children() };
                });
                kendo.destroy(content.children());
                content.html(html);
                this.angular('compile', function () {
                    var a = [];
                    for (var i = content.length; --i >= 0;) {
                        a.push({ dataItem: data });
                    }
                    return {
                        elements: content.children(),
                        data: a
                    };
                });
                that.options.content = html;
                return that;
            },
            _focusDialog: function () {
                if (this._defaultFocus) {
                    this._focus(this._defaultFocus);
                }
                this._tabKeyTrap.trap();
            },
            _focus: function (node) {
                if (node) {
                    node.focus();
                }
            },
            events: [
                INITOPEN,
                OPEN,
                CLOSE,
                SHOW,
                HIDE
            ],
            options: {
                title: '',
                buttonLayout: 'stretched',
                actions: [],
                modal: true,
                width: null,
                height: null,
                minWidth: 0,
                minHeight: 0,
                maxWidth: Infinity,
                maxHeight: Infinity,
                content: null,
                visible: null,
                appendTo: BODY,
                closable: true
            }
        });
        var Dialog = DialogBase.extend({
            options: {
                name: 'Dialog',
                messages: { close: 'Close' }
            }
        });
        kendo.ui.plugin(Dialog);
        var PopupBox = DialogBase.extend({
            _init: function (element, options) {
                var that = this;
                that.wrapperTemplate = templates.alertWrapper;
                options._defaultFocus = null;
                that._ensureContentId(element);
                DialogBase.fn._init.call(that, element, options);
                that.bind(HIDE, proxy(that.destroy, that));
                that._ariaDescribedBy();
                that._initFocus();
            },
            _ensureContentId: function (element) {
                var node = $(element);
                if (!node.attr('id')) {
                    node.attr('id', kendo.guid() + '_k-popup');
                }
            },
            _ariaDescribedBy: function () {
                this.wrapper.attr('aria-describedby', this.element.attr('id'));
            },
            _initFocus: function () {
                var o = this.options;
                this._defaultFocus = this._chooseEntryFocus();
                if (this._defaultFocus && o.visible && o.modal) {
                    this._focusDialog();
                }
            },
            _chooseEntryFocus: function () {
                return this.wrapper.find(KBUTTONGROUP + ' > ' + KBUTTON)[0];
            },
            options: {
                title: window.location.host,
                closable: false,
                messages: messages
            }
        });
        var Alert = PopupBox.extend({
            _init: function (element, options) {
                var that = this;
                PopupBox.fn._init.call(that, element, options);
                that.wrapper.addClass(KALERT);
            },
            options: {
                name: 'Alert',
                modal: true,
                actions: [{ text: '#: messages.okText #' }]
            }
        });
        kendo.ui.plugin(Alert);
        var kendoAlert = function (text) {
            return $(templates.alert).kendoAlert({ content: text }).data('kendoAlert').open();
        };
        var Confirm = PopupBox.extend({
            _init: function (element, options) {
                var that = this;
                PopupBox.fn._init.call(that, element, options);
                that.wrapper.addClass(KCONFIRM);
                that.result = $.Deferred();
            },
            options: {
                name: 'Confirm',
                modal: true,
                actions: [
                    {
                        text: '#: messages.okText #',
                        primary: true,
                        action: function (e) {
                            e.sender.result.resolve();
                        }
                    },
                    {
                        text: '#: messages.cancel #',
                        action: function (e) {
                            e.sender.result.reject();
                        }
                    }
                ]
            }
        });
        kendo.ui.plugin(Confirm);
        var kendoConfirm = function (text) {
            var confirmDialog = $(templates.confirm).kendoConfirm({ content: text }).data('kendoConfirm').open();
            return confirmDialog.result;
        };
        var Prompt = PopupBox.extend({
            _init: function (element, options) {
                var that = this;
                PopupBox.fn._init.call(that, element, options);
                that.wrapper.addClass(KPROMPT);
                that._createPrompt();
                that.result = $.Deferred();
            },
            _createPrompt: function () {
                var value = this.options.value, promptContainer = $(templates.promptInputContainer(this.options)).insertAfter(this.element);
                if (value) {
                    promptContainer.children(KTEXTBOX).val(value);
                }
                this._defaultFocus = this._chooseEntryFocus();
                this._focusDialog();
            },
            _chooseEntryFocus: function () {
                return this.wrapper.find(KTEXTBOX)[0];
            },
            options: {
                name: 'Prompt',
                modal: true,
                value: '',
                actions: [
                    {
                        text: '#: messages.okText #',
                        primary: true,
                        action: function (e) {
                            var sender = e.sender, value = sender.wrapper.find(KTEXTBOX).val();
                            sender.result.resolve(value);
                        }
                    },
                    {
                        text: '#: messages.cancel #',
                        action: function (e) {
                            var sender = e.sender, value = sender.wrapper.find(KTEXTBOX).val();
                            e.sender.result.reject(value);
                        }
                    }
                ]
            }
        });
        kendo.ui.plugin(Prompt);
        var kendoPrompt = function (text, value) {
            var promptDialog = $(templates.prompt).kendoPrompt({
                content: text,
                value: value
            }).data('kendoPrompt').open();
            return promptDialog.result;
        };
        templates = {
            wrapper: template('<div class=\'k-widget k-window k-dialog\' role=\'dialog\' />'),
            action: template('<button type=\'button\' class=\'k-button# if (data.primary) { # k-primary# } role=\'button\' #\'></button>'),
            titlebar: template('<div class=\'k-window-titlebar k-dialog-titlebar k-header\'>' + '<span class=\'k-window-title k-dialog-title\'>#: title #</span>' + '<div class=\'k-window-actions k-dialog-actions\' />' + '</div>'),
            close: template('<a role=\'button\' href=\'\\#\' class=\'k-button k-bare k-button-icon k-window-action k-dialog-action k-dialog-close\' title=\'#: messages.close #\' aria-label=\'#: messages.close #\' tabindex=\'-1\'><span class=\'k-icon k-i-close\'></span></a>'),
            actionbar: template('<div class=\'k-button-group k-dialog-buttongroup k-dialog-button-layout-#: buttonLayout #\' role=\'toolbar\' />'),
            overlay: '<div class=\'k-overlay\' />',
            alertWrapper: template('<div class=\'k-widget k-window k-dialog\' role=\'alertdialog\' />'),
            alert: '<div />',
            confirm: '<div />',
            prompt: '<div />',
            promptInputContainer: template('<div class=\'k-prompt-container\'><input type=\'text\' class=\'k-textbox\' title=\'#: messages.promptInput #\' aria-label=\'#: messages.promptInput #\' /></div>')
        };
        kendo.alert = kendoAlert;
        kendo.confirm = kendoConfirm;
        kendo.prompt = kendoPrompt;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.virtuallist', ['kendo.data'], f);
}(function () {
    var __meta__ = {
        id: 'virtuallist',
        name: 'VirtualList',
        category: 'framework',
        depends: ['data'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, DataBoundWidget = ui.DataBoundWidget, proxy = $.proxy, WRAPPER = 'k-virtual-wrap', VIRTUALLIST = 'k-virtual-list', CONTENT = 'k-virtual-content', LIST = 'k-list', HEADER = 'k-group-header', VIRTUALITEM = 'k-virtual-item', ITEM = 'k-item', HEIGHTCONTAINER = 'k-height-container', GROUPITEM = 'k-group', SELECTED = 'k-state-selected', FOCUSED = 'k-state-focused', HOVER = 'k-state-hover', CHANGE = 'change', CLICK = 'click', LISTBOUND = 'listBound', ITEMCHANGE = 'itemChange', ACTIVATE = 'activate', DEACTIVATE = 'deactivate', VIRTUAL_LIST_NS = '.VirtualList';
        function lastFrom(array) {
            return array[array.length - 1];
        }
        function toArray(value) {
            return value instanceof Array ? value : [value];
        }
        function isPrimitive(dataItem) {
            return typeof dataItem === 'string' || typeof dataItem === 'number' || typeof dataItem === 'boolean';
        }
        function getItemCount(screenHeight, listScreens, itemHeight) {
            return Math.ceil(screenHeight * listScreens / itemHeight);
        }
        function appendChild(parent, className, tagName) {
            var element = document.createElement(tagName || 'div');
            if (className) {
                element.className = className;
            }
            parent.appendChild(element);
            return element;
        }
        function getDefaultItemHeight() {
            var mockList = $('<div class="k-popup"><ul class="k-list"><li class="k-item"><li></ul></div>'), lineHeight;
            mockList.css({
                position: 'absolute',
                left: '-200000px',
                visibility: 'hidden'
            });
            mockList.appendTo(document.body);
            lineHeight = parseFloat(kendo.getComputedStyles(mockList.find('.k-item')[0], ['line-height'])['line-height']);
            mockList.remove();
            return lineHeight;
        }
        function bufferSizes(screenHeight, listScreens, opposite) {
            return {
                down: screenHeight * opposite,
                up: screenHeight * (listScreens - 1 - opposite)
            };
        }
        function listValidator(options, screenHeight) {
            var downThreshold = (options.listScreens - 1 - options.threshold) * screenHeight;
            var upThreshold = options.threshold * screenHeight;
            return function (list, scrollTop, lastScrollTop) {
                if (scrollTop > lastScrollTop) {
                    return scrollTop - list.top < downThreshold;
                } else {
                    return list.top === 0 || scrollTop - list.top > upThreshold;
                }
            };
        }
        function scrollCallback(element, callback) {
            return function (force) {
                return callback(element.scrollTop, force);
            };
        }
        function syncList(reorder) {
            return function (list, force) {
                reorder(list.items, list.index, force);
                return list;
            };
        }
        function position(element, y) {
            if (kendo.support.browser.msie && kendo.support.browser.version < 10) {
                element.style.top = y + 'px';
            } else {
                element.style.webkitTransform = 'translateY(' + y + 'px)';
                element.style.transform = 'translateY(' + y + 'px)';
            }
        }
        function map2(callback, templates) {
            return function (arr1, arr2) {
                for (var i = 0, len = arr1.length; i < len; i++) {
                    callback(arr1[i], arr2[i], templates);
                    if (arr2[i].item) {
                        this.trigger(ITEMCHANGE, {
                            item: $(arr1[i]),
                            data: arr2[i].item,
                            ns: kendo.ui
                        });
                    }
                }
            };
        }
        function reshift(items, diff) {
            var range;
            if (diff > 0) {
                range = items.splice(0, diff);
                items.push.apply(items, range);
            } else {
                range = items.splice(diff, -diff);
                items.unshift.apply(items, range);
            }
            return range;
        }
        function render(element, data, templates) {
            var itemTemplate = templates.template;
            element = $(element);
            if (!data.item) {
                itemTemplate = templates.placeholderTemplate;
            }
            this.angular('cleanup', function () {
                return { elements: [element] };
            });
            element.attr('data-uid', data.item ? data.item.uid : '').attr('data-offset-index', data.index).html(itemTemplate(data.item || {}));
            element.toggleClass(FOCUSED, data.current);
            element.toggleClass(SELECTED, data.selected);
            element.toggleClass('k-first', data.newGroup);
            element.toggleClass('k-loading-item', !data.item);
            if (data.index !== 0 && data.newGroup) {
                $('<div class=' + GROUPITEM + '></div>').appendTo(element).html(templates.groupTemplate(data.group));
            }
            if (data.top !== undefined) {
                position(element[0], data.top);
            }
            this.angular('compile', function () {
                return {
                    elements: [element],
                    data: [{
                            dataItem: data.item,
                            group: data.group,
                            newGroup: data.newGroup
                        }]
                };
            });
        }
        function mapChangedItems(selected, itemsToMatch) {
            var itemsLength = itemsToMatch.length;
            var selectedLength = selected.length;
            var dataItem;
            var found;
            var i, j;
            var changed = [];
            var unchanged = [];
            if (selectedLength) {
                for (i = 0; i < selectedLength; i++) {
                    dataItem = selected[i];
                    found = false;
                    for (j = 0; j < itemsLength; j++) {
                        if (dataItem === itemsToMatch[j]) {
                            found = true;
                            changed.push({
                                index: i,
                                item: dataItem
                            });
                            break;
                        }
                    }
                    if (!found) {
                        unchanged.push(dataItem);
                    }
                }
            }
            return {
                changed: changed,
                unchanged: unchanged
            };
        }
        function isActivePromise(promise) {
            return promise && promise.state() !== 'resolved';
        }
        var VirtualList = DataBoundWidget.extend({
            init: function (element, options) {
                var that = this;
                that.bound(false);
                that._fetching = false;
                Widget.fn.init.call(that, element, options);
                if (!that.options.itemHeight) {
                    that.options.itemHeight = getDefaultItemHeight();
                }
                options = that.options;
                that.element.addClass(LIST + ' ' + VIRTUALLIST).attr('role', 'listbox');
                that.content = that.element.wrap('<div unselectable=\'on\' class=\'' + CONTENT + '\'></div>').parent();
                that.wrapper = that.content.wrap('<div class=\'' + WRAPPER + '\'></div>').parent();
                that.header = that.content.before('<div class=\'' + HEADER + '\'></div>').prev();
                that.element.on('mouseenter' + VIRTUAL_LIST_NS, 'li:not(.k-loading-item)', function () {
                    $(this).addClass(HOVER);
                }).on('mouseleave' + VIRTUAL_LIST_NS, 'li', function () {
                    $(this).removeClass(HOVER);
                });
                that._values = toArray(that.options.value);
                that._selectedDataItems = [];
                that._selectedIndexes = [];
                that._rangesList = {};
                that._promisesList = [];
                that._optionID = kendo.guid();
                that._templates();
                that.setDataSource(options.dataSource);
                that.content.on('scroll' + VIRTUAL_LIST_NS, kendo.throttle(function () {
                    that._renderItems();
                    that._triggerListBound();
                }, options.delay));
                that._selectable();
            },
            options: {
                name: 'VirtualList',
                autoBind: true,
                delay: 100,
                height: null,
                listScreens: 4,
                threshold: 0.5,
                itemHeight: null,
                oppositeBuffer: 1,
                type: 'flat',
                selectable: false,
                value: [],
                dataValueField: null,
                template: '#:data#',
                placeholderTemplate: 'loading...',
                groupTemplate: '#:data#',
                fixedGroupTemplate: 'fixed header template',
                mapValueTo: 'index',
                valueMapper: null
            },
            events: [
                CHANGE,
                CLICK,
                LISTBOUND,
                ITEMCHANGE,
                ACTIVATE,
                DEACTIVATE
            ],
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                if (this._selectProxy && this.options.selectable === false) {
                    this.element.off(CLICK, '.' + VIRTUALITEM, this._selectProxy);
                } else if (!this._selectProxy && this.options.selectable) {
                    this._selectable();
                }
                this._templates();
                this.refresh();
            },
            items: function () {
                return $(this._items);
            },
            destroy: function () {
                this.wrapper.off(VIRTUAL_LIST_NS);
                this.dataSource.unbind(CHANGE, this._refreshHandler);
                Widget.fn.destroy.call(this);
            },
            setDataSource: function (source) {
                var that = this;
                var dataSource = source || {};
                var value;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                dataSource = kendo.data.DataSource.create(dataSource);
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    that._clean();
                    that.bound(false);
                    that._deferValueSet = true;
                    value = that.value();
                    that.value([]);
                    that.mute(function () {
                        that.value(value);
                    });
                } else {
                    that._refreshHandler = $.proxy(that.refresh, that);
                }
                that.dataSource = dataSource.bind(CHANGE, that._refreshHandler);
                that.setDSFilter(dataSource.filter());
                if (dataSource.view().length !== 0) {
                    that.refresh();
                } else if (that.options.autoBind) {
                    dataSource.fetch();
                }
            },
            skip: function () {
                return this.dataSource.currentRangeStart();
            },
            _triggerListBound: function () {
                var that = this;
                var skip = that.skip();
                if (that.bound() && !that._selectingValue && that._skip !== skip) {
                    that._skip = skip;
                    that.trigger(LISTBOUND);
                }
            },
            _getValues: function (dataItems) {
                var getter = this._valueGetter;
                return $.map(dataItems, function (dataItem) {
                    return getter(dataItem);
                });
            },
            refresh: function (e) {
                var that = this;
                var action = e && e.action;
                var isItemChange = action === 'itemchange';
                var filtered = this.isFiltered();
                var result;
                if (that._mute) {
                    return;
                }
                that._deferValueSet = false;
                if (!that._fetching) {
                    if (filtered) {
                        that.focus(0);
                    }
                    that._createList();
                    if (!action && that._values.length && !filtered && !that.options.skipUpdateOnBind) {
                        that._selectingValue = true;
                        that.value(that._values, true).done(function () {
                            that.bound(true);
                            that._selectingValue = false;
                            that._triggerListBound();
                        });
                    } else {
                        that.bound(true);
                        that._triggerListBound();
                    }
                } else {
                    if (that._renderItems) {
                        that._renderItems(true);
                    }
                    that._triggerListBound();
                }
                if (isItemChange || action === 'remove') {
                    result = mapChangedItems(that._selectedDataItems, e.items);
                    if (result.changed.length) {
                        if (isItemChange) {
                            that.trigger('selectedItemChange', { items: result.changed });
                        } else {
                            that.value(that._getValues(result.unchanged));
                        }
                    }
                }
                that._fetching = false;
            },
            removeAt: function (position) {
                this._selectedIndexes.splice(position, 1);
                this._values.splice(position, 1);
                return {
                    position: position,
                    dataItem: this._selectedDataItems.splice(position, 1)[0]
                };
            },
            setValue: function (value) {
                this._values = toArray(value);
            },
            value: function (value, _forcePrefetch) {
                var that = this;
                if (value === undefined) {
                    return that._values.slice();
                }
                if (value === null) {
                    value = [];
                }
                value = toArray(value);
                if (!that._valueDeferred || that._valueDeferred.state() === 'resolved') {
                    that._valueDeferred = $.Deferred();
                }
                var shouldClear = that.options.selectable === 'multiple' && that.select().length && value.length;
                if (shouldClear || !value.length) {
                    that.select(-1);
                }
                that._values = value;
                if (that.bound() && !that._mute && !that._deferValueSet || _forcePrefetch) {
                    that._prefetchByValue(value);
                }
                return that._valueDeferred;
            },
            _prefetchByValue: function (value) {
                var that = this, dataView = that._dataView, valueGetter = that._valueGetter, mapValueTo = that.options.mapValueTo, item, match = false, forSelection = [];
                for (var i = 0; i < value.length; i++) {
                    for (var idx = 0; idx < dataView.length; idx++) {
                        item = dataView[idx].item;
                        if (item) {
                            match = isPrimitive(item) ? value[i] === item : value[i] === valueGetter(item);
                            if (match) {
                                forSelection.push(dataView[idx].index);
                            }
                        }
                    }
                }
                if (forSelection.length === value.length) {
                    that._values = [];
                    that.select(forSelection);
                    return;
                }
                if (typeof that.options.valueMapper === 'function') {
                    that.options.valueMapper({
                        value: this.options.selectable === 'multiple' ? value : value[0],
                        success: function (response) {
                            if (mapValueTo === 'index') {
                                that.mapValueToIndex(response);
                            } else if (mapValueTo === 'dataItem') {
                                that.mapValueToDataItem(response);
                            }
                        }
                    });
                } else {
                    that.select([-1]);
                }
            },
            mapValueToIndex: function (indexes) {
                if (indexes === undefined || indexes === -1 || indexes === null) {
                    indexes = [];
                } else {
                    indexes = toArray(indexes);
                }
                if (!indexes.length) {
                    indexes = [-1];
                } else {
                    var removed = this._deselect([]).removed;
                    if (removed.length) {
                        this._triggerChange(removed, []);
                    }
                }
                this.select(indexes);
            },
            mapValueToDataItem: function (dataItems) {
                var removed, added;
                if (dataItems === undefined || dataItems === null) {
                    dataItems = [];
                } else {
                    dataItems = toArray(dataItems);
                }
                if (!dataItems.length) {
                    this.select([-1]);
                } else {
                    removed = $.map(this._selectedDataItems, function (item, index) {
                        return {
                            index: index,
                            dataItem: item
                        };
                    });
                    added = $.map(dataItems, function (item, index) {
                        return {
                            index: index,
                            dataItem: item
                        };
                    });
                    this._selectedDataItems = dataItems;
                    this._selectedIndexes = [];
                    for (var i = 0; i < this._selectedDataItems.length; i++) {
                        this._selectedIndexes.push(undefined);
                    }
                    this._triggerChange(removed, added);
                    if (this._valueDeferred) {
                        this._valueDeferred.resolve();
                    }
                }
            },
            deferredRange: function (index) {
                var dataSource = this.dataSource;
                var take = this.itemCount;
                var ranges = this._rangesList;
                var result = $.Deferred();
                var defs = [];
                var low = Math.floor(index / take) * take;
                var high = Math.ceil(index / take) * take;
                var pages = high === low ? [high] : [
                    low,
                    high
                ];
                $.each(pages, function (_, skip) {
                    var end = skip + take;
                    var existingRange = ranges[skip];
                    var deferred;
                    if (!existingRange || existingRange.end !== end) {
                        deferred = $.Deferred();
                        ranges[skip] = {
                            end: end,
                            deferred: deferred
                        };
                        dataSource._multiplePrefetch(skip, take, function () {
                            deferred.resolve();
                        });
                    } else {
                        deferred = existingRange.deferred;
                    }
                    defs.push(deferred);
                });
                $.when.apply($, defs).then(function () {
                    result.resolve();
                });
                return result;
            },
            prefetch: function (indexes) {
                var that = this, take = this.itemCount, isEmptyList = !that._promisesList.length;
                if (!isActivePromise(that._activeDeferred)) {
                    that._activeDeferred = $.Deferred();
                    that._promisesList = [];
                }
                $.each(indexes, function (_, index) {
                    that._promisesList.push(that.deferredRange(that._getSkip(index, take)));
                });
                if (isEmptyList) {
                    $.when.apply($, that._promisesList).done(function () {
                        that._promisesList = [];
                        that._activeDeferred.resolve();
                    });
                }
                return that._activeDeferred;
            },
            _findDataItem: function (view, index) {
                var group;
                if (this.options.type === 'group') {
                    for (var i = 0; i < view.length; i++) {
                        group = view[i].items;
                        if (group.length <= index) {
                            index = index - group.length;
                        } else {
                            return group[index];
                        }
                    }
                }
                return view[index];
            },
            _getRange: function (skip, take) {
                return this.dataSource._findRange(skip, Math.min(skip + take, this.dataSource.total()));
            },
            dataItemByIndex: function (index) {
                var take = this.itemCount;
                var skip = this._getSkip(index, take);
                var view = this._getRange(skip, take);
                return this._findDataItem(view, [index - skip]);
            },
            selectedDataItems: function () {
                return this._selectedDataItems.slice();
            },
            scrollWith: function (value) {
                this.content.scrollTop(this.content.scrollTop() + value);
            },
            scrollTo: function (y) {
                this.content.scrollTop(y);
            },
            scrollToIndex: function (index) {
                this.scrollTo(index * this.options.itemHeight);
            },
            focus: function (candidate) {
                var element, index, data, current, itemHeight = this.options.itemHeight, id = this._optionID, triggerEvent = true;
                if (candidate === undefined) {
                    current = this.element.find('.' + FOCUSED);
                    return current.length ? current : null;
                }
                if (typeof candidate === 'function') {
                    data = this.dataSource.flatView();
                    for (var idx = 0; idx < data.length; idx++) {
                        if (candidate(data[idx])) {
                            candidate = idx;
                            break;
                        }
                    }
                }
                if (candidate instanceof Array) {
                    candidate = lastFrom(candidate);
                }
                if (isNaN(candidate)) {
                    element = $(candidate);
                    index = parseInt($(element).attr('data-offset-index'), 10);
                } else {
                    index = candidate;
                    element = this._getElementByIndex(index);
                }
                if (index === -1) {
                    this.element.find('.' + FOCUSED).removeClass(FOCUSED);
                    this._focusedIndex = undefined;
                    return;
                }
                if (element.length) {
                    if (element.hasClass(FOCUSED)) {
                        triggerEvent = false;
                    }
                    if (this._focusedIndex !== undefined) {
                        current = this._getElementByIndex(this._focusedIndex);
                        current.removeClass(FOCUSED).removeAttr('id');
                        if (triggerEvent) {
                            this.trigger(DEACTIVATE);
                        }
                    }
                    this._focusedIndex = index;
                    element.addClass(FOCUSED).attr('id', id);
                    var position = this._getElementLocation(index);
                    if (position === 'top') {
                        this.scrollTo(index * itemHeight);
                    } else if (position === 'bottom') {
                        this.scrollTo(index * itemHeight + itemHeight - this._screenHeight);
                    } else if (position === 'outScreen') {
                        this.scrollTo(index * itemHeight);
                    }
                    if (triggerEvent) {
                        this.trigger(ACTIVATE);
                    }
                } else {
                    this._focusedIndex = index;
                    this.items().removeClass(FOCUSED);
                    this.scrollToIndex(index);
                }
            },
            focusIndex: function () {
                return this._focusedIndex;
            },
            focusFirst: function () {
                this.scrollTo(0);
                this.focus(0);
            },
            focusLast: function () {
                var lastIndex = this.dataSource.total();
                this.scrollTo(this.heightContainer.offsetHeight);
                this.focus(lastIndex);
            },
            focusPrev: function () {
                var index = this._focusedIndex;
                var current;
                if (!isNaN(index) && index > 0) {
                    index -= 1;
                    this.focus(index);
                    current = this.focus();
                    if (current && current.hasClass('k-loading-item')) {
                        index += 1;
                        this.focus(index);
                    }
                    return index;
                } else {
                    index = this.dataSource.total() - 1;
                    this.focus(index);
                    return index;
                }
            },
            focusNext: function () {
                var index = this._focusedIndex;
                var lastIndex = this.dataSource.total() - 1;
                var current;
                if (!isNaN(index) && index < lastIndex) {
                    index += 1;
                    this.focus(index);
                    current = this.focus();
                    if (current && current.hasClass('k-loading-item')) {
                        index -= 1;
                        this.focus(index);
                    }
                    return index;
                } else {
                    index = 0;
                    this.focus(index);
                    return index;
                }
            },
            _triggerChange: function (removed, added) {
                removed = removed || [];
                added = added || [];
                if (removed.length || added.length) {
                    this.trigger(CHANGE, {
                        removed: removed,
                        added: added
                    });
                }
            },
            select: function (candidate) {
                var that = this, indices, singleSelection = that.options.selectable !== 'multiple', prefetchStarted = isActivePromise(that._activeDeferred), filtered = this.isFiltered(), isAlreadySelected, deferred, result, removed = [];
                if (candidate === undefined) {
                    return that._selectedIndexes.slice();
                }
                if (!that._selectDeferred || that._selectDeferred.state() === 'resolved') {
                    that._selectDeferred = $.Deferred();
                }
                indices = that._getIndecies(candidate);
                isAlreadySelected = singleSelection && !filtered && lastFrom(indices) === lastFrom(this._selectedIndexes);
                removed = that._deselectCurrentValues(indices);
                if (removed.length || !indices.length || isAlreadySelected) {
                    that._triggerChange(removed);
                    if (that._valueDeferred) {
                        that._valueDeferred.resolve();
                    }
                    return that._selectDeferred.resolve().promise();
                }
                if (indices.length === 1 && indices[0] === -1) {
                    indices = [];
                }
                result = that._deselect(indices);
                removed = result.removed;
                indices = result.indices;
                if (singleSelection) {
                    prefetchStarted = false;
                    if (indices.length) {
                        indices = [lastFrom(indices)];
                    }
                }
                var done = function () {
                    var added = that._select(indices);
                    that.focus(indices);
                    that._triggerChange(removed, added);
                    if (that._valueDeferred) {
                        that._valueDeferred.resolve();
                    }
                    that._selectDeferred.resolve();
                };
                deferred = that.prefetch(indices);
                if (!prefetchStarted) {
                    if (deferred) {
                        deferred.done(done);
                    } else {
                        done();
                    }
                }
                return that._selectDeferred.promise();
            },
            bound: function (bound) {
                if (bound === undefined) {
                    return this._listCreated;
                }
                this._listCreated = bound;
            },
            mute: function (callback) {
                this._mute = true;
                proxy(callback(), this);
                this._mute = false;
            },
            setDSFilter: function (filter) {
                this._lastDSFilter = $.extend({}, filter);
            },
            isFiltered: function () {
                if (!this._lastDSFilter) {
                    this.setDSFilter(this.dataSource.filter());
                }
                return !kendo.data.Query.compareFilters(this.dataSource.filter(), this._lastDSFilter);
            },
            skipUpdate: $.noop,
            _getElementByIndex: function (index) {
                return this.items().filter(function (idx, element) {
                    return index === parseInt($(element).attr('data-offset-index'), 10);
                });
            },
            _getElementByDataItem: function (dataItem) {
                var dataView = this._dataView, valueGetter = this._valueGetter, element, match;
                for (var i = 0; i < dataView.length; i++) {
                    match = dataView[i].item && isPrimitive(dataView[i].item) ? dataView[i].item === dataItem : valueGetter(dataView[i].item) === valueGetter(dataItem);
                    if (match) {
                        element = dataView[i];
                        break;
                    }
                }
                return element ? this._getElementByIndex(element.index) : $();
            },
            _clean: function () {
                this.result = undefined;
                this._lastScrollTop = undefined;
                this._skip = undefined;
                $(this.heightContainer).remove();
                this.heightContainer = undefined;
                this.element.empty();
            },
            _height: function () {
                var hasData = !!this.dataSource.view().length, height = this.options.height, itemHeight = this.options.itemHeight, total = this.dataSource.total();
                if (!hasData) {
                    height = 0;
                } else if (height / itemHeight > total) {
                    height = total * itemHeight;
                }
                return height;
            },
            setScreenHeight: function () {
                var height = this._height();
                this.content.height(height);
                this._screenHeight = height;
            },
            screenHeight: function () {
                return this._screenHeight;
            },
            _getElementLocation: function (index) {
                var scrollTop = this.content.scrollTop(), screenHeight = this._screenHeight, itemHeight = this.options.itemHeight, yPosition = index * itemHeight, yDownPostion = yPosition + itemHeight, screenEnd = scrollTop + screenHeight, position;
                if (yPosition === scrollTop - itemHeight || yDownPostion > scrollTop && yPosition < scrollTop) {
                    position = 'top';
                } else if (yPosition === screenEnd || yPosition < screenEnd && screenEnd < yDownPostion) {
                    position = 'bottom';
                } else if (yPosition >= scrollTop && yPosition <= scrollTop + (screenHeight - itemHeight)) {
                    position = 'inScreen';
                } else {
                    position = 'outScreen';
                }
                return position;
            },
            _templates: function () {
                var options = this.options;
                var templates = {
                    template: options.template,
                    placeholderTemplate: options.placeholderTemplate,
                    groupTemplate: options.groupTemplate,
                    fixedGroupTemplate: options.fixedGroupTemplate
                };
                for (var key in templates) {
                    if (typeof templates[key] !== 'function') {
                        templates[key] = kendo.template(templates[key] || '');
                    }
                }
                this.templates = templates;
            },
            _generateItems: function (element, count) {
                var items = [], item, itemHeight = this.options.itemHeight + 'px';
                while (count-- > 0) {
                    item = document.createElement('li');
                    item.tabIndex = -1;
                    item.className = VIRTUALITEM + ' ' + ITEM;
                    item.setAttribute('role', 'option');
                    item.style.height = itemHeight;
                    item.style.minHeight = itemHeight;
                    element.appendChild(item);
                    items.push(item);
                }
                return items;
            },
            _saveInitialRanges: function () {
                var ranges = this.dataSource._ranges;
                var deferred = $.Deferred();
                deferred.resolve();
                this._rangesList = {};
                for (var i = 0; i < ranges.length; i++) {
                    this._rangesList[ranges[i].start] = {
                        end: ranges[i].end,
                        deferred: deferred
                    };
                }
            },
            _createList: function () {
                var that = this, content = that.content.get(0), options = that.options, dataSource = that.dataSource;
                if (that.bound()) {
                    that._clean();
                }
                that._saveInitialRanges();
                that._buildValueGetter();
                that.setScreenHeight();
                that.itemCount = getItemCount(that._screenHeight, options.listScreens, options.itemHeight);
                if (that.itemCount > dataSource.total()) {
                    that.itemCount = dataSource.total();
                }
                that._items = that._generateItems(that.element[0], that.itemCount);
                that._setHeight(options.itemHeight * dataSource.total());
                that.options.type = (dataSource.group() || []).length ? 'group' : 'flat';
                if (that.options.type === 'flat') {
                    that.header.hide();
                } else {
                    that.header.show();
                }
                that.getter = that._getter(function () {
                    that._renderItems(true);
                });
                that._onScroll = function (scrollTop, force) {
                    var getList = that._listItems(that.getter);
                    return that._fixedHeader(scrollTop, getList(scrollTop, force));
                };
                that._renderItems = that._whenChanged(scrollCallback(content, that._onScroll), syncList(that._reorderList(that._items, $.proxy(render, that))));
                that._renderItems();
                that._calculateGroupPadding(that._screenHeight);
            },
            _setHeight: function (height) {
                var currentHeight, heightContainer = this.heightContainer;
                if (!heightContainer) {
                    heightContainer = this.heightContainer = appendChild(this.content[0], HEIGHTCONTAINER);
                } else {
                    currentHeight = heightContainer.offsetHeight;
                }
                if (height !== currentHeight) {
                    heightContainer.innerHTML = '';
                    while (height > 0) {
                        var padHeight = Math.min(height, 250000);
                        appendChild(heightContainer).style.height = padHeight + 'px';
                        height -= padHeight;
                    }
                }
            },
            _getter: function () {
                var lastRequestedRange = null, dataSource = this.dataSource, lastRangeStart = dataSource.skip(), type = this.options.type, pageSize = this.itemCount, flatGroups = {};
                if (dataSource.pageSize() < pageSize) {
                    this.mute(function () {
                        dataSource.pageSize(pageSize);
                    });
                }
                return function (index, rangeStart) {
                    var that = this;
                    if (!dataSource.inRange(rangeStart, pageSize)) {
                        if (lastRequestedRange !== rangeStart) {
                            lastRequestedRange = rangeStart;
                            lastRangeStart = rangeStart;
                            if (that._getterDeferred) {
                                that._getterDeferred.reject();
                            }
                            that._getterDeferred = that.deferredRange(rangeStart);
                            that._getterDeferred.then(function () {
                                var firstItemIndex = that._indexConstraint(that.content[0].scrollTop);
                                that._getterDeferred = null;
                                if (rangeStart <= firstItemIndex && firstItemIndex <= rangeStart + pageSize) {
                                    that._fetching = true;
                                    dataSource.range(rangeStart, pageSize);
                                }
                            });
                        }
                        return null;
                    } else {
                        if (lastRangeStart !== rangeStart) {
                            this.mute(function () {
                                dataSource.range(rangeStart, pageSize);
                                lastRangeStart = rangeStart;
                            });
                        }
                        var result;
                        if (type === 'group') {
                            if (!flatGroups[rangeStart]) {
                                var flatGroup = flatGroups[rangeStart] = [];
                                var groups = dataSource.view();
                                for (var i = 0, len = groups.length; i < len; i++) {
                                    var group = groups[i];
                                    for (var j = 0, groupLength = group.items.length; j < groupLength; j++) {
                                        flatGroup.push({
                                            item: group.items[j],
                                            group: group.value
                                        });
                                    }
                                }
                            }
                            result = flatGroups[rangeStart][index - rangeStart];
                        } else {
                            result = dataSource.view()[index - rangeStart];
                        }
                        return result;
                    }
                };
            },
            _fixedHeader: function (scrollTop, list) {
                var group = this.currentVisibleGroup, itemHeight = this.options.itemHeight, firstVisibleDataItemIndex = Math.floor((scrollTop - list.top) / itemHeight), firstVisibleDataItem = list.items[firstVisibleDataItemIndex];
                if (firstVisibleDataItem && firstVisibleDataItem.item) {
                    var firstVisibleGroup = firstVisibleDataItem.group;
                    if (firstVisibleGroup !== group) {
                        this.header[0].innerHTML = firstVisibleGroup || '';
                        this.currentVisibleGroup = firstVisibleGroup;
                    }
                }
                return list;
            },
            _itemMapper: function (item, index, value) {
                var listType = this.options.type, itemHeight = this.options.itemHeight, currentIndex = this._focusedIndex, selected = false, current = false, newGroup = false, group = null, match = false, valueGetter = this._valueGetter;
                if (listType === 'group') {
                    if (item) {
                        newGroup = index === 0 || this._currentGroup && this._currentGroup !== item.group;
                        this._currentGroup = item.group;
                    }
                    group = item ? item.group : null;
                    item = item ? item.item : null;
                }
                if (!this.isFiltered() && value.length && item) {
                    for (var i = 0; i < value.length; i++) {
                        match = isPrimitive(item) ? value[i] === item : value[i] === valueGetter(item);
                        if (match) {
                            value.splice(i, 1);
                            selected = true;
                            break;
                        }
                    }
                }
                if (currentIndex === index) {
                    current = true;
                }
                return {
                    item: item ? item : null,
                    group: group,
                    newGroup: newGroup,
                    selected: selected,
                    current: current,
                    index: index,
                    top: index * itemHeight
                };
            },
            _range: function (index) {
                var itemCount = this.itemCount, value = this._values.slice(), items = [], item;
                this._view = {};
                this._currentGroup = null;
                for (var i = index, length = index + itemCount; i < length; i++) {
                    item = this._itemMapper(this.getter(i, index), i, value);
                    items.push(item);
                    this._view[item.index] = item;
                }
                this._dataView = items;
                return items;
            },
            _getDataItemsCollection: function (scrollTop, lastScrollTop) {
                var items = this._range(this._listIndex(scrollTop, lastScrollTop));
                return {
                    index: items.length ? items[0].index : 0,
                    top: items.length ? items[0].top : 0,
                    items: items
                };
            },
            _listItems: function () {
                var screenHeight = this._screenHeight, options = this.options;
                var theValidator = listValidator(options, screenHeight);
                return $.proxy(function (value, force) {
                    var result = this.result, lastScrollTop = this._lastScrollTop;
                    if (force || !result || !theValidator(result, value, lastScrollTop)) {
                        result = this._getDataItemsCollection(value, lastScrollTop);
                    }
                    this._lastScrollTop = value;
                    this.result = result;
                    return result;
                }, this);
            },
            _whenChanged: function (getter, callback) {
                var current;
                return function (force) {
                    var theNew = getter(force);
                    if (theNew !== current) {
                        current = theNew;
                        callback(theNew, force);
                    }
                };
            },
            _reorderList: function (list, reorder) {
                var that = this;
                var length = list.length;
                var currentOffset = -Infinity;
                reorder = $.proxy(map2(reorder, this.templates), this);
                return function (list2, offset, force) {
                    var diff = offset - currentOffset;
                    var range, range2;
                    if (force || Math.abs(diff) >= length) {
                        range = list;
                        range2 = list2;
                    } else {
                        range = reshift(list, diff);
                        range2 = diff > 0 ? list2.slice(-diff) : list2.slice(0, -diff);
                    }
                    reorder(range, range2, that.bound());
                    currentOffset = offset;
                };
            },
            _bufferSizes: function () {
                var options = this.options;
                return bufferSizes(this._screenHeight, options.listScreens, options.oppositeBuffer);
            },
            _indexConstraint: function (position) {
                var itemCount = this.itemCount, itemHeight = this.options.itemHeight, total = this.dataSource.total();
                return Math.min(Math.max(total - itemCount, 0), Math.max(0, Math.floor(position / itemHeight)));
            },
            _listIndex: function (scrollTop, lastScrollTop) {
                var buffers = this._bufferSizes(), position;
                position = scrollTop - (scrollTop > lastScrollTop ? buffers.down : buffers.up);
                return this._indexConstraint(position);
            },
            _selectable: function () {
                if (this.options.selectable) {
                    this._selectProxy = $.proxy(this, '_clickHandler');
                    this.element.on(CLICK + VIRTUAL_LIST_NS, '.' + VIRTUALITEM, this._selectProxy);
                }
            },
            getElementIndex: function (element) {
                if (!(element instanceof jQuery)) {
                    return undefined;
                }
                return parseInt(element.attr('data-offset-index'), 10);
            },
            _getIndecies: function (candidate) {
                var result = [], data;
                if (typeof candidate === 'function') {
                    data = this.dataSource.flatView();
                    for (var idx = 0; idx < data.length; idx++) {
                        if (candidate(data[idx])) {
                            result.push(idx);
                            break;
                        }
                    }
                }
                if (typeof candidate === 'number') {
                    result.push(candidate);
                }
                var elementIndex = this.getElementIndex(candidate);
                if (!isNaN(elementIndex)) {
                    result.push(elementIndex);
                }
                if (candidate instanceof Array) {
                    result = candidate;
                }
                return result;
            },
            _deselect: function (indices) {
                var removed = [], selectedIndex, dataItem, selectedIndexes = this._selectedIndexes, selectedDataItems = this._selectedDataItems, position = 0, selectable = this.options.selectable, removedindexesCounter = 0, valueGetter = this._valueGetter, item, match, result = null;
                indices = indices.slice();
                if (selectable === true || !indices.length) {
                    for (var idx = 0; idx < selectedIndexes.length; idx++) {
                        if (selectedIndexes[idx] !== undefined) {
                            this._getElementByIndex(selectedIndexes[idx]).removeClass(SELECTED);
                        } else if (selectedDataItems[idx]) {
                            this._getElementByDataItem(selectedDataItems[idx]).removeClass(SELECTED);
                        }
                        removed.push({
                            index: selectedIndexes[idx],
                            position: idx,
                            dataItem: selectedDataItems[idx]
                        });
                    }
                    this._values = [];
                    this._selectedDataItems = [];
                    this._selectedIndexes = [];
                } else if (selectable === 'multiple') {
                    for (var i = 0; i < indices.length; i++) {
                        result = null;
                        position = $.inArray(indices[i], selectedIndexes);
                        dataItem = this.dataItemByIndex(indices[i]);
                        if (position === -1 && dataItem) {
                            for (var j = 0; j < selectedDataItems.length; j++) {
                                match = isPrimitive(dataItem) ? selectedDataItems[j] === dataItem : valueGetter(selectedDataItems[j]) === valueGetter(dataItem);
                                if (match) {
                                    item = this._getElementByIndex(indices[i]);
                                    result = this._deselectSingleItem(item, j, indices[i], removedindexesCounter);
                                }
                            }
                        } else {
                            selectedIndex = selectedIndexes[position];
                            if (selectedIndex !== undefined) {
                                item = this._getElementByIndex(selectedIndex);
                                result = this._deselectSingleItem(item, position, selectedIndex, removedindexesCounter);
                            }
                        }
                        if (result) {
                            indices.splice(i, 1);
                            removed.push(result);
                            removedindexesCounter++;
                            i--;
                        }
                    }
                }
                return {
                    indices: indices,
                    removed: removed
                };
            },
            _deselectSingleItem: function (item, position, selectedIndex, removedindexesCounter) {
                var dataItem;
                if (!item.hasClass('k-state-selected')) {
                    return;
                }
                item.removeClass(SELECTED);
                this._values.splice(position, 1);
                this._selectedIndexes.splice(position, 1);
                dataItem = this._selectedDataItems.splice(position, 1)[0];
                return {
                    index: selectedIndex,
                    position: position + removedindexesCounter,
                    dataItem: dataItem
                };
            },
            _deselectCurrentValues: function (indices) {
                var children = this.element[0].children;
                var value, index, position;
                var values = this._values;
                var removed = [];
                var idx = 0;
                var j;
                if (this.options.selectable !== 'multiple' || !this.isFiltered()) {
                    return [];
                }
                if (indices[0] === -1) {
                    $(children).removeClass('k-state-selected');
                    removed = $.map(this._selectedDataItems.slice(0), function (dataItem, idx) {
                        return {
                            dataItem: dataItem,
                            position: idx
                        };
                    });
                    this._selectedIndexes = [];
                    this._selectedDataItems = [];
                    this._values = [];
                    return removed;
                }
                for (; idx < indices.length; idx++) {
                    position = -1;
                    index = indices[idx];
                    value = this._valueGetter(this.dataItemByIndex(index));
                    for (j = 0; j < values.length; j++) {
                        if (value == values[j]) {
                            position = j;
                            break;
                        }
                    }
                    if (position > -1) {
                        removed.push(this.removeAt(position));
                        $(children[index]).removeClass('k-state-selected');
                    }
                }
                return removed;
            },
            _getSkip: function (index, take) {
                var page = index < take ? 1 : Math.floor(index / take) + 1;
                return (page - 1) * take;
            },
            _select: function (indexes) {
                var that = this, singleSelection = this.options.selectable !== 'multiple', dataSource = this.dataSource, dataItem, oldSkip, take = this.itemCount, valueGetter = this._valueGetter, added = [];
                if (singleSelection) {
                    that._selectedIndexes = [];
                    that._selectedDataItems = [];
                    that._values = [];
                }
                oldSkip = dataSource.skip();
                $.each(indexes, function (_, index) {
                    var skip = that._getSkip(index, take);
                    that.mute(function () {
                        dataSource.range(skip, take);
                        dataItem = that._findDataItem(dataSource.view(), [index - skip]);
                        that._selectedIndexes.push(index);
                        that._selectedDataItems.push(dataItem);
                        that._values.push(isPrimitive(dataItem) ? dataItem : valueGetter(dataItem));
                        added.push({
                            index: index,
                            dataItem: dataItem
                        });
                        that._getElementByIndex(index).addClass(SELECTED);
                        dataSource.range(oldSkip, take);
                    });
                });
                return added;
            },
            _clickHandler: function (e) {
                var item = $(e.currentTarget);
                if (!e.isDefaultPrevented() && item.attr('data-uid')) {
                    this.trigger(CLICK, { item: item });
                }
            },
            _buildValueGetter: function () {
                this._valueGetter = kendo.getter(this.options.dataValueField);
            },
            _calculateGroupPadding: function (height) {
                var firstItem = this.items().first(), groupHeader = this.header, padding = 0;
                if (groupHeader[0] && groupHeader[0].style.display !== 'none') {
                    if (height !== 'auto') {
                        padding = kendo.support.scrollbar();
                    }
                    padding += parseFloat(firstItem.css('border-right-width'), 10) + parseFloat(firstItem.children('.k-group').css('right'), 10);
                    groupHeader.css('padding-right', padding);
                }
            }
        });
        kendo.ui.VirtualList = VirtualList;
        kendo.ui.plugin(VirtualList);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.view', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.view',
        name: 'Scheduler View',
        category: 'web',
        description: 'The Scheduler Common View',
        depends: ['core'],
        hidden: true
    };
    kendo.ui.scheduler = {};
    (function ($) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, outerHeight = kendo._outerHeight, keys = kendo.keys, NS = '.kendoSchedulerView', math = Math;
        function levels(values, key) {
            var result = [];
            function collect(depth, values) {
                values = values[key];
                if (values) {
                    var level = result[depth] = result[depth] || [];
                    for (var idx = 0; idx < values.length; idx++) {
                        level.push(values[idx]);
                        collect(depth + 1, values[idx]);
                    }
                }
            }
            collect(0, values);
            return result;
        }
        function cellspacing() {
            if (kendo.support.cssBorderSpacing) {
                return '';
            }
            return 'cellspacing="0"';
        }
        function table(tableRows, className) {
            if (!tableRows.length) {
                return '';
            }
            return '<table ' + cellspacing() + ' class="' + $.trim('k-scheduler-table ' + (className || '')) + '">' + '<tr>' + tableRows.join('</tr><tr>') + '</tr>' + '</table>';
        }
        function allDayTable(tableRows, className) {
            if (!tableRows.length) {
                return '';
            }
            return '<div style=\'position:relative\'>' + table(tableRows, className) + '</div>';
        }
        function timesHeader(columnLevelCount, allDaySlot, rowCount) {
            var tableRows = [];
            if (rowCount > 0) {
                for (var idx = 0; idx < columnLevelCount; idx++) {
                    tableRows.push('<th>&#8203;</th>');
                }
            }
            if (allDaySlot) {
                tableRows.push('<th class="k-scheduler-times-all-day">' + allDaySlot.text + '</th>');
            }
            if (rowCount < 1) {
                return $();
            }
            return $('<div class="k-scheduler-times">' + table(tableRows) + '</div>');
        }
        function datesHeader(columnLevels, columnCount, allDaySlot) {
            var dateTableRows = [];
            var columnIndex;
            for (var columnLevelIndex = 0; columnLevelIndex < columnLevels.length; columnLevelIndex++) {
                var level = columnLevels[columnLevelIndex];
                var th = [];
                var colspan = columnCount / level.length;
                for (columnIndex = 0; columnIndex < level.length; columnIndex++) {
                    var column = level[columnIndex];
                    th.push('<th colspan="' + (column.colspan || colspan) + '" class="' + (column.className || '') + '">' + column.text + '</th>');
                }
                dateTableRows.push(th.join(''));
            }
            var allDayTableRows = [];
            if (allDaySlot) {
                var lastLevel = columnLevels[columnLevels.length - 1];
                var td = [];
                var cellContent = allDaySlot.cellContent;
                for (columnIndex = 0; columnIndex < lastLevel.length; columnIndex++) {
                    td.push('<td class="' + (lastLevel[columnIndex].className || '') + '">' + (cellContent ? cellContent(columnIndex) : '&nbsp;') + '</td>');
                }
                allDayTableRows.push(td.join(''));
            }
            return $('<div class="k-scheduler-header k-state-default">' + '<div class="k-scheduler-header-wrap">' + table(dateTableRows) + allDayTable(allDayTableRows, 'k-scheduler-header-all-day') + '</div>' + '</div>');
        }
        function times(rowLevels, rowCount) {
            var rows = new Array(rowCount).join().split(',');
            var rowHeaderRows = [];
            var rowIndex;
            for (var rowLevelIndex = 0; rowLevelIndex < rowLevels.length; rowLevelIndex++) {
                var level = rowLevels[rowLevelIndex];
                var rowspan = rowCount / level.length;
                var className;
                for (rowIndex = 0; rowIndex < level.length; rowIndex++) {
                    className = level[rowIndex].className || '';
                    if (level[rowIndex].allDay) {
                        className = 'k-scheduler-times-all-day';
                    }
                    rows[rowspan * rowIndex] += '<th class="' + className + '" rowspan="' + rowspan + '">' + level[rowIndex].text + '</th>';
                }
            }
            for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
                rowHeaderRows.push(rows[rowIndex]);
            }
            if (rowCount < 1) {
                return $();
            }
            return $('<div class="k-scheduler-times">' + table(rowHeaderRows) + '</div>');
        }
        function content() {
            return $('<div class="k-scheduler-content">' + '<table ' + cellspacing() + ' class="k-scheduler-table"/>' + '</div>');
        }
        var HINT = '<div class="k-marquee k-scheduler-marquee">' + '<div class="k-marquee-color"></div>' + '<div class="k-marquee-text">' + '<div class="k-label-top"></div>' + '<div class="k-label-bottom"></div>' + '</div>' + '</div>';
        var ResourceView = kendo.Class.extend({
            init: function (index, isRtl) {
                this._index = index;
                this._timeSlotCollections = [];
                this._daySlotCollections = [];
                this._isRtl = isRtl;
            },
            addTimeSlotCollection: function (startDate, endDate) {
                return this._addCollection(startDate, endDate, this._timeSlotCollections);
            },
            addDaySlotCollection: function (startDate, endDate) {
                return this._addCollection(startDate, endDate, this._daySlotCollections);
            },
            _addCollection: function (startDate, endDate, collections) {
                var collection = new SlotCollection(startDate, endDate, this._index, collections.length);
                collections.push(collection);
                return collection;
            },
            timeSlotCollectionCount: function () {
                return this._timeSlotCollections.length;
            },
            daySlotCollectionCount: function () {
                return this._daySlotCollections.length;
            },
            daySlotByPosition: function (x, y, byDate) {
                return this._slotByPosition(x, y, this._daySlotCollections, byDate);
            },
            timeSlotByPosition: function (x, y, byDate) {
                return this._slotByPosition(x, y, this._timeSlotCollections, byDate);
            },
            _slotByPosition: function (x, y, collections, byDate) {
                for (var collectionIndex = 0; collectionIndex < collections.length; collectionIndex++) {
                    var collection = collections[collectionIndex];
                    for (var slotIndex = 0; slotIndex < collection.count(); slotIndex++) {
                        var slot = collection.at(slotIndex);
                        var width = slot.offsetWidth;
                        var height = slot.offsetHeight;
                        var nextSlot;
                        var horizontalEnd = slot.offsetLeft + width;
                        var verticalEnd = slot.offsetTop + height;
                        if (!byDate) {
                            nextSlot = collection.at(slotIndex + 1);
                        }
                        if (nextSlot) {
                            if (nextSlot.offsetLeft != slot.offsetLeft) {
                                if (this._isRtl) {
                                    horizontalEnd = slot.offsetLeft + (slot.offsetLeft - nextSlot.offsetLeft);
                                } else {
                                    horizontalEnd = nextSlot.offsetLeft;
                                }
                            } else {
                                verticalEnd = nextSlot.offsetTop;
                            }
                        }
                        if (x >= slot.offsetLeft && x < horizontalEnd && y >= slot.offsetTop && y < verticalEnd) {
                            return slot;
                        }
                    }
                }
            },
            refresh: function () {
                var collectionIndex;
                for (collectionIndex = 0; collectionIndex < this._daySlotCollections.length; collectionIndex++) {
                    this._daySlotCollections[collectionIndex].refresh();
                }
                for (collectionIndex = 0; collectionIndex < this._timeSlotCollections.length; collectionIndex++) {
                    this._timeSlotCollections[collectionIndex].refresh();
                }
            },
            timeSlotRanges: function (startTime, endTime) {
                var collections = this._timeSlotCollections;
                var start = this._startSlot(startTime, collections);
                if (!start.inRange && startTime >= start.slot.end) {
                    start = null;
                }
                var end = start;
                if (startTime < endTime) {
                    end = this._endSlot(endTime, collections);
                }
                if (end && !end.inRange && endTime <= end.slot.start) {
                    end = null;
                }
                if (start === null && end === null) {
                    return [];
                }
                if (start === null) {
                    start = {
                        inRange: true,
                        slot: collections[end.slot.collectionIndex].first()
                    };
                }
                if (end === null) {
                    end = {
                        inRange: true,
                        slot: collections[start.slot.collectionIndex].last()
                    };
                }
                return this._continuousRange(TimeSlotRange, collections, start, end);
            },
            daySlotRanges: function (startTime, endTime, isAllDay) {
                var collections = this._daySlotCollections;
                var start = this._startSlot(startTime, collections, isAllDay);
                if (!start.inRange && startTime >= start.slot.end) {
                    start = null;
                }
                var end = start;
                if (startTime < endTime) {
                    end = this._endSlot(endTime, collections, isAllDay);
                }
                if (end && !end.inRange && endTime <= end.slot.start) {
                    end = null;
                }
                if (start === null && end === null) {
                    return [];
                }
                if (start === null) {
                    do {
                        startTime += kendo.date.MS_PER_DAY;
                        start = this._startSlot(startTime, collections, isAllDay);
                    } while (!start.inRange && startTime >= start.slot.end);
                }
                if (end === null) {
                    do {
                        endTime -= kendo.date.MS_PER_DAY;
                        end = this._endSlot(endTime, collections, isAllDay);
                    } while (!end.inRange && endTime <= end.slot.start);
                }
                return this._continuousRange(DaySlotRange, collections, start, end);
            },
            _continuousRange: function (range, collections, start, end) {
                var startSlot = start.slot;
                var endSlot = end.slot;
                var startIndex = startSlot.collectionIndex;
                var endIndex = endSlot.collectionIndex;
                var ranges = [];
                for (var collectionIndex = startIndex; collectionIndex <= endIndex; collectionIndex++) {
                    var collection = collections[collectionIndex];
                    var first = collection.first();
                    var last = collection.last();
                    var head = false;
                    var tail = false;
                    if (collectionIndex == startIndex) {
                        tail = !start.inRange;
                    }
                    if (collectionIndex == endIndex) {
                        head = !end.inRange;
                    }
                    if (first.start < startSlot.start) {
                        first = startSlot;
                    }
                    if (last.start > endSlot.start) {
                        last = endSlot;
                    }
                    if (startIndex < endIndex) {
                        if (collectionIndex == startIndex) {
                            head = true;
                        } else if (collectionIndex == endIndex) {
                            tail = true;
                        } else {
                            head = tail = true;
                        }
                    }
                    ranges.push(new range({
                        start: first,
                        end: last,
                        collection: collection,
                        head: head,
                        tail: tail
                    }));
                }
                return ranges;
            },
            slotRanges: function (event, isDay) {
                var startTime = event._startTime || kendo.date.toUtcTime(event.start);
                var endTime = event._endTime || kendo.date.toUtcTime(event.end);
                if (isDay === undefined) {
                    isDay = event.isMultiDay();
                }
                if (isDay) {
                    return this.daySlotRanges(startTime, endTime, event.isAllDay);
                }
                return this.timeSlotRanges(startTime, endTime);
            },
            ranges: function (startTime, endTime, isDay, isAllDay) {
                if (typeof startTime != 'number') {
                    startTime = kendo.date.toUtcTime(startTime);
                }
                if (typeof endTime != 'number') {
                    endTime = kendo.date.toUtcTime(endTime);
                }
                if (isDay) {
                    return this.daySlotRanges(startTime, endTime, isAllDay);
                }
                return this.timeSlotRanges(startTime, endTime);
            },
            _startCollection: function (date, collections) {
                for (var collectionIndex = 0; collectionIndex < collections.length; collectionIndex++) {
                    var collection = collections[collectionIndex];
                    if (collection.startInRange(date)) {
                        return collection;
                    }
                }
                return null;
            },
            _endCollection: function (date, collections, isAllDay) {
                for (var collectionIndex = 0; collectionIndex < collections.length; collectionIndex++) {
                    var collection = collections[collectionIndex];
                    if (collection.endInRange(date, isAllDay)) {
                        return collection;
                    }
                }
                return null;
            },
            _getCollections: function (isDay) {
                return isDay ? this._daySlotCollections : this._timeSlotCollections;
            },
            continuousSlot: function (slot, reverse) {
                var pad = reverse ? -1 : 1;
                var collections = this._getCollections(slot.isDaySlot);
                var collection = collections[slot.collectionIndex + pad];
                return collection ? collection[reverse ? 'last' : 'first']() : undefined;
            },
            firstSlot: function () {
                var collections = this._getCollections(this.daySlotCollectionCount());
                return collections[0].first();
            },
            lastSlot: function () {
                var collections = this._getCollections(this.daySlotCollectionCount());
                return collections[collections.length - 1].last();
            },
            upSlot: function (slot, keepCollection, groupByDateVertically) {
                var that = this;
                var moveToDaySlot = function (isDaySlot, collectionIndex, index) {
                    var isFirstCell = index === 0;
                    if (!keepCollection && !isDaySlot && isFirstCell && that.daySlotCollectionCount()) {
                        return that._daySlotCollections[0].at(collectionIndex);
                    }
                };
                if (!this.timeSlotCollectionCount()) {
                    keepCollection = true;
                }
                return this._verticalSlot(slot, -1, moveToDaySlot, groupByDateVertically);
            },
            downSlot: function (slot, keepCollection, groupByDateVertically) {
                var that = this;
                var moveToTimeSlot = function (isDaySlot, collectionIndex, index) {
                    if (!keepCollection && isDaySlot && that.timeSlotCollectionCount()) {
                        return that._timeSlotCollections[index].at(0);
                    }
                };
                if (!this.timeSlotCollectionCount()) {
                    keepCollection = true;
                }
                return this._verticalSlot(slot, 1, moveToTimeSlot, groupByDateVertically);
            },
            leftSlot: function (slot, groupByDateVertically) {
                return this._horizontalSlot(slot, -1, groupByDateVertically);
            },
            rightSlot: function (slot, groupByDateVertically) {
                return this._horizontalSlot(slot, 1, groupByDateVertically);
            },
            _horizontalSlot: function (slot, step, groupByDateVertically) {
                var index = slot.index;
                var isDaySlot = slot.isDaySlot;
                var collectionIndex = slot.collectionIndex;
                var collections = this._getCollections(isDaySlot);
                isDaySlot = groupByDateVertically ? false : isDaySlot;
                if (isDaySlot) {
                    index += step;
                } else {
                    collectionIndex += step;
                }
                var collection = collections[collectionIndex];
                return collection ? collection.at(index) : undefined;
            },
            _verticalSlot: function (slot, step, swapCollection, groupByDateVertically) {
                var index = slot.index;
                var isDaySlot = slot.isDaySlot;
                var collectionIndex = slot.collectionIndex;
                var collections = this._getCollections(isDaySlot);
                slot = swapCollection(isDaySlot, collectionIndex, index);
                if (slot) {
                    return slot;
                }
                isDaySlot = groupByDateVertically ? false : isDaySlot;
                if (isDaySlot) {
                    collectionIndex += step;
                } else {
                    index += step;
                }
                var collection = collections[collectionIndex];
                return collection ? collection.at(index) : undefined;
            },
            _collection: function (index, multiday) {
                var collections = multiday ? this._daySlotCollections : this._timeSlotCollections;
                return collections[index];
            },
            _startSlot: function (time, collections, isAllDay) {
                var collection = this._startCollection(time, collections);
                var inRange = true;
                if (!collection) {
                    collection = collections[0];
                    inRange = false;
                }
                var slot = collection.slotByStartDate(time, isAllDay);
                if (!slot) {
                    slot = collection.first();
                    inRange = false;
                }
                return {
                    slot: slot,
                    inRange: inRange
                };
            },
            _endSlot: function (time, collections, isAllDay) {
                var collection = this._endCollection(time, collections, isAllDay);
                var inRange = true;
                if (!collection) {
                    collection = collections[collections.length - 1];
                    inRange = false;
                }
                var slot = collection.slotByEndDate(time, isAllDay);
                if (!slot) {
                    slot = collection.last();
                    inRange = false;
                }
                return {
                    slot: slot,
                    inRange: inRange
                };
            },
            getSlotCollection: function (index, isDay) {
                return this[isDay ? 'getDaySlotCollection' : 'getTimeSlotCollection'](index);
            },
            getTimeSlotCollection: function (index) {
                return this._timeSlotCollections[index];
            },
            getDaySlotCollection: function (index) {
                return this._daySlotCollections[index];
            }
        });
        var SlotRange = kendo.Class.extend({
            init: function (options) {
                $.extend(this, options);
            },
            innerHeight: function () {
                var collection = this.collection;
                var startIndex = this.start.index;
                var endIndex = this.end.index;
                var result = 0;
                for (var slotIndex = startIndex; slotIndex <= endIndex; slotIndex++) {
                    result += collection.at(slotIndex).offsetHeight;
                }
                return result;
            },
            events: function () {
                return this.collection.events();
            },
            addEvent: function (event) {
                this.events().push(event);
            },
            startSlot: function () {
                if (this.start.offsetLeft > this.end.offsetLeft) {
                    return this.end;
                }
                return this.start;
            },
            endSlot: function () {
                if (this.start.offsetLeft > this.end.offsetLeft) {
                    return this.start;
                }
                return this.end;
            }
        });
        var TimeSlotRange = SlotRange.extend({
            innerHeight: function () {
                var collection = this.collection;
                var startIndex = this.start.index;
                var endIndex = this.end.index;
                var result = 0;
                for (var slotIndex = startIndex; slotIndex <= endIndex; slotIndex++) {
                    result += collection.at(slotIndex).offsetHeight;
                }
                return result;
            },
            outerRect: function (start, end, snap) {
                return this._rect('offset', start, end, snap);
            },
            _rect: function (property, start, end, snap) {
                var top;
                var bottom;
                var left;
                var right;
                var startSlot = this.start;
                var endSlot = this.end;
                var isRtl = kendo.support.isRtl(startSlot.element);
                if (typeof start != 'number') {
                    start = kendo.date.toUtcTime(start);
                }
                if (typeof end != 'number') {
                    end = kendo.date.toUtcTime(end);
                }
                if (snap) {
                    top = startSlot.offsetTop;
                    bottom = endSlot.offsetTop + endSlot[property + 'Height'];
                    if (isRtl) {
                        left = endSlot.offsetLeft;
                        right = startSlot.offsetLeft + startSlot[property + 'Width'];
                    } else {
                        left = startSlot.offsetLeft;
                        right = endSlot.offsetLeft + endSlot[property + 'Width'];
                    }
                } else {
                    var startOffset = start - startSlot.start;
                    if (startOffset < 0) {
                        startOffset = 0;
                    }
                    var startSlotDuration = startSlot.end - startSlot.start;
                    top = startSlot.offsetTop + startSlot[property + 'Height'] * startOffset / startSlotDuration;
                    var endOffset = endSlot.end - end;
                    if (endOffset < 0) {
                        endOffset = 0;
                    }
                    var endSlotDuration = endSlot.end - endSlot.start;
                    bottom = endSlot.offsetTop + endSlot[property + 'Height'] - endSlot[property + 'Height'] * endOffset / endSlotDuration;
                    if (isRtl) {
                        left = Math.round(endSlot.offsetLeft + endSlot[property + 'Width'] * endOffset / endSlotDuration);
                        right = Math.round(startSlot.offsetLeft + startSlot[property + 'Width'] - startSlot[property + 'Width'] * startOffset / startSlotDuration);
                    } else {
                        left = Math.round(startSlot.offsetLeft + startSlot[property + 'Width'] * startOffset / startSlotDuration);
                        right = Math.round(endSlot.offsetLeft + endSlot[property + 'Width'] - endSlot[property + 'Width'] * endOffset / endSlotDuration);
                    }
                }
                return {
                    top: top,
                    bottom: bottom,
                    left: left === 0 ? left : left + 1,
                    right: right
                };
            },
            innerRect: function (start, end, snap) {
                return this._rect('client', start, end, snap);
            }
        });
        var DaySlotRange = SlotRange.extend({
            innerWidth: function () {
                var collection = this.collection;
                var startIndex = this.start.index;
                var endIndex = this.end.index;
                var result = 0;
                var width = startIndex !== endIndex ? 'offsetWidth' : 'clientWidth';
                for (var slotIndex = startIndex; slotIndex <= endIndex; slotIndex++) {
                    result += collection.at(slotIndex)[width];
                }
                return result;
            }
        });
        var SlotCollection = kendo.Class.extend({
            init: function (startDate, endDate, groupIndex, collectionIndex) {
                this._slots = [];
                this._events = [];
                this._start = kendo.date.toUtcTime(startDate);
                this._end = kendo.date.toUtcTime(endDate);
                this._groupIndex = groupIndex;
                this._collectionIndex = collectionIndex;
            },
            refresh: function () {
                for (var slotIndex = 0; slotIndex < this._slots.length; slotIndex++) {
                    this._slots[slotIndex].refresh();
                }
            },
            startInRange: function (date) {
                return this._start <= date && date < this._end;
            },
            endInRange: function (date, isAllDay) {
                var end = isAllDay ? date < this._end : date <= this._end;
                return this._start <= date && end;
            },
            slotByStartDate: function (date) {
                var time = date;
                if (typeof time != 'number') {
                    time = kendo.date.toUtcTime(date);
                }
                for (var slotIndex = 0; slotIndex < this._slots.length; slotIndex++) {
                    var slot = this._slots[slotIndex];
                    if (slot.startInRange(time)) {
                        return slot;
                    }
                }
                return null;
            },
            slotByEndDate: function (date, allday) {
                var time = date;
                if (typeof time != 'number') {
                    time = kendo.date.toUtcTime(date);
                }
                if (allday) {
                    return this.slotByStartDate(date, false);
                }
                for (var slotIndex = 0; slotIndex < this._slots.length; slotIndex++) {
                    var slot = this._slots[slotIndex];
                    if (slot.endInRange(time)) {
                        return slot;
                    }
                }
                return null;
            },
            count: function () {
                return this._slots.length;
            },
            events: function () {
                return this._events;
            },
            addTimeSlot: function (element, start, end, isHorizontal) {
                var slot = new TimeSlot(element, start, end, this._groupIndex, this._collectionIndex, this._slots.length, isHorizontal);
                this._slots.push(slot);
            },
            addDaySlot: function (element, start, end, eventCount) {
                var slot = new DaySlot(element, start, end, this._groupIndex, this._collectionIndex, this._slots.length, eventCount);
                this._slots.push(slot);
            },
            first: function () {
                return this._slots[0];
            },
            last: function () {
                return this._slots[this._slots.length - 1];
            },
            at: function (index) {
                return this._slots[index];
            }
        });
        var Slot = kendo.Class.extend({
            init: function (element, start, end, groupIndex, collectionIndex, index) {
                this.element = element;
                this.clientWidth = element.clientWidth;
                this.clientHeight = element.clientHeight;
                this.offsetWidth = element.offsetWidth;
                this.offsetHeight = element.offsetHeight;
                this.offsetTop = element.offsetTop;
                this.offsetLeft = element.offsetLeft;
                this.start = start;
                this.end = end;
                this.element = element;
                this.groupIndex = groupIndex;
                this.collectionIndex = collectionIndex;
                this.index = index;
                this.isDaySlot = false;
            },
            refresh: function () {
                var element = this.element;
                this.clientWidth = element.clientWidth;
                this.clientHeight = element.clientHeight;
                this.offsetWidth = element.offsetWidth;
                this.offsetHeight = element.offsetHeight;
                this.offsetTop = element.offsetTop;
                this.offsetLeft = element.offsetLeft;
            },
            startDate: function () {
                return kendo.timezone.toLocalDate(this.start);
            },
            endDate: function () {
                return kendo.timezone.toLocalDate(this.end);
            },
            startInRange: function (date) {
                return this.start <= date && date < this.end;
            },
            endInRange: function (date) {
                return this.start < date && date <= this.end;
            },
            startOffset: function () {
                return this.start;
            },
            endOffset: function () {
                return this.end;
            }
        });
        var TimeSlot = Slot.extend({
            init: function (element, start, end, groupIndex, collectionIndex, index, isHorizontal) {
                Slot.fn.init.apply(this, arguments);
                this.isHorizontal = isHorizontal ? true : false;
            },
            offsetX: function (rtl, offset) {
                if (rtl) {
                    return this.offsetLeft + offset;
                } else {
                    return this.offsetLeft + offset;
                }
            },
            startInRange: function (date) {
                return this.start <= date && date < this.end;
            },
            endInRange: function (date) {
                return this.start < date && date <= this.end;
            },
            startOffset: function (x, y, snap) {
                if (snap) {
                    return this.start;
                }
                var offset = $(this.element).offset();
                var duration = this.end - this.start;
                var difference;
                var time;
                if (this.isHorizontal) {
                    var isRtl = kendo.support.isRtl(this.element);
                    difference = x - offset.left;
                    time = Math.floor(duration * (difference / this.offsetWidth));
                    if (isRtl) {
                        return this.start + duration - time;
                    }
                } else {
                    difference = y - offset.top;
                    time = Math.floor(duration * (difference / this.offsetHeight));
                }
                return this.start + time;
            },
            endOffset: function (x, y, snap) {
                if (snap) {
                    return this.end;
                }
                var offset = $(this.element).offset();
                var duration = this.end - this.start;
                var difference;
                var time;
                if (this.isHorizontal) {
                    var isRtl = kendo.support.isRtl(this.element);
                    difference = x - offset.left;
                    time = Math.floor(duration * (difference / this.offsetWidth));
                    if (isRtl) {
                        return this.start + duration - time;
                    }
                } else {
                    difference = y - offset.top;
                    time = Math.floor(duration * (difference / this.offsetHeight));
                }
                return this.start + time;
            }
        });
        var DaySlot = Slot.extend({
            init: function (element, start, end, groupIndex, collectionIndex, index, eventCount) {
                Slot.fn.init.apply(this, arguments);
                this.eventCount = eventCount;
                this.isDaySlot = true;
                if (this.element.children.length) {
                    this.firstChildHeight = this.element.children[0].offsetHeight + 3;
                    this.firstChildTop = this.element.children[0].offsetTop;
                } else {
                    this.firstChildHeight = 3;
                    this.firstChildTop = 0;
                }
            },
            startDate: function () {
                var date = new Date(this.start);
                return kendo.timezone.apply(date, 'Etc/UTC');
            },
            endDate: function () {
                var date = new Date(this.end);
                return kendo.timezone.apply(date, 'Etc/UTC');
            },
            startInRange: function (date) {
                return this.start <= date && date < this.end;
            },
            endInRange: function (date) {
                return this.start < date && date <= this.end;
            }
        });
        var scrollbarWidth;
        function scrollbar() {
            scrollbarWidth = scrollbarWidth ? scrollbarWidth : kendo.support.scrollbar();
            return scrollbarWidth;
        }
        kendo.ui.SchedulerView = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._normalizeOptions();
                this._scrollbar = scrollbar();
                this._isRtl = kendo.support.isRtl(element);
                this._resizeHint = $();
                this._moveHint = $();
                this._cellId = kendo.guid();
                this._resourcesForGroups();
                this._selectedSlots = [];
            },
            _normalizeOptions: function () {
                var options = this.options;
                if (options.startTime) {
                    options.startTime.setMilliseconds(0);
                }
                if (options.endTime) {
                    options.endTime.setMilliseconds(0);
                }
                if (options.workDayStart) {
                    options.workDayStart.setMilliseconds(0);
                }
                if (options.workDayEnd) {
                    options.workDayEnd.setMilliseconds(0);
                }
            },
            _isMobile: function () {
                var options = this.options;
                return options.mobile === true && kendo.support.mobileOS || options.mobile === 'phone' || options.mobile === 'tablet';
            },
            _isMobilePhoneView: function () {
                var options = this.options;
                return options.mobile === true && kendo.support.mobileOS && !kendo.support.mobileOS.tablet || options.mobile === 'phone';
            },
            _addResourceView: function () {
                var resourceView = new ResourceView(this.groups.length, this._isRtl);
                this.groups.push(resourceView);
                return resourceView;
            },
            dateForTitle: function () {
                return kendo.format(this.options.selectedDateFormat, this.startDate(), this.endDate());
            },
            shortDateForTitle: function () {
                return kendo.format(this.options.selectedShortDateFormat, this.startDate(), this.endDate());
            },
            _changeGroup: function (selection, previous) {
                var method = previous ? 'prevGroupSlot' : 'nextGroupSlot';
                var slot = this[method](selection.start, selection.groupIndex, selection.isAllDay);
                if (slot) {
                    selection.groupIndex += previous ? -1 : 1;
                }
                if (this._isGroupedByDate() && !slot) {
                    selection.groupIndex = previous ? this.groups.length - 1 : 0;
                }
                return slot;
            },
            _changeDate: function (selection, slot, previous) {
                var group = this.groups[selection.groupIndex];
                var collections, index;
                if (previous) {
                    collections = group._getCollections(false);
                    index = group.daySlotCollectionCount() ? slot.index - 1 : slot.collectionIndex - 1;
                    if (index >= 0) {
                        return collections[index]._slots[collections[index]._slots.length - 1];
                    }
                } else {
                    collections = group._getCollections(group.daySlotCollectionCount());
                    index = group.daySlotCollectionCount() ? 0 : slot.collectionIndex + 1;
                    var slotIndex = group.daySlotCollectionCount() ? slot.collectionIndex + 1 : 0;
                    if (collections[index] && collections[index]._slots[slotIndex]) {
                        return collections[index]._slots[slotIndex];
                    }
                }
            },
            _changeGroupContinuously: function () {
                return null;
            },
            _changeViewPeriod: function () {
                return false;
            },
            _horizontalSlots: function (selection, ranges, multiple, reverse) {
                var method = reverse ? 'leftSlot' : 'rightSlot';
                var horizontalRange = {
                    startSlot: ranges[0].start,
                    endSlot: ranges[ranges.length - 1].end
                };
                var group = this.groups[selection.groupIndex];
                var isVertical = this._isVerticallyGrouped();
                if (!multiple) {
                    var slot = this._normalizeHorizontalSelection(selection, ranges, reverse);
                    if (slot) {
                        horizontalRange.startSlot = horizontalRange.endSlot = slot;
                    }
                }
                if (this._isGroupedByDate() && !multiple) {
                    var tempSlot = this._changeGroup(selection, reverse);
                    if (!tempSlot) {
                        horizontalRange = this._getNextHorizontalRange(group, method, horizontalRange);
                    } else {
                        horizontalRange.startSlot = horizontalRange.endSlot = tempSlot;
                    }
                } else {
                    horizontalRange.startSlot = group[method](horizontalRange.startSlot);
                    horizontalRange.endSlot = group[method](horizontalRange.endSlot);
                    if (!multiple && !isVertical && (!horizontalRange.startSlot || !horizontalRange.endSlot)) {
                        horizontalRange.startSlot = horizontalRange.endSlot = this._changeGroup(selection, reverse);
                    }
                }
                var continuousSlot;
                if ((!horizontalRange.startSlot || !horizontalRange.endSlot) && !this._isGroupedByDate()) {
                    continuousSlot = this._continuousSlot(selection, ranges, reverse);
                    continuousSlot = this._changeGroupContinuously(selection, continuousSlot, multiple, reverse);
                    if (continuousSlot) {
                        horizontalRange.startSlot = horizontalRange.endSlot = continuousSlot;
                    }
                }
                return horizontalRange;
            },
            _getNextHorizontalRange: function (group, method, horizontalRange) {
                if (!this._isVerticallyGrouped()) {
                    horizontalRange.startSlot = group[method](horizontalRange.startSlot);
                    horizontalRange.endSlot = group[method](horizontalRange.endSlot);
                }
                return horizontalRange;
            },
            _verticalSlots: function (selection, ranges, multiple, reverse) {
                var group = this.groups[selection.groupIndex];
                var slot;
                var verticalRange = {
                    startSlot: ranges[0].start,
                    endSlot: ranges[ranges.length - 1].end
                };
                if (!multiple) {
                    slot = this._normalizeVerticalSelection(selection, ranges, reverse);
                    if (slot) {
                        verticalRange.startSlot = verticalRange.endSlot = slot;
                    }
                }
                var method = reverse ? 'upSlot' : 'downSlot';
                verticalRange = this._getNextVerticalRange(group, method, verticalRange, multiple);
                if (!multiple && this._isVerticallyGrouped() && (!verticalRange.startSlot || !verticalRange.endSlot)) {
                    if (this._isGroupedByDate()) {
                        verticalRange.startSlot = verticalRange.endSlot = this._changeDate(selection, slot, reverse);
                    } else {
                        verticalRange.startSlot = verticalRange.endSlot = this._changeGroup(selection, reverse);
                    }
                }
                return verticalRange;
            },
            _getNextVerticalRange: function (group, method, verticalRange, multiple) {
                verticalRange.startSlot = group[method](verticalRange.startSlot, multiple);
                verticalRange.endSlot = group[method](verticalRange.endSlot, multiple);
                return verticalRange;
            },
            _normalizeHorizontalSelection: function () {
                return null;
            },
            _normalizeVerticalSelection: function (selection, ranges, reverse) {
                var slot;
                if (reverse) {
                    slot = ranges[0].start;
                } else {
                    slot = ranges[ranges.length - 1].end;
                }
                return slot;
            },
            _continuousSlot: function () {
                return null;
            },
            constrainSelection: function (selection) {
                var group = this.groups[0];
                var slot;
                if (!this.inRange(selection)) {
                    slot = group.firstSlot();
                    selection.isAllDay = slot.isDaySlot;
                    selection.start = slot.startDate();
                    selection.end = slot.endDate();
                } else {
                    if (!group.daySlotCollectionCount()) {
                        selection.isAllDay = false;
                    } else if (!group.timeSlotCollectionCount()) {
                        selection.isAllDay = true;
                    }
                }
                if (!this.groups[selection.groupIndex]) {
                    selection.groupIndex = 0;
                }
            },
            move: function (selection, key, shift) {
                var handled = false;
                var group = this.groups[selection.groupIndex];
                var verticalByDate = this._isGroupedByDate() && this._isVerticallyGrouped();
                if (!group.timeSlotCollectionCount()) {
                    selection.isAllDay = true;
                }
                var ranges = group.ranges(selection.start, selection.end, selection.isAllDay, false);
                var startSlot, endSlot, reverse, slots;
                if (key === keys.DOWN || key === keys.UP) {
                    handled = true;
                    reverse = key === keys.UP;
                    this._updateDirection(selection, ranges, shift, reverse, true);
                    slots = this._verticalSlots(selection, ranges, shift, reverse);
                    if (!slots.startSlot && !shift && this._changeViewPeriod(selection, reverse, !verticalByDate)) {
                        return handled;
                    }
                } else if (key === keys.LEFT || key === keys.RIGHT) {
                    handled = true;
                    reverse = key === keys.LEFT;
                    this._updateDirection(selection, ranges, shift, reverse, false);
                    slots = this._horizontalSlots(selection, ranges, shift, reverse);
                    if (!slots.startSlot && !shift && this._changeViewPeriod(selection, reverse, verticalByDate)) {
                        return handled;
                    }
                }
                if (handled) {
                    startSlot = slots.startSlot;
                    endSlot = slots.endSlot;
                    if (shift) {
                        var backward = selection.backward;
                        if (backward && startSlot) {
                            selection.start = startSlot.startDate();
                        } else if (!backward && endSlot) {
                            selection.end = endSlot.endDate();
                        }
                    } else if (startSlot && endSlot) {
                        selection.isAllDay = startSlot.isDaySlot;
                        selection.start = startSlot.startDate();
                        selection.end = endSlot.endDate();
                    }
                    selection.events = [];
                }
                return handled;
            },
            moveToEventInGroup: function (group, slot, selectedEvents, prev) {
                var events = group._continuousEvents || [];
                var found, event;
                var pad = prev ? -1 : 1;
                var length = events.length;
                var idx = prev ? length - 1 : 0;
                while (idx < length && idx > -1) {
                    event = events[idx];
                    if (!prev && event.start.startDate() >= slot.startDate() || prev && event.start.startDate() <= slot.startDate()) {
                        if (selectedEvents.length) {
                            event = events[idx + pad];
                        }
                        if (event && $.inArray(event.uid, selectedEvents) === -1) {
                            found = !!event;
                            break;
                        }
                    }
                    idx += pad;
                }
                return event;
            },
            moveToEvent: function (selection, prev) {
                var groupIndex = selection.groupIndex;
                var group = this.groups[groupIndex];
                var slot = group.ranges(selection.start, selection.end, selection.isAllDay, false)[0].start;
                var length = this.groups.length;
                var pad = prev ? -1 : 1;
                var events = selection.events;
                var event;
                if (this._isGroupedByDate()) {
                    var allEvents = this._getAllEvents();
                    var uniqueAllEvents = this._getUniqueEvents(allEvents);
                    var sortedEvents = this._getSortedEvents(uniqueAllEvents);
                    if (events.length === 0) {
                        var eventIndex = this._getNextEventIndexBySlot(slot, sortedEvents, groupIndex);
                        if (prev) {
                            eventIndex--;
                        }
                        event = sortedEvents[eventIndex];
                    } else {
                        var idx = this._getStartIdx(events, sortedEvents);
                        while (idx < sortedEvents.length && idx > -1) {
                            if (events.length > 0) {
                                slot = this._getSelectedSlot(slot, sortedEvents, event, idx, pad, prev);
                            }
                            if (!slot) {
                                break;
                            }
                            if (!prev && sortedEvents[idx].start.startDate() >= slot.startDate() || prev && sortedEvents[idx].start.startDate() <= slot.startDate()) {
                                if (events[0] != sortedEvents[idx].uid) {
                                    event = sortedEvents[idx];
                                    break;
                                }
                            }
                            idx += pad;
                        }
                    }
                } else {
                    while (groupIndex < length && groupIndex > -1) {
                        event = this.moveToEventInGroup(group, slot, events, prev);
                        groupIndex += pad;
                        group = this.groups[groupIndex];
                        if (!group || event) {
                            break;
                        }
                        events = [];
                        if (prev) {
                            slot = group.lastSlot();
                        } else {
                            slot = group.firstSlot(true);
                        }
                    }
                }
                if (event) {
                    selection.events = [event.uid];
                    selection.start = event.start.startDate();
                    selection.end = event.end.endDate();
                    selection.isAllDay = event.start.isDaySlot;
                    selection.groupIndex = event.start.groupIndex;
                }
                return !!event;
            },
            current: function (candidate) {
                if (candidate !== undefined) {
                    this._current = candidate;
                    if (this.content.has(candidate)) {
                        this._scrollTo(candidate, this.content[0]);
                    }
                } else {
                    return this._current;
                }
            },
            select: function (selection) {
                this.clearSelection();
                if (!this._selectEvents(selection)) {
                    this._selectSlots(selection);
                }
            },
            _getNextEventIndexBySlot: function (slot, sortedEvents, groupIndex) {
                var tempIndex = 0;
                var slotStartDate = kendo.date.getDate(slot.startDate());
                for (var i = 0; i < sortedEvents.length; i++) {
                    var eventStartDate = kendo.date.getDate(sortedEvents[i].start.startDate());
                    if (slotStartDate > eventStartDate) {
                        tempIndex++;
                        continue;
                    }
                    if (slotStartDate.getTime() === eventStartDate.getTime() && groupIndex > sortedEvents[i].start.groupIndex) {
                        tempIndex++;
                        continue;
                    }
                    if (slotStartDate.getTime() === eventStartDate.getTime() && groupIndex >= sortedEvents[i].start.groupIndex && slot.startDate() > sortedEvents[i].start.startDate()) {
                        tempIndex++;
                        continue;
                    }
                    break;
                }
                return tempIndex;
            },
            _getSelectedSlot: function (slot, sortedEvents, event, idx, pad, prev) {
                if (sortedEvents[idx + pad] && sortedEvents[idx].start.groupIndex !== sortedEvents[idx + pad].start.groupIndex) {
                    var groupIndex = sortedEvents[idx + pad].start.groupIndex;
                    var group = this.groups[groupIndex];
                    if (!group || event) {
                        slot = null;
                    }
                    if (prev) {
                        slot = group.lastSlot();
                    } else {
                        slot = group.firstSlot(true);
                    }
                }
                return slot;
            },
            _getStartIdx: function (events, sortedEvents) {
                var selectedEventIndex = 0;
                $.each(sortedEvents, function () {
                    if (this.uid === events[0]) {
                        return false;
                    }
                    selectedEventIndex++;
                });
                return selectedEventIndex;
            },
            _getAllEvents: function () {
                var allEvents = [];
                var groups = this.groups;
                for (var idx = 0; idx < groups.length; idx++) {
                    if (groups[idx]._continuousEvents) {
                        allEvents = allEvents.concat(groups[idx]._continuousEvents);
                    }
                }
                return allEvents;
            },
            _getUniqueEvents: function (allEvents) {
                var uniqueAllEvents = [];
                for (var i = 0; i < allEvents.length; i++) {
                    var exists = false;
                    for (var j = 0; j < uniqueAllEvents.length; j++) {
                        if (allEvents[i].uid === uniqueAllEvents[j].uid) {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists) {
                        uniqueAllEvents.push(allEvents[i]);
                    }
                }
                return uniqueAllEvents;
            },
            _getSortedEvents: function (uniqueAllEvents) {
                return uniqueAllEvents.sort(function (first, second) {
                    var firstStartDate = first.start.startDate();
                    var secondStartDate = second.start.startDate();
                    var result = kendo.date.getDate(firstStartDate) - kendo.date.getDate(secondStartDate);
                    if (result === 0) {
                        result = first.start.groupIndex - second.start.groupIndex;
                    }
                    if (result === 0) {
                        result = firstStartDate.getTime() - secondStartDate.getTime();
                    }
                    if (result === 0) {
                        if (first.start.isDaySlot && !second.start.isDaySlot) {
                            result = -1;
                        }
                        if (!first.start.isDaySlot && second.start.isDaySlot) {
                            result = 1;
                        }
                    }
                    if (result === 0) {
                        result = $(first.element).index() - $(second.element).index();
                    }
                    return result;
                });
            },
            _selectSlots: function (selection) {
                var isAllDay = selection.isAllDay;
                var group = this.groups[selection.groupIndex];
                if (!group.timeSlotCollectionCount()) {
                    isAllDay = true;
                }
                this._selectedSlots = [];
                var ranges = group.ranges(selection.start, selection.end, isAllDay, false);
                var element;
                var slot;
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    var range = ranges[rangeIndex];
                    var collection = range.collection;
                    for (var slotIndex = range.start.index; slotIndex <= range.end.index; slotIndex++) {
                        slot = collection.at(slotIndex);
                        element = slot.element;
                        element.setAttribute('aria-selected', true);
                        addSelectedState(element);
                        this._selectedSlots.push({
                            start: slot.startDate(),
                            end: slot.endDate(),
                            element: element
                        });
                    }
                }
                if (selection.backward) {
                    element = ranges[0].start.element;
                }
                this.current(element);
            },
            _selectEvents: function (selection) {
                var found = false;
                var events = selection.events;
                var groupEvents = this.groups[selection.groupIndex]._continuousEvents || [];
                var idx, length = groupEvents.length;
                if (!events[0] || !groupEvents[0]) {
                    return found;
                }
                var result = $();
                selection.events = [];
                for (idx = 0; idx < length; idx++) {
                    if ($.inArray(groupEvents[idx].uid, events) > -1) {
                        result = result.add(groupEvents[idx].element);
                        selection.events.push(groupEvents[idx].uid);
                    }
                }
                if (result[0]) {
                    result.addClass('k-state-selected').attr('aria-selected', true);
                    this.current(result.last()[0]);
                    this._selectedSlots = [];
                    found = true;
                }
                return found;
            },
            inRange: function (options) {
                var startDate = this.startDate();
                var endDate = kendo.date.addDays(this.endDate(), 1);
                var start = options.start;
                var end = options.end;
                return startDate <= start && start < endDate && startDate < end && end <= endDate;
            },
            _resourceValue: function (resource, item) {
                if (resource.valuePrimitive) {
                    item = kendo.getter(resource.dataValueField)(item);
                }
                return item;
            },
            _resourceBySlot: function (slot) {
                var resources = this.groupedResources;
                var result = {};
                if (resources.length) {
                    var resourceIndex = slot.groupIndex;
                    for (var idx = resources.length - 1; idx >= 0; idx--) {
                        var resource = resources[idx];
                        var value = this._resourceValue(resource, resource.dataSource.view()[resourceIndex % resource.dataSource.total()]);
                        if (resource.multiple) {
                            value = [value];
                        }
                        var setter = kendo.setter(resource.field);
                        setter(result, value);
                        resourceIndex = Math.floor(resourceIndex / resource.dataSource.total());
                    }
                }
                return result;
            },
            _createResizeHint: function (left, top, width, height) {
                return $(HINT).css({
                    left: left,
                    top: top,
                    width: width,
                    height: height
                });
            },
            _removeResizeHint: function () {
                this._resizeHint.remove();
                this._resizeHint = $();
            },
            _removeMoveHint: function () {
                this._moveHint.remove();
                this._moveHint = $();
            },
            _scrollTo: function (element, container) {
                var elementOffset = element.offsetTop, elementOffsetDir = element.offsetHeight, containerScroll = container.scrollTop, containerOffsetDir = container.clientHeight, bottomDistance = elementOffset + elementOffsetDir, result = 0;
                if (containerScroll > elementOffset) {
                    result = elementOffset;
                } else if (bottomDistance > containerScroll + containerOffsetDir) {
                    if (elementOffsetDir <= containerOffsetDir) {
                        result = bottomDistance - containerOffsetDir;
                    } else {
                        result = elementOffset;
                    }
                } else {
                    result = containerScroll;
                }
                container.scrollTop = result;
            },
            _shouldInverseResourceColor: function (resource) {
                var resourceColorIsDark = new Color(resource.color).isDark();
                var currentColor = this.element.css('color');
                var currentColorIsDark = new Color(currentColor).isDark();
                return resourceColorIsDark == currentColorIsDark;
            },
            _eventTmpl: function (template, wrapper) {
                var options = this.options, settings = $.extend({}, kendo.Template, options.templateSettings), paramName = settings.paramName, html = '', type = typeof template, state = {
                        storage: {},
                        count: 0
                    };
                if (type === 'function') {
                    state.storage['tmpl' + state.count] = template;
                    html += '#=this.tmpl' + state.count + '(' + paramName + ')#';
                    state.count++;
                } else if (type === 'string') {
                    html += template;
                }
                var tmpl = kendo.template(kendo.format(wrapper, html), settings);
                if (state.count > 0) {
                    tmpl = $.proxy(tmpl, state.storage);
                }
                return tmpl;
            },
            eventResources: function (event) {
                var resources = [], options = this.options;
                if (!options.resources) {
                    return resources;
                }
                for (var idx = 0; idx < options.resources.length; idx++) {
                    var resource = options.resources[idx];
                    var field = resource.field;
                    var eventResources = kendo.getter(field)(event);
                    if (eventResources == null) {
                        continue;
                    }
                    if (!resource.multiple) {
                        eventResources = [eventResources];
                    }
                    var data = resource.dataSource.view();
                    for (var resourceIndex = 0; resourceIndex < eventResources.length; resourceIndex++) {
                        var eventResource = null;
                        var value = eventResources[resourceIndex];
                        if (!resource.valuePrimitive) {
                            value = kendo.getter(resource.dataValueField)(value);
                        }
                        for (var dataIndex = 0; dataIndex < data.length; dataIndex++) {
                            if (data[dataIndex].get(resource.dataValueField) == value) {
                                eventResource = data[dataIndex];
                                break;
                            }
                        }
                        if (eventResource !== null) {
                            var resourceColor = kendo.getter(resource.dataColorField)(eventResource);
                            resources.push({
                                field: resource.field,
                                title: resource.title,
                                name: resource.name,
                                text: kendo.getter(resource.dataTextField)(eventResource),
                                value: value,
                                color: resourceColor
                            });
                        }
                    }
                }
                return resources;
            },
            createLayout: function (layout) {
                var allDayIndex = -1;
                if (!layout.rows) {
                    layout.rows = [];
                }
                for (var idx = 0; idx < layout.rows.length; idx++) {
                    if (layout.rows[idx].allDay) {
                        allDayIndex = idx;
                        break;
                    }
                }
                var allDaySlot = layout.rows[allDayIndex];
                if (allDayIndex >= 0) {
                    layout.rows.splice(allDayIndex, 1);
                }
                var columnLevels = this.columnLevels = levels(layout, 'columns');
                var rowLevels = this.rowLevels = levels(layout, 'rows');
                this.table = $('<table ' + cellspacing() + ' class="k-scheduler-layout k-scheduler-' + this.name + 'view"><tbody></tbody></table>');
                var rowCount = rowLevels[rowLevels.length - 1].length;
                this.table.find('tbody:first').append(this._topSection(columnLevels, allDaySlot, rowCount));
                this.table.find('tbody:first').append(this._bottomSection(columnLevels, rowLevels, rowCount));
                this.element.append(this.table);
                this._scroller();
            },
            refreshLayout: function () {
                var that = this, toolbar = that.element.find('>.k-scheduler-toolbar'), height = that.element.innerHeight(), scrollbar = this._scrollbar, headerHeight = 0, paddingDirection = this._isRtl ? 'left' : 'right';
                for (var idx = 0; idx < toolbar.length; idx++) {
                    height -= outerHeight(toolbar.eq(idx));
                }
                if (that.datesHeader) {
                    headerHeight = outerHeight(that.datesHeader);
                }
                if (that.timesHeader && outerHeight(that.timesHeader) > headerHeight) {
                    headerHeight = outerHeight(that.timesHeader);
                }
                if (that.datesHeader && that.timesHeader) {
                    var datesHeaderRows = that.datesHeader.find('table:first tr');
                    that.timesHeader.find('tr').height(function (index) {
                        $(this).height(datesHeaderRows.eq(index).height());
                    });
                }
                if (headerHeight) {
                    height -= headerHeight;
                }
                if (that.footer) {
                    height -= outerHeight(that.footer);
                }
                var isSchedulerHeightSet = function (el) {
                    var initialHeight, newHeight;
                    if (el[0].style.height) {
                        return true;
                    } else {
                        initialHeight = el.height();
                    }
                    el.height('auto');
                    newHeight = el.height();
                    if (initialHeight != newHeight) {
                        el.height('');
                        return true;
                    }
                    el.height('');
                    return false;
                };
                var contentDiv = that.content[0], scrollbarWidth = !kendo.support.kineticScrollNeeded ? scrollbar : 0;
                if (isSchedulerHeightSet(that.element)) {
                    if (height > scrollbar * 2) {
                        that.content.height(height);
                    } else {
                        that.content.height(scrollbar * 2 + 1);
                    }
                    that.times.height(contentDiv.clientHeight);
                    var timesTable = that.times.find('table');
                    if (timesTable.length) {
                        timesTable.height(that.content.find('table')[0].clientHeight);
                    }
                }
                if (contentDiv.offsetWidth - contentDiv.clientWidth > 0) {
                    that.table.addClass('k-scrollbar-v');
                    that.datesHeader.css('padding-' + paddingDirection, scrollbarWidth - parseInt(that.datesHeader.children().css('border-' + paddingDirection + '-width'), 10));
                } else {
                    that.datesHeader.css('padding-' + paddingDirection, '');
                }
                if (contentDiv.offsetHeight - contentDiv.clientHeight > 0 || contentDiv.clientHeight > that.content.children('.k-scheduler-table').height()) {
                    that.table.addClass('k-scrollbar-h');
                } else {
                    that.table.removeClass('k-scrollbar-h');
                }
            },
            _topSection: function (columnLevels, allDaySlot, rowCount) {
                this.timesHeader = timesHeader(columnLevels.length, allDaySlot, rowCount);
                var columnCount = columnLevels[columnLevels.length - 1].length;
                this.datesHeader = datesHeader(columnLevels, columnCount, allDaySlot);
                return $('<tr>').append(this.timesHeader.add(this.datesHeader).wrap('<td>').parent());
            },
            _bottomSection: function (columnLevels, rowLevels, rowCount) {
                this.times = times(rowLevels, rowCount);
                this.content = content(columnLevels[columnLevels.length - 1], rowLevels[rowLevels.length - 1]);
                return $('<tr>').append(this.times.add(this.content).wrap('<td>').parent());
            },
            _scroller: function () {
                var that = this;
                this.content.bind('scroll' + NS, function () {
                    that.datesHeader.find('>.k-scheduler-header-wrap').scrollLeft(this.scrollLeft);
                    that.times.scrollTop(this.scrollTop);
                });
                var touchScroller = kendo.touchScroller(this.content, {
                    avoidScrolling: function (e) {
                        return $(e.event.target).closest('.k-event.k-event-active').length > 0;
                    }
                });
                if (touchScroller && touchScroller.movable) {
                    this._touchScroller = touchScroller;
                    this.content = touchScroller.scrollElement;
                    touchScroller.movable.bind('change', function (e) {
                        that.datesHeader.find('>.k-scheduler-header-wrap').scrollLeft(-e.sender.x);
                        that.times.scrollTop(-e.sender.y);
                    });
                }
            },
            _resourcesForGroups: function () {
                var result = [];
                var groups = this.options.group;
                var resources = this.options.resources;
                groups = groups && groups.resources ? groups.resources : [];
                if (resources && groups.length) {
                    for (var idx = 0, length = resources.length; idx < length; idx++) {
                        for (var groupIdx = 0, groupLength = groups.length; groupIdx < groupLength; groupIdx++) {
                            if (resources[idx].name === groups[groupIdx]) {
                                result.push(resources[idx]);
                            }
                        }
                    }
                }
                this.groupedResources = result;
            },
            _createDateLayout: function (dates, inner, times) {
                return createDateLayoutConfiguration('rows', dates, inner, times);
            },
            _createColumnsLayout: function (resources, inner, template, dates, times) {
                return createLayoutConfiguration('columns', resources, inner, template, dates, times);
            },
            _groupOrientation: function () {
                var groups = this.options.group;
                return groups && groups.resources ? groups.orientation : 'horizontal';
            },
            _isGroupedByDate: function () {
                return this.options.group && this.options.group.date;
            },
            _isVerticallyGrouped: function () {
                return this.groupedResources.length && this._groupOrientation() === 'vertical';
            },
            _createRowsLayout: function (resources, inner, template, dates) {
                return createLayoutConfiguration('rows', resources, inner, template, dates);
            },
            selectionByElement: function () {
                return null;
            },
            clearSelection: function () {
                this.content.find('.k-state-selected').removeAttr('id').attr('aria-selected', false).removeClass('k-state-selected');
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(this);
                if (that.table) {
                    kendo.destroy(that.table);
                    that.table.remove();
                }
                that.groups = null;
                that.table = null;
                that.content = null;
                that.times = null;
                that.datesHeader = null;
                that.timesHeader = null;
                that.footer = null;
                that._resizeHint = null;
                that._moveHint = null;
            },
            calendarInfo: function () {
                return kendo.getCulture().calendars.standard;
            },
            prevGroupSlot: function (date, groupIndex, isDay) {
                var collection;
                var group = this.groups[groupIndex];
                var slot = group.ranges(date, date, isDay, false)[0].start;
                if (groupIndex <= 0) {
                    return;
                }
                if (this._isGroupedByDate()) {
                    return slot;
                }
                if (this._isVerticallyGrouped()) {
                    if (!group.timeSlotCollectionCount()) {
                        collection = group._collection(group.daySlotCollectionCount() - 1, true);
                        return collection.at(slot.index);
                    } else {
                        collection = group._collection(isDay ? slot.index : slot.collectionIndex, false);
                        return collection.last();
                    }
                } else {
                    if (!group.timeSlotCollectionCount()) {
                        collection = group._collection(slot.collectionIndex, true);
                        return collection.last();
                    } else {
                        collection = group._collection(isDay ? 0 : group.timeSlotCollectionCount() - 1, isDay);
                        return isDay ? collection.last() : collection.at(slot.index);
                    }
                }
            },
            nextGroupSlot: function (date, groupIndex, isDay) {
                var collection;
                var group = this.groups[groupIndex];
                var slot = group.ranges(date, date, isDay, false)[0].start;
                var daySlotCollectionCount;
                if (groupIndex >= this.groups.length - 1) {
                    return;
                }
                if (this._isGroupedByDate()) {
                    return slot;
                }
                if (this._isVerticallyGrouped()) {
                    if (!group.timeSlotCollectionCount()) {
                        collection = group._collection(0, true);
                        return collection.at(slot.index);
                    } else {
                        daySlotCollectionCount = group.daySlotCollectionCount();
                        collection = group._collection(daySlotCollectionCount ? 0 : slot.collectionIndex, daySlotCollectionCount);
                        return isDay ? collection.first() : collection.at(slot.collectionIndex);
                    }
                } else {
                    if (!group.timeSlotCollectionCount()) {
                        collection = group._collection(slot.collectionIndex, true);
                        return collection.first();
                    } else {
                        collection = group._collection(0, isDay);
                        return isDay ? collection.first() : collection.at(slot.index);
                    }
                }
            },
            _eventOptionsForMove: function () {
                return {};
            },
            _updateEventForResize: function () {
                return;
            },
            _updateEventForSelection: function (event) {
                return event;
            }
        });
        function collidingEvents(elements, start, end) {
            var idx, index, startIndex, overlaps, endIndex;
            for (idx = elements.length - 1; idx >= 0; idx--) {
                index = rangeIndex(elements[idx]);
                startIndex = index.start;
                endIndex = index.end;
                overlaps = startIndex <= start && endIndex >= start;
                if (overlaps || startIndex >= start && endIndex <= end || start <= startIndex && end >= startIndex) {
                    if (startIndex < start) {
                        start = startIndex;
                    }
                    if (endIndex > end) {
                        end = endIndex;
                    }
                }
            }
            return eventsForSlot(elements, start, end);
        }
        function rangeIndex(eventElement) {
            return {
                start: eventElement.start,
                end: eventElement.end
            };
        }
        function eventsForSlot(elements, slotStart, slotEnd) {
            var events = [];
            for (var idx = 0; idx < elements.length; idx++) {
                var event = rangeIndex(elements[idx]);
                if (event.start < slotStart && event.end > slotStart || event.start >= slotStart && event.end <= slotEnd) {
                    events.push(elements[idx]);
                }
            }
            return events;
        }
        function createColumns(eventElements) {
            return _createColumns(eventElements);
        }
        function createRows(eventElements) {
            return _createColumns(eventElements);
        }
        var Color = function (value) {
            var color = this, formats = Color.formats, re, processor, parts, i, channels;
            if (arguments.length === 1) {
                value = color.resolveColor(value);
                for (i = 0; i < formats.length; i++) {
                    re = formats[i].re;
                    processor = formats[i].process;
                    parts = re.exec(value);
                    if (parts) {
                        channels = processor(parts);
                        color.r = channels[0];
                        color.g = channels[1];
                        color.b = channels[2];
                    }
                }
            } else {
                color.r = arguments[0];
                color.g = arguments[1];
                color.b = arguments[2];
            }
            color.r = color.normalizeByte(color.r);
            color.g = color.normalizeByte(color.g);
            color.b = color.normalizeByte(color.b);
        };
        Color.prototype = {
            resolveColor: function (value) {
                value = value || '#000';
                if (value.charAt(0) == '#') {
                    value = value.substr(1, 6);
                }
                value = value.replace(/ /g, '');
                value = value.toLowerCase();
                value = Color.namedColors[value] || value;
                return value;
            },
            normalizeByte: function (value) {
                return value < 0 || isNaN(value) ? 0 : value > 255 ? 255 : value;
            },
            percBrightness: function () {
                var color = this;
                return math.sqrt(0.241 * color.r * color.r + 0.691 * color.g * color.g + 0.068 * color.b * color.b);
            },
            isDark: function () {
                var color = this;
                var brightnessValue = color.percBrightness();
                return brightnessValue < 180;
            }
        };
        Color.formats = [
            {
                re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
                process: function (parts) {
                    return [
                        parseInt(parts[1], 10),
                        parseInt(parts[2], 10),
                        parseInt(parts[3], 10)
                    ];
                }
            },
            {
                re: /^(\w{2})(\w{2})(\w{2})$/,
                process: function (parts) {
                    return [
                        parseInt(parts[1], 16),
                        parseInt(parts[2], 16),
                        parseInt(parts[3], 16)
                    ];
                }
            },
            {
                re: /^(\w{1})(\w{1})(\w{1})$/,
                process: function (parts) {
                    return [
                        parseInt(parts[1] + parts[1], 16),
                        parseInt(parts[2] + parts[2], 16),
                        parseInt(parts[3] + parts[3], 16)
                    ];
                }
            }
        ];
        Color.namedColors = {
            aqua: '00ffff',
            azure: 'f0ffff',
            beige: 'f5f5dc',
            black: '000000',
            blue: '0000ff',
            brown: 'a52a2a',
            coral: 'ff7f50',
            cyan: '00ffff',
            darkblue: '00008b',
            darkcyan: '008b8b',
            darkgray: 'a9a9a9',
            darkgreen: '006400',
            darkorange: 'ff8c00',
            darkred: '8b0000',
            dimgray: '696969',
            fuchsia: 'ff00ff',
            gold: 'ffd700',
            goldenrod: 'daa520',
            gray: '808080',
            green: '008000',
            greenyellow: 'adff2f',
            indigo: '4b0082',
            ivory: 'fffff0',
            khaki: 'f0e68c',
            lightblue: 'add8e6',
            lightgrey: 'd3d3d3',
            lightgreen: '90ee90',
            lightpink: 'ffb6c1',
            lightyellow: 'ffffe0',
            lime: '00ff00',
            limegreen: '32cd32',
            linen: 'faf0e6',
            magenta: 'ff00ff',
            maroon: '800000',
            mediumblue: '0000cd',
            navy: '000080',
            olive: '808000',
            orange: 'ffa500',
            orangered: 'ff4500',
            orchid: 'da70d6',
            pink: 'ffc0cb',
            plum: 'dda0dd',
            purple: '800080',
            red: 'ff0000',
            royalblue: '4169e1',
            salmon: 'fa8072',
            silver: 'c0c0c0',
            skyblue: '87ceeb',
            slateblue: '6a5acd',
            slategray: '708090',
            snow: 'fffafa',
            steelblue: '4682b4',
            tan: 'd2b48c',
            teal: '008080',
            tomato: 'ff6347',
            turquoise: '40e0d0',
            violet: 'ee82ee',
            wheat: 'f5deb3',
            white: 'ffffff',
            whitesmoke: 'f5f5f5',
            yellow: 'ffff00',
            yellowgreen: '9acd32'
        };
        function _createColumns(eventElements) {
            var columns = [];
            for (var idx = 0; idx < eventElements.length; idx++) {
                var event = eventElements[idx];
                var eventRange = rangeIndex(event);
                var column = null;
                for (var j = 0, columnLength = columns.length; j < columnLength; j++) {
                    var endOverlaps = eventRange.start > columns[j].end;
                    if (eventRange.start < columns[j].start || endOverlaps) {
                        column = columns[j];
                        if (column.end < eventRange.end) {
                            column.end = eventRange.end;
                        }
                        break;
                    }
                }
                if (!column) {
                    column = {
                        start: eventRange.start,
                        end: eventRange.end,
                        events: []
                    };
                    columns.push(column);
                }
                column.events.push(event);
            }
            return columns;
        }
        function createDateLayoutConfiguration(name, dates, inner, times) {
            var configuration = [];
            $.each(dates, function (index, item) {
                var className = item.className ? 'k-slot-cell ' + item.className : 'k-slot-cell';
                var obj = {
                    text: item.text,
                    className: className
                };
                if (times && !item.minorTicks) {
                    obj[name] = createDateLayoutConfiguration(name, item.columns, inner, times);
                } else {
                    obj[name] = inner;
                }
                configuration.push(obj);
            });
            return configuration;
        }
        function createLayoutConfiguration(name, resources, inner, template, dates, times) {
            var resource = resources[0];
            var configuration = [];
            if (resource) {
                if (dates && inner) {
                    $.each(dates, function (index, item) {
                        if (times && !item.minorTicks) {
                            item[name] = createLayoutConfiguration(name, resources, item.columns, template, item.columns, times);
                        } else {
                            item[name] = createLayoutConfiguration(name, resources, null, template);
                        }
                    });
                    configuration = dates;
                } else {
                    var data = resource.dataSource.view();
                    for (var dataIndex = 0; dataIndex < data.length; dataIndex++) {
                        var obj = {
                            text: template({
                                text: kendo.htmlEncode(kendo.getter(resource.dataTextField)(data[dataIndex])),
                                color: kendo.getter(resource.dataColorField)(data[dataIndex]),
                                field: resource.field,
                                title: resource.title,
                                name: resource.name,
                                value: kendo.getter(resource.dataValueField)(data[dataIndex])
                            }),
                            className: 'k-slot-cell'
                        };
                        obj[name] = createLayoutConfiguration(name, resources.slice(1), inner, template);
                        configuration.push(obj);
                    }
                }
                return configuration;
            }
            return inner;
        }
        function groupEqFilter(value) {
            return function (item) {
                if ($.isArray(item) || item instanceof kendo.data.ObservableArray) {
                    for (var idx = 0; idx < item.length; idx++) {
                        if (item[idx] == value) {
                            return true;
                        }
                    }
                    return false;
                }
                return item == value;
            };
        }
        var selectedStateRegExp = /\s*k-state-selected/;
        function addSelectedState(cell) {
            cell.className = cell.className.replace(selectedStateRegExp, '') + ' k-state-selected';
        }
        $.extend(ui.SchedulerView, {
            createColumns: createColumns,
            createRows: createRows,
            rangeIndex: rangeIndex,
            collidingEvents: collidingEvents,
            groupEqFilter: groupEqFilter
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.dayview', ['kendo.scheduler.view'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.dayview',
        name: 'Scheduler Day View',
        category: 'web',
        description: 'The Scheduler Day View',
        depends: ['scheduler.view'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, setTime = kendo.date.setTime, SchedulerView = ui.SchedulerView, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, extend = $.extend, proxy = $.proxy, getDate = kendo.date.getDate, MS_PER_MINUTE = kendo.date.MS_PER_MINUTE, MS_PER_DAY = kendo.date.MS_PER_DAY, CURRENT_TIME_MARKER_CLASS = 'k-current-time', CURRENT_TIME_MARKER_ARROW_CLASS = 'k-current-time-arrow', BORDER_SIZE_COEFF = 0.8666, getMilliseconds = kendo.date.getMilliseconds, NS = '.kendoMultiDayView';
        var DAY_VIEW_EVENT_TEMPLATE = kendo.template('<div title="(#=kendo.format("{0:t} - {1:t}", start, end)#): #=title.replace(/"/g,"&\\#34;")#">' + '<div class="k-event-template k-event-time">#:kendo.format("{0:t} - {1:t}", start, end)#</div>' + '<div class="k-event-template">${title}</div>' + '</div>'), DAY_VIEW_ALL_DAY_EVENT_TEMPLATE = kendo.template('<div title="(#=kendo.format("{0:t}", start)#): #=title.replace(/"/g,"&\\#34;")#">' + '<div class="k-event-template">${title}</div>' + '</div>'), DATA_HEADER_TEMPLATE = kendo.template('<span class=\'k-link k-nav-day\'>#=kendo.toString(date, \'ddd M/dd\')#</span>'), ALLDAY_EVENT_WRAPPER_STRING = '<div role="gridcell" aria-selected="false" ' + 'data-#=ns#uid="#=uid#"' + '#if (resources[0]) { #' + 'style="background-color:#=resources[0].color#; border-color: #=resources[0].color#"' + 'class="k-event#=inverseColor ? " k-event-inverse" : ""#" ' + '#} else {#' + 'class="k-event"' + '#}#' + '>' + '<span class="k-event-actions">' + '# if(data.tail || data.middle) {#' + '<span class="k-icon k-i-arrow-60-left"></span>' + '#}#' + '# if(data.isException()) {#' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if(data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '# } #' + '</span>' + '{0}' + '<span class="k-event-actions">' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '# if(data.head || data.middle) {#' + '<span class="k-icon k-i-arrow-60-right"></span>' + '#}#' + '</span>' + '#if(resizable && !singleDay && !data.tail && !data.middle){#' + '<span class="k-resize-handle k-resize-w"></span>' + '#}#' + '#if(resizable && !singleDay && !data.head && !data.middle){#' + '<span class="k-resize-handle k-resize-e"></span>' + '#}#' + '</div>', EVENT_WRAPPER_STRING = '<div role="gridcell" aria-selected="false" ' + 'data-#=ns#uid="#=uid#" ' + '#if (resources[0]) { #' + 'style="background-color:#=resources[0].color #; border-color: #=resources[0].color#"' + 'class="k-event#=inverseColor ? " k-event-inverse" : ""#"' + '#} else {#' + 'class="k-event"' + '#}#' + '>' + '<span class="k-event-actions">' + '# if(data.isException()) {#' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if(data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '# } #' + '</span>' + '{0}' + '<span class="k-event-actions">' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '</span>' + '<span class="k-event-top-actions">' + '# if(data.tail || data.middle) {#' + '<span class="k-icon k-i-arrow-60-up"></span>' + '# } #' + '</span>' + '<span class="k-event-bottom-actions">' + '# if(data.head || data.middle) {#' + '<span class="k-icon k-i-arrow-60-down"></span>' + '# } #' + '</span>' + '# if(resizable && !data.tail && !data.middle) {#' + '<span class="k-resize-handle k-resize-n"></span>' + '# } #' + '# if(resizable && !data.head && !data.middle) {#' + '<span class="k-resize-handle k-resize-s"></span>' + '# } #' + '</div>';
        function toInvariantTime(date) {
            var staticDate = new Date(1980, 1, 1, 0, 0, 0);
            setTime(staticDate, getMilliseconds(date));
            return staticDate;
        }
        function isInDateRange(value, min, max) {
            return value >= min && value <= max;
        }
        function isInTimeRange(value, min, max, overlaps) {
            overlaps = overlaps ? value <= max : value < max;
            return value > min && overlaps;
        }
        function addContinuousEvent(group, range, element, isAllDay) {
            var events = group._continuousEvents;
            var lastEvent = events[events.length - 1];
            var startDate = getDate(range.start.startDate()).getTime();
            if (isAllDay && lastEvent && getDate(lastEvent.start.startDate()).getTime() == startDate) {
                var idx = events.length - 1;
                for (; idx > -1; idx--) {
                    if (events[idx].isAllDay || getDate(events[idx].start.startDate()).getTime() < startDate) {
                        break;
                    }
                }
                events.splice(idx + 1, 0, {
                    element: element,
                    isAllDay: true,
                    uid: element.attr(kendo.attr('uid')),
                    start: range.start,
                    end: range.end
                });
            } else {
                events.push({
                    element: element,
                    isAllDay: isAllDay,
                    uid: element.attr(kendo.attr('uid')),
                    start: range.start,
                    end: range.end
                });
            }
        }
        function getWorkDays(options) {
            var workDays = [];
            var dayIndex = options.workWeekStart;
            workDays.push(dayIndex);
            while (options.workWeekEnd != dayIndex) {
                if (dayIndex > 6) {
                    dayIndex -= 7;
                } else {
                    dayIndex++;
                }
                workDays.push(dayIndex);
            }
            return workDays;
        }
        var MultiDayView = SchedulerView.extend({
            init: function (element, options) {
                var that = this;
                SchedulerView.fn.init.call(that, element, options);
                that.title = that.options.title || that.options.name;
                that._workDays = getWorkDays(that.options);
                that._templates();
                that._editable();
                that.calculateDateRange();
                that._groups();
                that._currentTime(true);
            },
            _currentTimeMarkerUpdater: function () {
                this._updateCurrentTimeMarker(new Date());
            },
            _updateCurrentTimeMarker: function (currentTime) {
                var options = this.options;
                if (options.currentTimeMarker.useLocalTimezone === false) {
                    var timezone = options.dataSource.options.schema.timezone;
                    if (options.dataSource && timezone) {
                        var timezoneOffset = kendo.timezone.offset(currentTime, timezone);
                        currentTime = kendo.timezone.convert(currentTime, currentTime.getTimezoneOffset(), timezoneOffset);
                    }
                }
                this.times.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                this.content.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                var groupsCount = !options.group || options.group.orientation == 'horizontal' ? 1 : this.groups.length;
                var firstTimesCell = this.times.find('tr:first th:first');
                var lastTimesCell = this.times.find('tr:first th:last');
                for (var groupIndex = 0; groupIndex < groupsCount; groupIndex++) {
                    var currentGroup = this.groups[groupIndex];
                    if (!currentGroup) {
                        return;
                    }
                    var utcCurrentTime = kendo.date.toUtcTime(currentTime);
                    var ranges = currentGroup.timeSlotRanges(utcCurrentTime, utcCurrentTime + 1);
                    if (ranges.length === 0) {
                        return;
                    }
                    var collection = ranges[0].collection;
                    var slotElement = collection.slotByStartDate(currentTime);
                    if (slotElement) {
                        var elementHtml = '<div class=\'' + CURRENT_TIME_MARKER_CLASS + '\'></div>';
                        var timesTableMarker = $(elementHtml).prependTo(this.times);
                        var markerTopPosition = Math.round(ranges[0].innerRect(currentTime, new Date(currentTime.getTime() + 1), false).top);
                        var timesTableMarkerCss = {};
                        if (this._isRtl) {
                            timesTableMarkerCss.right = firstTimesCell.position().left + outerHeight(firstTimesCell) - outerHeight(lastTimesCell);
                            timesTableMarker.addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-left');
                        } else {
                            timesTableMarkerCss.left = lastTimesCell.position().left;
                            timesTableMarker.addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-right');
                        }
                        timesTableMarkerCss.top = markerTopPosition - outerWidth(timesTableMarker) * BORDER_SIZE_COEFF / 2;
                        timesTableMarker.css(timesTableMarkerCss);
                        $(elementHtml).prependTo(this.content).css({
                            top: markerTopPosition,
                            height: '1px',
                            right: '1px',
                            width: this.content[0].scrollWidth,
                            left: 0
                        });
                    }
                }
            },
            _currentTime: function (setUpdateTimer) {
                var that = this;
                var markerOptions = that.options.currentTimeMarker;
                if (markerOptions !== false && markerOptions.updateInterval !== undefined) {
                    that._currentTimeMarkerUpdater();
                    if (setUpdateTimer) {
                        that._currentTimeUpdateTimer = setInterval(proxy(this._currentTimeMarkerUpdater, that), markerOptions.updateInterval);
                    }
                }
            },
            _updateResizeHint: function (event, groupIndex, startTime, endTime) {
                var multiday = event.isMultiDay();
                var group = this.groups[groupIndex];
                var ranges = group.ranges(startTime, endTime, multiday, event.isAllDay);
                var width, height, top, hint;
                this._removeResizeHint();
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    var range = ranges[rangeIndex];
                    var start = range.startSlot();
                    if (this._isGroupedByDate() && multiday) {
                        for (var slotIdx = start.index; slotIdx <= range.end.index; slotIdx++) {
                            var slot = range.collection._slots[slotIdx];
                            width = slot.offsetWidth;
                            height = slot.clientHeight;
                            top = slot.offsetTop;
                            hint = SchedulerView.fn._createResizeHint.call(this, slot.offsetLeft, top, width, height);
                            this._resizeHint = this._resizeHint.add(hint);
                        }
                    } else {
                        width = start.offsetWidth;
                        height = start.clientHeight;
                        top = start.offsetTop;
                        if (multiday) {
                            width = range.innerWidth();
                        } else {
                            var rect = range.outerRect(startTime, endTime, this.options.snap);
                            top = rect.top;
                            height = rect.bottom - rect.top;
                        }
                        hint = SchedulerView.fn._createResizeHint.call(this, start.offsetLeft, top, width, height);
                        this._resizeHint = this._resizeHint.add(hint);
                    }
                }
                var format = 't';
                var container = this.content;
                if (multiday) {
                    format = 'M/dd';
                    container = this.element.find('.k-scheduler-header-wrap:has(.k-scheduler-header-all-day) > div');
                    if (!container.length) {
                        container = this.content;
                    }
                }
                this._resizeHint.appendTo(container);
                this._resizeHint.find('.k-label-top,.k-label-bottom').text('');
                this._resizeHint.first().addClass('k-first').find('.k-label-top').text(kendo.toString(kendo.timezone.toLocalDate(startTime), format));
                this._resizeHint.last().addClass('k-last').find('.k-label-bottom').text(kendo.toString(kendo.timezone.toLocalDate(endTime), format));
            },
            _updateMoveHint: function (event, groupIndex, distance) {
                var multiday = event.isMultiDay();
                var group = this.groups[groupIndex];
                var start = kendo.date.toUtcTime(event.start) + distance;
                var end = start + event.duration();
                var ranges = group.ranges(start, end, multiday, event.isAllDay);
                start = kendo.timezone.toLocalDate(start);
                end = kendo.timezone.toLocalDate(end);
                this._removeMoveHint();
                if (!multiday && (getMilliseconds(end) === 0 || getMilliseconds(end) < getMilliseconds(this.startTime()))) {
                    if (ranges.length > 1) {
                        ranges.pop();
                    }
                }
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    var range = ranges[rangeIndex];
                    var startSlot = range.start;
                    var hint;
                    var css = {
                        left: startSlot.offsetLeft + 2,
                        top: startSlot.offsetTop
                    };
                    if (this._isGroupedByDate() && multiday) {
                        for (var slotIdx = startSlot.index; slotIdx <= range.end.index; slotIdx++) {
                            var slot = range.collection._slots[slotIdx];
                            css.left = this._isRtl ? slot.clientWidth * 0.1 + slot.offsetLeft + 2 : slot.offsetLeft + 2;
                            css.height = slot.offsetHeight;
                            css.width = slot.clientWidth * 0.9 - 4;
                            hint = this._createEventElement(event.clone({
                                start: start,
                                end: end
                            }), !multiday);
                            this._appendMoveHint(hint, css);
                        }
                    } else {
                        if (this._isRtl) {
                            css.left = startSlot.clientWidth * 0.1 + startSlot.offsetLeft + 2;
                        }
                        if (multiday) {
                            css.width = range.innerWidth() - 4;
                        } else {
                            var rect = range.outerRect(start, end, this.options.snap);
                            css.top = rect.top;
                            css.height = rect.bottom - rect.top;
                            css.width = startSlot.clientWidth * 0.9 - 4;
                        }
                        hint = this._createEventElement(event.clone({
                            start: start,
                            end: end
                        }), !multiday);
                        this._appendMoveHint(hint, css);
                    }
                }
                var content = this.content;
                if (multiday) {
                    content = this.element.find('.k-scheduler-header-wrap:has(.k-scheduler-header-all-day) > div');
                    if (!content.length) {
                        content = this.content;
                    }
                }
                this._moveHint.appendTo(content);
            },
            _appendMoveHint: function (hint, css) {
                hint.addClass('k-event-drag-hint');
                hint.css(css);
                this._moveHint = this._moveHint.add(hint);
            },
            _slotByPosition: function (x, y) {
                var slot, offset;
                if (this._isVerticallyGrouped()) {
                    offset = this.content.offset();
                    y += this.content[0].scrollTop;
                    x += this.content[0].scrollLeft;
                } else {
                    offset = this.element.find('.k-scheduler-header-wrap:has(.k-scheduler-header-all-day)').find('>div').offset();
                }
                if (offset) {
                    x -= offset.left;
                    y -= offset.top;
                }
                x = Math.ceil(x);
                y = Math.ceil(y);
                var group;
                var groupIndex;
                for (groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    group = this.groups[groupIndex];
                    slot = group.daySlotByPosition(x, y, this._isGroupedByDate());
                    if (slot) {
                        return slot;
                    }
                }
                if (offset) {
                    x += offset.left;
                    y += offset.top;
                }
                offset = this.content.offset();
                x -= offset.left;
                y -= offset.top;
                if (!this._isVerticallyGrouped()) {
                    y += this.content[0].scrollTop;
                    x += this.content[0].scrollLeft;
                }
                x = Math.ceil(x);
                y = Math.ceil(y);
                for (groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    group = this.groups[groupIndex];
                    slot = group.timeSlotByPosition(x, y);
                    if (slot) {
                        return slot;
                    }
                }
                return null;
            },
            _groupCount: function () {
                var resources = this.groupedResources;
                var byDate = this._isGroupedByDate();
                if (resources.length) {
                    if (this._groupOrientation() === 'vertical') {
                        if (byDate) {
                            return this._columnCountForLevel(resources.length - 1);
                        } else {
                            return this._rowCountForLevel(resources.length - 1);
                        }
                    } else {
                        if (byDate) {
                            return this._columnCountForLevel(resources.length) / this._columnCountForLevel(0);
                        } else {
                            return this._columnCountForLevel(resources.length) / this._columnOffsetForResource(resources.length);
                        }
                    }
                }
                return 1;
            },
            _columnCountInResourceView: function () {
                var resources = this.groupedResources;
                var byDate = this._isGroupedByDate();
                if (!resources.length || this._isVerticallyGrouped()) {
                    if (byDate) {
                        return this._rowCountForLevel(0);
                    } else {
                        return this._columnCountForLevel(0);
                    }
                }
                if (byDate) {
                    return this._columnCountForLevel(0);
                } else {
                    return this._columnOffsetForResource(resources.length);
                }
            },
            _timeSlotGroups: function (groupCount, columnCount) {
                var interval = this._timeSlotInterval();
                var verticalViews = groupCount;
                var byDate = this._isGroupedByDate();
                var tableRows = this.content.find('tr:not(.k-scheduler-header-all-day)');
                var group, time, rowIndex, cellIndex;
                tableRows.attr('role', 'row');
                var rowCount = tableRows.length;
                if (this._isVerticallyGrouped()) {
                    if (byDate) {
                        verticalViews = columnCount;
                    }
                    rowCount = Math.floor(rowCount / verticalViews);
                }
                for (var groupIndex = 0; groupIndex < verticalViews; groupIndex++) {
                    var rowMultiplier = 0;
                    var cellMultiplier = 0;
                    if (this._isVerticallyGrouped()) {
                        rowMultiplier = groupIndex;
                    } else {
                        cellMultiplier = groupIndex;
                    }
                    rowIndex = rowMultiplier * rowCount;
                    while (rowIndex < (rowMultiplier + 1) * rowCount) {
                        var cells = tableRows[rowIndex].children;
                        if (rowIndex % rowCount === 0) {
                            time = getMilliseconds(new Date(+this.startTime()));
                        }
                        var timeIndex = 0;
                        if (byDate) {
                            if (this._isVerticallyGrouped()) {
                                for (cellIndex = 0; cellIndex < groupCount; cellIndex++) {
                                    group = this.groups[cellIndex];
                                    this._addTimeSlotGroup(group, cells, cellIndex, time, interval, groupIndex);
                                }
                            } else {
                                group = this.groups[groupIndex];
                                for (cellIndex = cellMultiplier; cellIndex < groupCount * columnCount; cellIndex = cellIndex + groupCount) {
                                    this._addTimeSlotGroup(group, cells, cellIndex, time, interval, timeIndex);
                                    timeIndex++;
                                }
                            }
                        } else {
                            group = this.groups[groupIndex];
                            for (cellIndex = cellMultiplier * columnCount; cellIndex < (cellMultiplier + 1) * columnCount; cellIndex++) {
                                this._addTimeSlotGroup(group, cells, cellIndex, time, interval, timeIndex);
                                timeIndex++;
                            }
                        }
                        time += interval;
                        rowIndex++;
                    }
                }
            },
            _addTimeSlotGroup: function (group, cells, cellIndex, time, interval, timeIndex) {
                var cell = cells[cellIndex];
                var collection = group.getTimeSlotCollection(timeIndex);
                var currentDate = this._dates[timeIndex];
                var currentTime = Date.UTC(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate());
                var start = currentTime + time;
                var end = start + interval;
                cell.setAttribute('role', 'gridcell');
                cell.setAttribute('aria-selected', false);
                collection.addTimeSlot(cell, start, end);
            },
            _addDaySlotGroup: function (collection, cells, cellIndex, columnCount, cellCount) {
                var cell = cells[cellIndex];
                var start = this._dates[cellCount];
                var currentTime = Date.UTC(start.getFullYear(), start.getMonth(), start.getDate());
                cell.setAttribute('role', 'gridcell');
                cell.setAttribute('aria-selected', false);
                collection.addDaySlot(cell, currentTime, currentTime + kendo.date.MS_PER_DAY);
            },
            _daySlotGroups: function (groupCount, columnCount) {
                var tableRows, cellIndex;
                var verticalViews = groupCount;
                var byDate = this._isGroupedByDate();
                if (this._isVerticallyGrouped()) {
                    if (byDate) {
                        verticalViews = columnCount;
                    }
                    tableRows = this.element.find('.k-scheduler-header-all-day');
                } else {
                    tableRows = this.element.find('.k-scheduler-header-all-day tr');
                }
                tableRows.attr('role', 'row');
                for (var groupIndex = 0; groupIndex < verticalViews; groupIndex++) {
                    var rowMultiplier = 0;
                    var group, collection;
                    if (this._isVerticallyGrouped()) {
                        rowMultiplier = groupIndex;
                    }
                    var cells = tableRows[rowMultiplier].children;
                    var cellMultiplier = 0;
                    if (!this._isVerticallyGrouped()) {
                        cellMultiplier = groupIndex;
                    }
                    var cellCount = 0;
                    if (byDate) {
                        if (this._isVerticallyGrouped()) {
                            for (cellIndex = 0; cellIndex < groupCount; cellIndex++) {
                                group = this.groups[cellIndex];
                                collection = group.getDaySlotCollection(0);
                                this._addDaySlotGroup(collection, cells, cellIndex, columnCount, groupIndex);
                            }
                        } else {
                            group = this.groups[groupIndex];
                            collection = group.getDaySlotCollection(0);
                            for (cellIndex = cellMultiplier; cellIndex < groupCount * columnCount; cellIndex = cellIndex + groupCount) {
                                this._addDaySlotGroup(collection, cells, cellIndex, columnCount, cellCount);
                                cellCount++;
                            }
                        }
                    } else {
                        group = this.groups[groupIndex];
                        collection = group.getDaySlotCollection(0);
                        for (cellIndex = cellMultiplier * columnCount; cellIndex < (cellMultiplier + 1) * columnCount; cellIndex++) {
                            this._addDaySlotGroup(collection, cells, cellIndex, columnCount, cellCount);
                            cellCount++;
                        }
                    }
                }
            },
            _groups: function () {
                var groupCount = this._groupCount();
                var columnCount = this._columnCountInResourceView();
                this.groups = [];
                for (var idx = 0; idx < groupCount; idx++) {
                    var view = this._addResourceView(idx);
                    for (var columnIndex = 0; columnIndex < columnCount; columnIndex++) {
                        view.addTimeSlotCollection(this._dates[columnIndex], kendo.date.addDays(this._dates[columnIndex], 1));
                    }
                    if (this.options.allDaySlot) {
                        view.addDaySlotCollection(this._dates[0], kendo.date.addDays(this._dates[this._dates.length - 1], 1));
                    }
                }
                this._timeSlotGroups(groupCount, columnCount);
                if (this.options.allDaySlot) {
                    this._daySlotGroups(groupCount, columnCount);
                }
            },
            options: {
                name: 'MultiDayView',
                selectedDateFormat: '{0:D}',
                selectedShortDateFormat: '{0:d}',
                allDaySlot: true,
                showWorkHours: false,
                title: '',
                startTime: kendo.date.today(),
                endTime: kendo.date.today(),
                minorTickCount: 2,
                majorTick: 60,
                majorTimeHeaderTemplate: '#=kendo.toString(date, \'t\')#',
                minorTimeHeaderTemplate: '&\\#8203;',
                groupHeaderTemplate: '#=text#',
                slotTemplate: '&nbsp;',
                allDaySlotTemplate: '&nbsp;',
                eventTemplate: DAY_VIEW_EVENT_TEMPLATE,
                allDayEventTemplate: DAY_VIEW_ALL_DAY_EVENT_TEMPLATE,
                dateHeaderTemplate: DATA_HEADER_TEMPLATE,
                editable: true,
                workDayStart: new Date(1980, 1, 1, 8, 0, 0),
                workDayEnd: new Date(1980, 1, 1, 17, 0, 0),
                workWeekStart: 1,
                workWeekEnd: 5,
                footer: { command: 'workDay' },
                messages: {
                    allDay: 'all day',
                    showFullDay: 'Show full day',
                    showWorkDay: 'Show business hours'
                },
                currentTimeMarker: {
                    updateInterval: 10000,
                    useLocalTimezone: true
                }
            },
            events: [
                'remove',
                'add',
                'edit'
            ],
            _templates: function () {
                var options = this.options, settings = extend({}, kendo.Template, options.templateSettings);
                this.eventTemplate = this._eventTmpl(options.eventTemplate, EVENT_WRAPPER_STRING);
                this.allDayEventTemplate = this._eventTmpl(options.allDayEventTemplate, ALLDAY_EVENT_WRAPPER_STRING);
                this.majorTimeHeaderTemplate = kendo.template(options.majorTimeHeaderTemplate, settings);
                this.minorTimeHeaderTemplate = kendo.template(options.minorTimeHeaderTemplate, settings);
                this.dateHeaderTemplate = kendo.template(options.dateHeaderTemplate, settings);
                this.slotTemplate = kendo.template(options.slotTemplate, settings);
                this.allDaySlotTemplate = kendo.template(options.allDaySlotTemplate, settings);
                this.groupHeaderTemplate = kendo.template(options.groupHeaderTemplate, settings);
            },
            _editable: function () {
                if (this.options.editable) {
                    if (this._isMobile()) {
                        this._touchEditable();
                    } else {
                        this._mouseEditable();
                    }
                }
            },
            _mouseEditable: function () {
                var that = this;
                that.element.on('click' + NS, '.k-event a:has(.k-i-close)', function (e) {
                    that.trigger('remove', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                    e.preventDefault();
                });
                if (that.options.editable.create !== false) {
                    that.element.on('dblclick' + NS, '.k-scheduler-content td', function (e) {
                        if (!$(this).parent().hasClass('k-scheduler-header-all-day')) {
                            var slot = that._slotByPosition(e.pageX, e.pageY);
                            if (slot) {
                                var resourceInfo = that._resourceBySlot(slot);
                                that.trigger('add', {
                                    eventInfo: extend({
                                        start: slot.startDate(),
                                        end: slot.endDate()
                                    }, resourceInfo)
                                });
                            }
                            e.preventDefault();
                        }
                    }).on('dblclick' + NS, '.k-scheduler-header-all-day td', function (e) {
                        var slot = that._slotByPosition(e.pageX, e.pageY);
                        if (slot) {
                            var resourceInfo = that._resourceBySlot(slot);
                            that.trigger('add', {
                                eventInfo: extend({}, {
                                    isAllDay: true,
                                    start: kendo.date.getDate(slot.startDate()),
                                    end: kendo.date.getDate(slot.startDate())
                                }, resourceInfo)
                            });
                        }
                        e.preventDefault();
                    });
                }
                if (that.options.editable.update !== false) {
                    that.element.on('dblclick' + NS, '.k-event', function (e) {
                        that.trigger('edit', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                        e.preventDefault();
                    });
                }
            },
            _touchEditable: function () {
                var that = this;
                var threshold = 0;
                if (kendo.support.mobileOS.android) {
                    threshold = 5;
                }
                if (that.options.editable.create !== false) {
                    that._addUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        filter: '.k-scheduler-content td',
                        tap: function (e) {
                            if (!$(e.target).parent().hasClass('k-scheduler-header-all-day')) {
                                var x = e.x.location !== undefined ? e.x.location : e.x;
                                var y = e.y.location !== undefined ? e.y.location : e.y;
                                var slot = that._slotByPosition(x, y);
                                if (slot) {
                                    var resourceInfo = that._resourceBySlot(slot);
                                    that.trigger('add', {
                                        eventInfo: extend({
                                            start: slot.startDate(),
                                            end: slot.endDate()
                                        }, resourceInfo)
                                    });
                                }
                                e.preventDefault();
                            }
                        }
                    });
                    that._allDayUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        filter: '.k-scheduler-header-all-day td',
                        tap: function (e) {
                            var x = e.x.location !== undefined ? e.x.location : e.x;
                            var y = e.y.location !== undefined ? e.y.location : e.y;
                            var slot = that._slotByPosition(x, y);
                            if (slot) {
                                var resourceInfo = that._resourceBySlot(slot);
                                that.trigger('add', {
                                    eventInfo: extend({}, {
                                        isAllDay: true,
                                        start: kendo.date.getDate(slot.startDate()),
                                        end: kendo.date.getDate(slot.startDate())
                                    }, resourceInfo)
                                });
                            }
                            e.preventDefault();
                        }
                    });
                }
                if (that.options.editable.update !== false) {
                    that._editUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        filter: '.k-event',
                        tap: function (e) {
                            var eventElement = $(e.target).closest('.k-event');
                            if (!eventElement.hasClass('k-event-active')) {
                                that.trigger('edit', { uid: eventElement.attr(kendo.attr('uid')) });
                            }
                            e.preventDefault();
                        }
                    });
                }
            },
            _layout: function (dates) {
                var columns = [];
                var rows = [];
                var options = this.options;
                var that = this;
                var byDate = that._isGroupedByDate();
                for (var idx = 0; idx < dates.length; idx++) {
                    var column = {};
                    column.text = that.dateHeaderTemplate({ date: dates[idx] });
                    if (kendo.date.isToday(dates[idx])) {
                        column.className = 'k-today';
                    }
                    columns.push(column);
                }
                var resources = this.groupedResources;
                if (options.allDaySlot) {
                    rows.push({
                        text: options.messages.allDay,
                        allDay: true,
                        cellContent: function (idx) {
                            var groupIndex = idx;
                            idx = resources.length && that._groupOrientation() !== 'vertical' ? idx % dates.length : idx;
                            return that.allDaySlotTemplate({
                                date: dates[idx],
                                resources: function () {
                                    return that._resourceBySlot({ groupIndex: groupIndex });
                                }
                            });
                        }
                    });
                }
                this._forTimeRange(this.startTime(), this.endTime(), function (date, majorTick, middleRow, lastSlotRow) {
                    var template = majorTick ? that.majorTimeHeaderTemplate : that.minorTimeHeaderTemplate;
                    var row = {
                        text: template({ date: date }),
                        className: lastSlotRow ? 'k-slot-cell' : ''
                    };
                    rows.push(row);
                });
                if (resources.length) {
                    if (this._groupOrientation() === 'vertical') {
                        if (byDate) {
                            rows = this._createDateLayout(columns, rows);
                            columns = this._createColumnsLayout(resources, null, this.groupHeaderTemplate);
                        } else {
                            rows = this._createRowsLayout(resources, rows, this.groupHeaderTemplate);
                        }
                    } else {
                        if (byDate) {
                            columns = this._createColumnsLayout(resources, columns, this.groupHeaderTemplate, columns);
                        } else {
                            columns = this._createColumnsLayout(resources, columns, this.groupHeaderTemplate);
                        }
                    }
                }
                return {
                    columns: columns,
                    rows: rows
                };
            },
            _footer: function () {
                var options = this.options;
                if (options.footer !== false) {
                    var html = '<div class="k-header k-scheduler-footer">';
                    var command = options.footer.command;
                    if (command && command === 'workDay') {
                        html += '<ul class="k-reset k-header">';
                        html += '<li class="k-state-default k-scheduler-fullday"><a href="#" class="k-link"><span class="k-icon k-i-clock"></span>';
                        html += (options.showWorkHours ? options.messages.showFullDay : options.messages.showWorkDay) + '</a></li>';
                        html += '</ul>';
                    } else {
                        html += '&nbsp;';
                    }
                    html += '</div>';
                    this.footer = $(html).appendTo(this.element);
                    var that = this;
                    this.footer.on('click' + NS, '.k-scheduler-fullday', function (e) {
                        e.preventDefault();
                        that.trigger('navigate', {
                            view: that.name || options.name,
                            date: options.date,
                            isWorkDay: !options.showWorkHours
                        });
                    });
                }
            },
            _forTimeRange: function (min, max, action, after) {
                min = toInvariantTime(min);
                max = toInvariantTime(max);
                var that = this, msMin = getMilliseconds(min), msMax = getMilliseconds(max), minorTickCount = that.options.minorTickCount, msMajorInterval = that.options.majorTick * MS_PER_MINUTE, msInterval = msMajorInterval / minorTickCount || 1, start = new Date(+min), startDay = start.getDate(), msStart, idx = 0, length, html = '';
                length = MS_PER_DAY / msInterval;
                if (msMin != msMax) {
                    if (msMin > msMax) {
                        msMax += MS_PER_DAY;
                    }
                    length = (msMax - msMin) / msInterval;
                }
                length = Math.round(length);
                for (; idx < length; idx++) {
                    var majorTickDivider = idx % (msMajorInterval / msInterval), isMajorTickRow = majorTickDivider === 0, isMiddleRow = majorTickDivider < minorTickCount - 1, isLastSlotRow = majorTickDivider === minorTickCount - 1;
                    html += action(start, isMajorTickRow, isMiddleRow, isLastSlotRow);
                    setTime(start, msInterval, false);
                }
                if (msMax) {
                    msStart = getMilliseconds(start);
                    if (startDay < start.getDate()) {
                        msStart += MS_PER_DAY;
                    }
                    if (msStart > msMax) {
                        start = new Date(+max);
                    }
                }
                if (after) {
                    html += after(start);
                }
                return html;
            },
            _content: function (dates) {
                var that = this;
                var options = that.options;
                var start = that.startTime();
                var end = this.endTime();
                var groupsCount = 1;
                var rowCount = 1;
                var columnCount = dates.length;
                var html = '';
                var resources = this.groupedResources;
                var allDaySlotTemplate = this.allDaySlotTemplate;
                var isVerticalGroupped = false;
                var allDayVerticalGroupRow;
                var byDate = that._isGroupedByDate();
                var dateID = 0;
                if (resources.length) {
                    isVerticalGroupped = that._groupOrientation() === 'vertical';
                    if (isVerticalGroupped) {
                        rowCount = this._rowCountForLevel(this.rowLevels.length - 2);
                        if (byDate) {
                            groupsCount = this._columnCountForLevel(this.columnLevels.length - 1);
                        }
                        if (options.allDaySlot) {
                            allDayVerticalGroupRow = function (groupIndex) {
                                var result = '<tr class="k-scheduler-header-all-day">';
                                var dateGroupIndex = byDate ? 0 : groupIndex;
                                var resources = function () {
                                    return that._resourceBySlot({ groupIndex: dateGroupIndex });
                                };
                                if (byDate) {
                                    for (; dateGroupIndex < groupsCount; dateGroupIndex++) {
                                        result += '<td>' + allDaySlotTemplate({
                                            date: dates[dateID],
                                            resources: resources
                                        }) + '</td>';
                                    }
                                } else {
                                    for (var idx = 0; idx < dates.length; idx++) {
                                        result += '<td>' + allDaySlotTemplate({
                                            date: dates[idx],
                                            resources: resources
                                        }) + '</td>';
                                    }
                                }
                                return result + '</tr>';
                            };
                        }
                    } else {
                        if (byDate) {
                            groupsCount = this._columnCountForLevel(this.columnLevels.length - 1) / this._columnCountForLevel(0);
                        } else {
                            groupsCount = this._columnCountForLevel(this.columnLevels.length - 2);
                        }
                    }
                }
                html += '<tbody>';
                var appendRow = function (date, majorTick) {
                    var content = '';
                    var groupIdx = 0;
                    var idx, length;
                    content = '<tr' + (majorTick ? ' class="k-middle-row"' : '') + '>';
                    if (byDate) {
                        for (idx = 0, length = columnCount; idx < length; idx++) {
                            for (groupIdx = 0; groupIdx < groupsCount; groupIdx++) {
                                var dateIndex = idx;
                                if (isVerticalGroupped) {
                                    dateIndex = dateID;
                                }
                                content = that._addCellsToContent(content, dates, date, dateIndex, groupIdx, rowIdx);
                            }
                            if (isVerticalGroupped) {
                                break;
                            }
                        }
                    } else {
                        for (; groupIdx < groupsCount; groupIdx++) {
                            for (idx = 0, length = columnCount; idx < length; idx++) {
                                content = that._addCellsToContent(content, dates, date, idx, groupIdx, rowIdx);
                            }
                        }
                    }
                    content += '</tr>';
                    return content;
                };
                for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
                    html += allDayVerticalGroupRow ? allDayVerticalGroupRow(rowIdx) : '';
                    html += this._forTimeRange(start, end, appendRow);
                    if (isVerticalGroupped) {
                        dateID++;
                    }
                }
                html += '</tbody>';
                this.content.find('table').append(html);
            },
            _addCellsToContent: function (content, dates, date, idx, groupIdx, rowIdx) {
                var that = this;
                var classes = '';
                var tmplDate;
                var slotTemplate = this.slotTemplate;
                var isVerticalGroupped = this._groupOrientation() === 'vertical';
                var resources = function (groupIndex) {
                    return function () {
                        return that._resourceBySlot({ groupIndex: groupIndex });
                    };
                };
                if (kendo.date.isToday(dates[idx])) {
                    classes += 'k-today';
                }
                if (kendo.date.getMilliseconds(date) < kendo.date.getMilliseconds(this.options.workDayStart) || kendo.date.getMilliseconds(date) >= kendo.date.getMilliseconds(this.options.workDayEnd) || !this._isWorkDay(dates[idx])) {
                    classes += ' k-nonwork-hour';
                }
                content += '<td' + (classes !== '' ? ' class="' + classes + '"' : '') + '>';
                tmplDate = kendo.date.getDate(dates[idx]);
                kendo.date.setTime(tmplDate, kendo.date.getMilliseconds(date));
                content += slotTemplate({
                    date: tmplDate,
                    resources: resources(isVerticalGroupped && !that._isGroupedByDate() ? rowIdx : groupIdx)
                });
                content += '</td>';
                return content;
            },
            _isWorkDay: function (date) {
                var day = date.getDay();
                var workDays = this._workDays;
                for (var i = 0; i < workDays.length; i++) {
                    if (workDays[i] === day) {
                        return true;
                    }
                }
                return false;
            },
            _render: function (dates) {
                var that = this;
                dates = dates || [];
                this._dates = dates;
                this._startDate = dates[0];
                this._endDate = dates[dates.length - 1 || 0];
                this.createLayout(this._layout(dates));
                this._content(dates);
                this._footer();
                this.refreshLayout();
                var allDayHeader = this.element.find('.k-scheduler-header-all-day td');
                if (allDayHeader.length) {
                    this._allDayHeaderHeight = allDayHeader.first()[0].clientHeight;
                }
                that.element.on('click' + NS, '.k-nav-day', function (e) {
                    var th = $(e.currentTarget).closest('th');
                    var offset = th.offset();
                    var additioanlWidth = 0;
                    var additionalHeight = outerHeight(th);
                    if (that._isGroupedByDate()) {
                        if (that._isVerticallyGrouped()) {
                            additioanlWidth = outerWidth(that.times);
                            additionalHeight = 0;
                        } else {
                            additionalHeight = outerHeight(that.datesHeader);
                        }
                    }
                    var slot = that._slotByPosition(offset.left + additioanlWidth, offset.top + additionalHeight);
                    that.trigger('navigate', {
                        view: 'day',
                        date: slot.startDate()
                    });
                });
            },
            startTime: function () {
                var options = this.options;
                return options.showWorkHours ? options.workDayStart : options.startTime;
            },
            endTime: function () {
                var options = this.options;
                return options.showWorkHours ? options.workDayEnd : options.endTime;
            },
            startDate: function () {
                return this._startDate;
            },
            endDate: function () {
                return this._endDate;
            },
            _end: function (isAllDay) {
                var time = getMilliseconds(this.endTime()) || MS_PER_DAY;
                if (isAllDay) {
                    time = 0;
                }
                return new Date(this._endDate.getTime() + time);
            },
            nextDate: function () {
                return kendo.date.nextDay(this.endDate());
            },
            previousDate: function () {
                return kendo.date.previousDay(this.startDate());
            },
            calculateDateRange: function () {
                this._render([this.options.date]);
            },
            destroy: function () {
                var that = this;
                if (that._currentTimeUpdateTimer) {
                    clearInterval(that._currentTimeUpdateTimer);
                }
                if (that.datesHeader) {
                    that.datesHeader.off(NS);
                }
                if (that.element) {
                    that.element.off(NS);
                }
                if (that.footer) {
                    that.footer.remove();
                }
                SchedulerView.fn.destroy.call(this);
                if (this._isMobile() && that.options.editable) {
                    if (that.options.editable.create !== false) {
                        that._addUserEvents.destroy();
                        that._allDayUserEvents.destroy();
                    }
                    if (that.options.editable.update !== false) {
                        that._editUserEvents.destroy();
                    }
                }
            },
            inRange: function (options) {
                var inRange = SchedulerView.fn.inRange.call(this, options);
                if (options.isAllDay) {
                    return inRange;
                }
                var startTime = getMilliseconds(this.startTime());
                var endTime = getMilliseconds(this.endTime()) || kendo.date.MS_PER_DAY;
                var start = getMilliseconds(options.start);
                var end = getMilliseconds(options.end) || kendo.date.MS_PER_DAY;
                return inRange && startTime <= start && end <= endTime;
            },
            selectionByElement: function (cell) {
                var offset = cell.offset();
                return this._slotByPosition(offset.left, offset.top);
            },
            _timeSlotInterval: function () {
                var options = this.options;
                return options.majorTick / options.minorTickCount * MS_PER_MINUTE;
            },
            _timeSlotIndex: function (date) {
                var options = this.options;
                var eventStartTime = getMilliseconds(date);
                var startTime = getMilliseconds(this.startTime());
                var timeSlotInterval = options.majorTick / options.minorTickCount * MS_PER_MINUTE;
                return (eventStartTime - startTime) / timeSlotInterval;
            },
            _slotIndex: function (date, multiday) {
                if (multiday) {
                    return this._dateSlotIndex(date);
                }
                return this._timeSlotIndex(date);
            },
            _dateSlotIndex: function (date, overlaps) {
                var idx;
                var length;
                var slots = this._dates || [];
                var slotStart;
                var slotEnd;
                var offset = 1;
                for (idx = 0, length = slots.length; idx < length; idx++) {
                    slotStart = kendo.date.getDate(slots[idx]);
                    slotEnd = new Date(kendo.date.getDate(slots[idx]).getTime() + MS_PER_DAY - (overlaps ? 0 : 1));
                    if (isInDateRange(date, slotStart, slotEnd)) {
                        return idx * offset;
                    }
                }
                return -1;
            },
            _positionAllDayEvent: function (element, slotRange) {
                var slotWidth = slotRange.innerWidth();
                var startIndex = slotRange.start.index;
                var endIndex = slotRange.end.index;
                var allDayEvents = SchedulerView.collidingEvents(slotRange.events(), startIndex, endIndex);
                var currentColumnCount = this._headerColumnCount || 0;
                var leftOffset = 2;
                var rightOffset = startIndex !== endIndex ? 5 : 4;
                var eventHeight = this._allDayHeaderHeight;
                var start = slotRange.startSlot();
                element.css({
                    left: start.offsetLeft + leftOffset,
                    width: slotWidth - rightOffset
                });
                slotRange.addEvent({
                    slotIndex: startIndex,
                    start: startIndex,
                    end: endIndex,
                    element: element
                });
                allDayEvents.push({
                    slotIndex: startIndex,
                    start: startIndex,
                    end: endIndex,
                    element: element
                });
                var rows = SchedulerView.createRows(allDayEvents);
                if (rows.length && rows.length > currentColumnCount) {
                    this._headerColumnCount = rows.length;
                }
                var top = slotRange.start.offsetTop;
                for (var idx = 0, length = rows.length; idx < length; idx++) {
                    var rowEvents = rows[idx].events;
                    for (var j = 0, eventLength = rowEvents.length; j < eventLength; j++) {
                        $(rowEvents[j].element).css({ top: top + idx * eventHeight });
                    }
                }
            },
            _arrangeColumns: function (element, top, height, slotRange) {
                var startSlot = slotRange.start;
                element = {
                    element: element,
                    slotIndex: startSlot.index,
                    start: top,
                    end: top + height
                };
                var columns, slotWidth = startSlot.clientWidth, eventRightOffset = slotWidth * 0.1, columnEvents, eventElements = slotRange.events(), slotEvents = SchedulerView.collidingEvents(eventElements, element.start, element.end);
                slotRange.addEvent(element);
                slotEvents.push(element);
                columns = SchedulerView.createColumns(slotEvents);
                var columnWidth = (slotWidth - eventRightOffset) / columns.length;
                for (var idx = 0, length = columns.length; idx < length; idx++) {
                    columnEvents = columns[idx].events;
                    for (var j = 0, eventLength = columnEvents.length; j < eventLength; j++) {
                        columnEvents[j].element[0].style.width = columnWidth - 4 + 'px';
                        columnEvents[j].element[0].style.left = (this._isRtl ? eventRightOffset : 0) + startSlot.offsetLeft + idx * columnWidth + 2 + 'px';
                    }
                }
            },
            _positionEvent: function (event, element, slotRange) {
                var start = event._startTime || event.start;
                var end = event._endTime || event.end;
                var rect = slotRange.innerRect(start, end, false);
                var height = rect.bottom - rect.top - 2;
                if (height < 0) {
                    height = 0;
                }
                element.css({
                    top: rect.top,
                    height: height
                });
                this._arrangeColumns(element, rect.top, element[0].clientHeight, slotRange);
            },
            _createEventElement: function (event, isOneDayEvent, head, tail) {
                var template = isOneDayEvent ? this.eventTemplate : this.allDayEventTemplate;
                var options = this.options;
                var editable = options.editable;
                var isMobile = this._isMobile();
                var showDelete = editable && editable.destroy !== false && !isMobile;
                var resizable = editable && editable.resize !== false;
                var startDate = getDate(this.startDate());
                var endDate = getDate(this.endDate());
                var startTime = getMilliseconds(this.startTime());
                var endTime = getMilliseconds(this.endTime());
                var eventStartTime = event._time('start');
                var eventEndTime = event._time('end');
                var middle;
                if (startTime >= endTime) {
                    endTime = getMilliseconds(new Date(this.endTime().getTime() + MS_PER_DAY - 1));
                }
                if (!isOneDayEvent && !event.isAllDay) {
                    endDate = new Date(endDate.getTime() + MS_PER_DAY);
                }
                var eventStartDate = event.start;
                var eventEndDate = event.end;
                if (event.isAllDay) {
                    eventEndDate = getDate(event.end);
                }
                if (!isInDateRange(getDate(eventStartDate), startDate, endDate) && !isInDateRange(eventEndDate, startDate, endDate) || isOneDayEvent && eventStartTime < startTime && eventEndTime > endTime) {
                    middle = true;
                } else if (getDate(eventStartDate) < startDate || isOneDayEvent && eventStartTime < startTime) {
                    tail = true;
                } else if (eventEndDate > endDate && !isOneDayEvent || isOneDayEvent && eventEndTime > endTime) {
                    head = true;
                }
                var resources = this.eventResources(event);
                if (event._startTime && eventStartTime !== kendo.date.getMilliseconds(event.start)) {
                    eventStartDate = new Date(eventStartTime);
                    eventStartDate = kendo.timezone.apply(eventStartDate, 'Etc/UTC');
                }
                if (event._endTime && eventEndTime !== kendo.date.getMilliseconds(event.end)) {
                    eventEndDate = new Date(eventEndTime);
                    eventEndDate = kendo.timezone.apply(eventEndDate, 'Etc/UTC');
                }
                var data = extend({}, {
                    ns: kendo.ns,
                    resizable: resizable,
                    showDelete: showDelete,
                    middle: middle,
                    head: head,
                    tail: tail,
                    singleDay: this._dates.length == 1,
                    resources: resources,
                    inverseColor: resources && resources[0] ? this._shouldInverseResourceColor(resources[0]) : false,
                    messages: options.messages
                }, event, {
                    start: eventStartDate,
                    end: eventEndDate
                });
                var element = $(template(data));
                this.angular('compile', function () {
                    return {
                        elements: element,
                        data: [{ dataItem: data }]
                    };
                });
                return element;
            },
            _isInTimeSlot: function (event) {
                var slotStartTime = this.startTime(), slotEndTime = this.endTime(), startTime = event._startTime || event.start, endTime = event._endTime || event.end;
                if (getMilliseconds(slotEndTime) === getMilliseconds(kendo.date.getDate(slotEndTime))) {
                    slotEndTime = kendo.date.getDate(slotEndTime);
                    setTime(slotEndTime, MS_PER_DAY - 1);
                }
                if (event._date('end') > event._date('start')) {
                    endTime = +event._date('end') + (MS_PER_DAY - 1);
                }
                endTime = endTime - event._date('end');
                startTime = startTime - event._date('start');
                slotEndTime = getMilliseconds(slotEndTime);
                slotStartTime = getMilliseconds(slotStartTime);
                if (slotStartTime === startTime && startTime === endTime) {
                    return true;
                }
                var overlaps = startTime !== slotEndTime;
                return isInTimeRange(startTime, slotStartTime, slotEndTime, overlaps) || isInTimeRange(endTime, slotStartTime, slotEndTime, overlaps) || isInTimeRange(slotStartTime, startTime, endTime) || isInTimeRange(slotEndTime, startTime, endTime);
            },
            _isInDateSlot: function (event) {
                var groups = this.groups[0];
                var slotStart = groups.firstSlot().start;
                var slotEnd = groups.lastSlot().end - 1;
                var startTime = kendo.date.toUtcTime(event.start);
                var endTime = kendo.date.toUtcTime(event.end);
                return (isInDateRange(startTime, slotStart, slotEnd) || isInDateRange(endTime, slotStart, slotEnd) || isInDateRange(slotStart, startTime, endTime) || isInDateRange(slotEnd, startTime, endTime)) && (!isInDateRange(endTime, slotStart, slotStart) || isInDateRange(endTime, startTime, startTime) || event.isAllDay);
            },
            _updateAllDayHeaderHeight: function (height) {
                if (this._height !== height) {
                    this._height = height;
                    var allDaySlots = this.element.find('.k-scheduler-header-all-day td');
                    if (allDaySlots.length) {
                        allDaySlots.parent().add(this.element.find('.k-scheduler-times-all-day').parent()).height(height);
                        for (var groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                            this.groups[groupIndex].refresh();
                        }
                    }
                }
            },
            _renderEvents: function (events, groupIndex) {
                var allDayEventContainer = this.datesHeader.find('.k-scheduler-header-wrap > div');
                var byDate = this._isGroupedByDate();
                var event;
                var idx;
                var length;
                for (idx = 0, length = events.length; idx < length; idx++) {
                    event = events[idx];
                    if (this._isInDateSlot(event)) {
                        var isMultiDayEvent = event.isAllDay || event.end.getTime() - event.start.getTime() >= MS_PER_DAY;
                        var container = isMultiDayEvent && !this._isVerticallyGrouped() ? allDayEventContainer : this.content;
                        var element, ranges, range, start, end, group;
                        if (!isMultiDayEvent) {
                            if (this._isInTimeSlot(event)) {
                                group = this.groups[groupIndex];
                                if (!group._continuousEvents) {
                                    group._continuousEvents = [];
                                }
                                ranges = group.slotRanges(event);
                                var rangeCount = ranges.length;
                                for (var rangeIndex = 0; rangeIndex < rangeCount; rangeIndex++) {
                                    range = ranges[rangeIndex];
                                    start = event.start;
                                    end = event.end;
                                    if (rangeCount > 1) {
                                        if (rangeIndex === 0) {
                                            end = range.end.endDate();
                                        } else if (rangeIndex == rangeCount - 1) {
                                            start = range.start.startDate();
                                        } else {
                                            start = range.start.startDate();
                                            end = range.end.endDate();
                                        }
                                    }
                                    var occurrence = event.clone({
                                        start: start,
                                        end: end,
                                        _startTime: event._startTime,
                                        _endTime: event.endTime
                                    });
                                    if (this._isInTimeSlot(occurrence)) {
                                        var head = range.head;
                                        element = this._createEventElement(event, !isMultiDayEvent, head, range.tail);
                                        element.appendTo(container);
                                        this._positionEvent(occurrence, element, range);
                                        addContinuousEvent(group, range, element, false);
                                    }
                                }
                            }
                        } else if (this.options.allDaySlot) {
                            group = this.groups[groupIndex];
                            if (!group._continuousEvents) {
                                group._continuousEvents = [];
                            }
                            ranges = group.slotRanges(event);
                            if (ranges.length) {
                                range = ranges[0];
                                var startIndex = range.start.index;
                                var endIndex = range.end.index;
                                if (byDate && startIndex !== endIndex) {
                                    start = range.start.start;
                                    end = range.end.end;
                                    var newStart = new Date(start);
                                    var newEnd = new Date(start);
                                    for (var i = range.start.index; i <= range.end.index; i++) {
                                        element = this._createEventElement(event, !isMultiDayEvent, i !== endIndex, i !== startIndex);
                                        var dateRange = group.daySlotRanges(newStart, newEnd, true)[0];
                                        newEnd.setDate(newEnd.getDate() + 1);
                                        newStart.setDate(newStart.getDate() + 1);
                                        this._positionAllDayEvent(element, dateRange);
                                        addContinuousEvent(group, dateRange, element, true);
                                        element.appendTo(container);
                                    }
                                } else {
                                    element = this._createEventElement(event, !isMultiDayEvent);
                                    this._positionAllDayEvent(element, ranges[0]);
                                    addContinuousEvent(group, ranges[0], element, true);
                                    element.appendTo(container);
                                }
                            }
                        }
                    }
                }
            },
            render: function (events) {
                this._headerColumnCount = 0;
                this._groups();
                this.element.find('.k-event').remove();
                events = new kendo.data.Query(events).sort([
                    {
                        field: 'start',
                        dir: 'asc'
                    },
                    {
                        field: 'end',
                        dir: 'desc'
                    }
                ]).toArray();
                var eventsByResource = [];
                this._eventsByResource(events, this.groupedResources, eventsByResource);
                var eventsPerDate = $.map(this._dates, function (date) {
                    return Math.max.apply(null, $.map(eventsByResource, function (events) {
                        return $.grep(events, function (event) {
                            return event.isMultiDay() && isInDateRange(date, getDate(event.start), getDate(event.end));
                        }).length;
                    }));
                });
                var height = Math.max.apply(null, eventsPerDate);
                this._updateAllDayHeaderHeight((height + 1) * this._allDayHeaderHeight);
                for (var groupIndex = 0; groupIndex < eventsByResource.length; groupIndex++) {
                    this._renderEvents(eventsByResource[groupIndex], groupIndex);
                }
                this.refreshLayout();
                this._currentTime(false);
                this.trigger('activate');
            },
            _eventsByResource: function (events, resources, result) {
                var resource = resources[0];
                if (resource) {
                    var view = resource.dataSource.view();
                    for (var itemIdx = 0; itemIdx < view.length; itemIdx++) {
                        var value = this._resourceValue(resource, view[itemIdx]);
                        var eventsFilteredByResource = new kendo.data.Query(events).filter({
                            field: resource.field,
                            operator: SchedulerView.groupEqFilter(value)
                        }).toArray();
                        if (resources.length > 1) {
                            this._eventsByResource(eventsFilteredByResource, resources.slice(1), result);
                        } else {
                            result.push(eventsFilteredByResource);
                        }
                    }
                } else {
                    result.push(events);
                }
            },
            _columnOffsetForResource: function (index) {
                return this._columnCountForLevel(index) / this._columnCountForLevel(index - 1);
            },
            _columnCountForLevel: function (level) {
                var columnLevel = this.columnLevels[level];
                return columnLevel ? columnLevel.length : 0;
            },
            _rowCountForLevel: function (level) {
                var rowLevel = this.rowLevels[level];
                return rowLevel ? rowLevel.length : 0;
            },
            clearSelection: function () {
                this.content.add(this.datesHeader).find('.k-state-selected').removeAttr('id').attr('aria-selected', false).removeClass('k-state-selected');
            },
            _updateDirection: function (selection, ranges, multiple, reverse, vertical) {
                var isDaySlot = selection.isAllDay;
                var startSlot = ranges[0].start;
                var endSlot = ranges[ranges.length - 1].end;
                if (multiple) {
                    if (vertical) {
                        if (!isDaySlot && startSlot.index === endSlot.index && startSlot.collectionIndex === endSlot.collectionIndex) {
                            selection.backward = reverse;
                        }
                    } else {
                        if (isDaySlot && startSlot.index === endSlot.index || !isDaySlot && startSlot.collectionIndex === endSlot.collectionIndex) {
                            selection.backward = reverse;
                        }
                    }
                }
            },
            _changeViewPeriod: function (selection, reverse, vertical) {
                if (!vertical) {
                    var date = reverse ? this.previousDate() : this.nextDate();
                    var start = selection.start;
                    var end = selection.end;
                    var verticalByDate = this._isGroupedByDate() && this._isVerticallyGrouped();
                    var group = this.groups[selection.groupIndex];
                    var collection = reverse ? group._timeSlotCollections : group._getCollections(group.daySlotCollectionCount());
                    var slots = collection[collection.length - 1]._slots;
                    var slotIndex = !reverse && !group.daySlotCollectionCount() ? 0 : slots.length - 1;
                    var endMilliseconds;
                    selection.start = new Date(date);
                    selection.end = new Date(date);
                    if (verticalByDate) {
                        var newStart = new Date(slots[slotIndex].startDate());
                        var newEnd = new Date(slots[slotIndex].endDate());
                        endMilliseconds = getMilliseconds(newEnd) ? getMilliseconds(newEnd) : MS_PER_DAY;
                        setTime(selection.start, getMilliseconds(newStart));
                        setTime(selection.end, endMilliseconds);
                        if (group.daySlotCollectionCount()) {
                            selection.isAllDay = !selection.isAllDay;
                        }
                    } else {
                        endMilliseconds = selection.isAllDay || !getMilliseconds(end) ? MS_PER_DAY : getMilliseconds(end);
                        setTime(selection.start, getMilliseconds(start));
                        setTime(selection.end, endMilliseconds);
                    }
                    if (!this._isVerticallyGrouped()) {
                        selection.groupIndex = reverse ? this.groups.length - 1 : 0;
                    }
                    selection.events = [];
                    return true;
                }
            }
        });
        extend(true, ui, {
            MultiDayView: MultiDayView,
            DayView: MultiDayView.extend({
                options: {
                    name: 'DayView',
                    title: 'Day'
                },
                name: 'day'
            }),
            WeekView: MultiDayView.extend({
                options: {
                    name: 'WeekView',
                    title: 'Week',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}'
                },
                name: 'week',
                calculateDateRange: function () {
                    var selectedDate = this.options.date, start = kendo.date.dayOfWeek(selectedDate, this.calendarInfo().firstDay, -1), idx, length, dates = [];
                    for (idx = 0, length = 7; idx < length; idx++) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            }),
            WorkWeekView: MultiDayView.extend({
                options: {
                    name: 'WorkWeekView',
                    title: 'Work Week',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}'
                },
                name: 'workWeek',
                nextDate: function () {
                    var weekStart = kendo.date.dayOfWeek(kendo.date.nextDay(this.startDate()), this.calendarInfo().firstDay, 1);
                    return kendo.date.addDays(weekStart, this._workDays[0]);
                },
                previousDate: function () {
                    var weekStart = kendo.date.dayOfWeek(this.startDate(), this.calendarInfo().firstDay, -1);
                    var workDays = this._workDays;
                    return kendo.date.addDays(weekStart, workDays[workDays.length - 1] - 7);
                },
                calculateDateRange: function () {
                    var selectedDate = this.options.date, dayOfWeek = kendo.date.dayOfWeek, weekStart = dayOfWeek(selectedDate, this.calendarInfo().firstDay, -1), start = dayOfWeek(weekStart, this.options.workWeekStart, 1), end = dayOfWeek(start, this.options.workWeekEnd, 1), dates = [];
                    while (start <= end) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            })
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.agendaview', ['kendo.scheduler.view'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.agendaview',
        name: 'Scheduler Agenda View',
        category: 'web',
        description: 'The Scheduler Agenda View',
        depends: ['scheduler.view'],
        hidden: true
    };
    (function ($) {
        var kendo = window.kendo, ui = kendo.ui, NS = '.kendoAgendaView';
        var EVENT_WRAPPER_FORMAT = '<div class="k-task" title="#:title.replace(/"/g,"\'")#" data-#=kendo.ns#uid="#=uid#">' + '# if (resources[0]) {#' + '<span class="k-scheduler-mark" style="background-color:#=resources[0].color#"></span>' + '# } #' + '# if (data.isException()) { #' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if (data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '# } #' + '{0}' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '</div>';
        var AgendaGroupedView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _getColumns: function (groupHeaders, columns) {
                return groupHeaders.concat(columns);
            },
            _getGroupsInDay: function () {
                return [];
            },
            _getSumOfItemsForDate: function () {
                return 0;
            },
            _renderTaskGroupsCells: function (headerCells, groups, taskGroupIndex, taskIndex) {
                var view = this._view;
                if (taskGroupIndex === 0 && taskIndex === 0 && groups.length) {
                    view._renderTaskGroupsCells(headerCells, groups);
                }
            },
            _renderDateCell: function (tableRow, groups, tasks, date, taskGroupIndex, tasksGroups) {
                var view = this._view;
                tableRow.push(kendo.format('<td class="k-scheduler-datecolumn{3}{2}" rowspan="{0}">{1}</td>', tasks.length, view._dateTemplate({ date: date }), taskGroupIndex == tasksGroups.length - 1 && !groups.length ? ' k-last' : '', !groups.length ? ' k-first' : ''));
            },
            _renderDates: function () {
                return undefined;
            },
            _getParents: function (parentGroups) {
                return parentGroups.splice(0);
            },
            _getGroupsByDate: function () {
                return undefined;
            },
            _renderTaskGroups: function (table, items, parents) {
                var view = this._view;
                table.append(view._renderTaskGroups(items, parents));
            }
        });
        var AgendaGroupedByDateView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _getColumns: function (groupHeaders, columns) {
                var view = this._view;
                if (view._isMobilePhoneView()) {
                    return groupHeaders.concat(columns);
                } else {
                    var date = columns.slice(0, 1);
                    var columnsWithoutDate = columns.slice(1);
                    return date.concat(groupHeaders).concat(columnsWithoutDate);
                }
            },
            _compareDateGroups: function (currentGroup, prevGroup, index) {
                if (currentGroup[index].text == prevGroup[index].text) {
                    if (index === 0) {
                        return true;
                    } else {
                        return this._compareDateGroups(currentGroup, prevGroup, index - 1);
                    }
                }
                return false;
            },
            _getGroupsInDay: function (tasksGroups, groups) {
                var groupsInDay = [];
                var prevGroup = null;
                for (var tasksGroupIdx = 0; tasksGroupIdx < tasksGroups.length; tasksGroupIdx++) {
                    for (var itemsIdx = 0; itemsIdx < tasksGroups[tasksGroupIdx].items.length; itemsIdx++) {
                        var idx = 0;
                        if (groupsInDay.length === 0) {
                            for (idx; idx < groups[tasksGroupIdx].length; idx++) {
                                groupsInDay.push([1]);
                            }
                        } else {
                            for (idx; idx < groups[tasksGroupIdx].length; idx++) {
                                if (this._compareDateGroups(groups[tasksGroupIdx], prevGroup, idx)) {
                                    groupsInDay[idx][groupsInDay[idx].length - 1]++;
                                } else {
                                    var lastItemValue = groupsInDay[idx][groupsInDay[idx].length - 1] - 1;
                                    for (var i = 0; i < lastItemValue; i++) {
                                        groupsInDay[idx].push(0);
                                    }
                                    groupsInDay[idx].push(1);
                                }
                            }
                        }
                        prevGroup = groups[tasksGroupIdx];
                    }
                }
                return groupsInDay;
            },
            _getSumOfItemsForDate: function (tasksGroups) {
                var sumOfItemsForDate = 0;
                for (var i = 0; i < tasksGroups.length; i++) {
                    sumOfItemsForDate += tasksGroups[i].items.length;
                }
                return sumOfItemsForDate;
            },
            _renderTaskGroupsCells: function (headerCells, groups, taskGroupIndex, taskIndex, groupsInDay, sumOfItemsForDate, date, groupsRowSpanIndex) {
                var view = this._view;
                var isPhoneView = view._isMobilePhoneView();
                if (!isPhoneView) {
                    if (taskGroupIndex === 0 && taskIndex === 0) {
                        headerCells.push(kendo.format('<td class="k-scheduler-datecolumn k-first" rowspan="{0}">{1}</td>', sumOfItemsForDate, view._dateTemplate({ date: date })));
                    }
                    for (var idx = 0; idx < groups[taskGroupIndex].length; idx++) {
                        if (groupsInDay[idx][groupsRowSpanIndex]) {
                            headerCells.push(kendo.format('<td class="k-scheduler-groupcolumn" rowspan="{0}">{1}</td>', groupsInDay[idx][groupsRowSpanIndex], view._groupTemplate({ value: groups[taskGroupIndex][idx].text }), groups[taskGroupIndex][idx].className));
                        }
                    }
                } else {
                    if (taskGroupIndex === 0 && taskIndex === 0 && groups.length) {
                        view._renderTaskGroupsCells(headerCells, groups);
                    }
                }
            },
            _renderDateCell: function () {
                return undefined;
            },
            _renderDates: function (table) {
                var view = this._view;
                var sortedArray = view._groupsByDate.sort(function (a, b) {
                    return a.array[0].value.getTime() - b.array[0].value.getTime();
                });
                for (var i = 0; i < sortedArray.length; i++) {
                    table.append(view._renderTaskGroups(sortedArray[i].array, sortedArray[i].groups));
                }
            },
            _getParents: function (parentGroups) {
                return parentGroups.slice(0);
            },
            _getGroupsByDate: function (groups, idx, parents) {
                var view = this._view;
                if (groups[idx].items) {
                    for (var taskGroupIndex = 0; taskGroupIndex < groups[idx].items.length; taskGroupIndex++) {
                        var date = groups[idx].items[taskGroupIndex].value;
                        var dateExists = false;
                        for (var i = 0; i < view._groupsByDate.length; i++) {
                            if (view._groupsByDate[i].array[0].value.getTime() === date.getTime()) {
                                dateExists = true;
                                view._groupsByDate[i].array.push(groups[idx].items[taskGroupIndex]);
                                view._groupsByDate[i].groups.push(parents);
                            }
                        }
                        if (!dateExists) {
                            view._groupsByDate.push({
                                array: [groups[idx].items[taskGroupIndex]],
                                groups: [parents]
                            });
                        }
                    }
                }
            },
            _renderTaskGroups: function () {
                return undefined;
            }
        });
        kendo.ui.scheduler.AgendaGroupedView = AgendaGroupedView;
        kendo.ui.scheduler.AgendaGroupedByDateView = AgendaGroupedByDateView;
        ui.AgendaView = ui.SchedulerView.extend({
            init: function (element, options) {
                ui.SchedulerView.fn.init.call(this, element, options);
                this._groupedView = this._getGroupedView();
                options = this.options;
                if (options.editable) {
                    options.editable = $.extend({ 'delete': true }, options.editable, {
                        create: false,
                        update: false
                    }, { messages: options.messages });
                }
                this.title = options.title;
                this._eventTemplate = this._eventTmpl(options.eventTemplate, EVENT_WRAPPER_FORMAT);
                this._dateTemplate = kendo.template(options.eventDateTemplate);
                this._groupTemplate = kendo.template(options.eventGroupTemplate);
                this._timeTemplate = kendo.template(options.eventTimeTemplate);
                this.element.on('mouseenter' + NS, '.k-scheduler-agenda .k-scheduler-content tr', '_mouseenter').on('mouseleave' + NS, '.k-scheduler-agenda .k-scheduler-content tr', '_mouseleave').on('click' + NS, '.k-scheduler-agenda .k-scheduler-content .k-link:has(.k-i-close)', '_remove');
                this._renderLayout(options.date);
            },
            name: 'agenda',
            _getGroupedView: function () {
                if (this._isGroupedByDate()) {
                    return new kendo.ui.scheduler.AgendaGroupedByDateView(this);
                } else {
                    return new kendo.ui.scheduler.AgendaGroupedView(this);
                }
            },
            _mouseenter: function (e) {
                $(e.currentTarget).addClass('k-state-hover');
            },
            _mouseleave: function (e) {
                $(e.currentTarget).removeClass('k-state-hover');
            },
            _remove: function (e) {
                e.preventDefault();
                this.trigger('remove', { uid: $(e.currentTarget).closest('.k-task').attr(kendo.attr('uid')) });
            },
            nextDate: function () {
                return kendo.date.nextDay(this.startDate());
            },
            startDate: function () {
                return this._startDate;
            },
            endDate: function () {
                return this._endDate;
            },
            previousDate: function () {
                return kendo.date.previousDay(this.startDate());
            },
            _renderLayout: function (date) {
                this._startDate = date;
                this._endDate = kendo.date.addDays(date, 7);
                this.createLayout(this._layout());
                this.table.addClass('k-scheduler-agenda');
            },
            _layout: function () {
                var columns = [
                    {
                        text: this.options.messages.time,
                        className: 'k-scheduler-timecolumn'
                    },
                    { text: this.options.messages.event }
                ];
                if (!this._isMobilePhoneView()) {
                    columns.splice(0, 0, {
                        text: this.options.messages.date,
                        className: 'k-scheduler-datecolumn'
                    });
                }
                var resources = this.groupedResources;
                if (resources.length) {
                    var groupHeaders = [];
                    for (var idx = 0; idx < resources.length; idx++) {
                        groupHeaders.push({
                            text: '',
                            className: 'k-scheduler-groupcolumn'
                        });
                    }
                    columns = this._groupedView._getColumns(groupHeaders, columns);
                }
                return { columns: columns };
            },
            _tasks: function (events) {
                var tasks = [];
                for (var idx = 0; idx < events.length; idx++) {
                    var event = events[idx];
                    var start = event.start;
                    var end = event.isAllDay ? kendo.date.getDate(event.end) : event.end;
                    var eventDurationInDays = Math.ceil((end - kendo.date.getDate(start)) / kendo.date.MS_PER_DAY);
                    if (event.isAllDay) {
                        eventDurationInDays += 1;
                    }
                    var task = event.clone();
                    task.startDate = kendo.date.getDate(start);
                    if (task.startDate >= this.startDate()) {
                        tasks.push(task);
                    }
                    if (eventDurationInDays > 1) {
                        task.end = kendo.date.nextDay(start);
                        task.head = true;
                        for (var day = 1; day < eventDurationInDays; day++) {
                            start = task.end;
                            task = event.clone();
                            task.start = task.startDate = kendo.date.getDate(start);
                            task.end = kendo.date.nextDay(start);
                            if (day == eventDurationInDays - 1) {
                                task.end = new Date(task.start.getFullYear(), task.start.getMonth(), task.start.getDate(), end.getHours(), end.getMinutes(), end.getSeconds(), end.getMilliseconds());
                                task.tail = true;
                            } else {
                                task.isAllDay = true;
                                task.middle = true;
                            }
                            if (kendo.date.getDate(task.end) <= this.endDate() && task.start >= this.startDate() || kendo.date.getDate(task.start).getTime() == this.endDate().getTime()) {
                                tasks.push(task);
                            }
                        }
                    }
                }
                return new kendo.data.Query(tasks).sort([
                    {
                        field: 'start',
                        dir: 'asc'
                    },
                    {
                        field: 'end',
                        dir: 'asc'
                    }
                ]).groupBy({ field: 'startDate' }).toArray();
            },
            _renderTaskGroups: function (tasksGroups, groups) {
                var tableRows = [];
                var editable = this.options.editable;
                var showDelete = editable && editable.destroy !== false && !this._isMobile();
                var isPhoneView = this._isMobilePhoneView();
                var sumOfItemsForDate = this._groupedView._getSumOfItemsForDate(tasksGroups);
                var groupsInDay = this._groupedView._getGroupsInDay(tasksGroups, groups);
                var groupsRowSpanIndex = 0;
                for (var taskGroupIndex = 0; taskGroupIndex < tasksGroups.length; taskGroupIndex++) {
                    var date = tasksGroups[taskGroupIndex].value;
                    var tasks = tasksGroups[taskGroupIndex].items;
                    var today = kendo.date.isToday(date);
                    for (var taskIndex = 0; taskIndex < tasks.length; taskIndex++) {
                        var task = tasks[taskIndex];
                        var tableRow = [];
                        var headerCells = !isPhoneView ? tableRow : [];
                        this._groupedView._renderTaskGroupsCells(headerCells, groups, taskGroupIndex, taskIndex, groupsInDay, sumOfItemsForDate, date, groupsRowSpanIndex);
                        groupsRowSpanIndex++;
                        if (taskIndex === 0) {
                            if (isPhoneView) {
                                headerCells.push(kendo.format('<td class="k-scheduler-datecolumn" colspan="2">{0}</td>', this._dateTemplate({ date: date })));
                                tableRows.push('<tr role="row" aria-selected="false"' + (today ? ' class="k-today">' : '>') + headerCells.join('') + '</tr>');
                            } else {
                                this._groupedView._renderDateCell(tableRow, groups, tasks, date, taskGroupIndex, tasksGroups);
                            }
                        }
                        if (task.head) {
                            task.format = '{0:t}';
                        } else if (task.tail) {
                            task.format = '{1:t}';
                        } else {
                            task.format = '{0:t}-{1:t}';
                        }
                        task.resources = this.eventResources(task);
                        tableRow.push(kendo.format('<td class="k-scheduler-timecolumn"><div>{0}{1}{2}</div></td><td>{3}</td>', task.tail || task.middle ? '<span class="k-icon k-i-arrow-60-left"></span>' : '', this._timeTemplate(task.clone({
                            start: task._startTime || task.start,
                            end: task.endTime || task.end
                        })), task.head || task.middle ? '<span class="k-icon k-i-arrow-60-right"></span>' : '', this._eventTemplate(task.clone({
                            showDelete: showDelete,
                            messages: this.options.messages
                        }))));
                        tableRows.push('<tr role="row" aria-selected="false"' + (today ? ' class="k-today">' : '>') + tableRow.join('') + '</tr>');
                    }
                }
                return tableRows.join('');
            },
            _renderTaskGroupsCells: function (headerCells, groups) {
                for (var idx = 0; idx < groups.length; idx++) {
                    headerCells.push(kendo.format('<td class="k-scheduler-groupcolumn{2}" rowspan="{0}">{1}</td>', groups[idx].rowSpan, this._groupTemplate({ value: groups[idx].text }), groups[idx].className));
                }
            },
            render: function (events) {
                var table = this.content.find('table').empty();
                var groups = [];
                if (events.length > 0) {
                    var resources = this.groupedResources;
                    if (resources.length) {
                        groups = this._createGroupConfiguration(events, resources, null);
                        this._groupsByDate = [];
                        this._renderGroups(groups, table, []);
                        this._groupedView._renderDates(table);
                    } else {
                        groups = this._tasks(events);
                        table.append(this._renderTaskGroups(groups, []));
                    }
                }
                var items = this._eventsList = flattenTaskGroups(groups);
                this._angularItems(table, items);
                this.refreshLayout();
                this.trigger('activate');
            },
            _angularItems: function (table, items) {
                this.angular('compile', function () {
                    var data = [], elements = items.map(function (item) {
                            data.push({ dataItem: item });
                            return table.find('.k-task[' + kendo.attr('uid') + '=' + item.uid + ']');
                        });
                    return {
                        elements: elements,
                        data: data
                    };
                });
            },
            _renderGroups: function (groups, table, parentGroups) {
                for (var idx = 0, length = groups.length; idx < length; idx++) {
                    var parents = this._groupedView._getParents(parentGroups);
                    parents.push(groups[idx]);
                    this._groupedView._getGroupsByDate(groups, idx, parents);
                    if (groups[idx].groups) {
                        this._renderGroups(groups[idx].groups, table, parents);
                    } else {
                        this._groupedView._renderTaskGroups(table, groups[idx].items, parents);
                    }
                }
            },
            _createGroupConfiguration: function (events, resources, parent) {
                var resource = resources[0];
                var configuration = [];
                var data = resource.dataSource.view();
                var isPhoneView = this._isMobilePhoneView();
                for (var dataIndex = 0; dataIndex < data.length; dataIndex++) {
                    var value = resourceValue(resource, data[dataIndex]);
                    var tmp = new kendo.data.Query(events).filter({
                        field: resource.field,
                        operator: ui.SchedulerView.groupEqFilter(value)
                    }).toArray();
                    if (tmp.length) {
                        var tasks = this._tasks(tmp);
                        var className = parent ? '' : ' k-first';
                        if (dataIndex === data.length - 1 && (!parent || parent.className.indexOf('k-last') > -1)) {
                            className += ' k-last';
                        }
                        var obj = {
                            text: kendo.getter(resource.dataTextField)(data[dataIndex]),
                            value: value,
                            rowSpan: 0,
                            className: className
                        };
                        if (resources.length > 1) {
                            obj.groups = this._createGroupConfiguration(tmp, resources.slice(1), obj);
                            if (parent) {
                                parent.rowSpan += obj.rowSpan;
                            }
                        } else {
                            obj.items = tasks;
                            var span = rowSpan(obj.items);
                            if (isPhoneView) {
                                span += obj.items.length;
                            }
                            obj.rowSpan = span;
                            if (parent) {
                                parent.rowSpan += span;
                            }
                        }
                        configuration.push(obj);
                    }
                }
                return configuration;
            },
            selectionByElement: function (cell) {
                var index, event;
                cell = $(cell);
                if (cell.hasClass('k-scheduler-datecolumn') || !this._eventsList.length) {
                    return;
                }
                if (cell.is('.k-task')) {
                    cell = cell.closest('td');
                }
                if (this._isMobile()) {
                    var parent = cell.parent();
                    index = parent.parent().children().filter(function () {
                        return $(this).children(':not(.k-scheduler-datecolumn)').length;
                    }).index(parent);
                } else {
                    index = cell.parent().index();
                }
                event = this._eventsList[index];
                return {
                    index: index,
                    start: event.start,
                    end: event.end,
                    isAllDay: event.isAllDay,
                    uid: event.uid
                };
            },
            select: function (selection) {
                this.clearSelection();
                var row = this.table.find('.k-task').eq(selection.index).closest('tr').addClass('k-state-selected').attr('aria-selected', true)[0];
                this.current(row);
            },
            move: function (selection, key) {
                var handled = false;
                var index = selection.index;
                if (key == kendo.keys.UP) {
                    index--;
                    handled = true;
                } else if (key == kendo.keys.DOWN) {
                    index++;
                    handled = true;
                }
                if (handled) {
                    var event = this._eventsList[index];
                    if (event) {
                        selection.start = event.start;
                        selection.end = event.end;
                        selection.isAllDay = event.isAllDay;
                        selection.events = [event.uid];
                        selection.index = index;
                    }
                }
                return handled;
            },
            moveToEvent: function () {
                return false;
            },
            constrainSelection: function (selection) {
                var event = this._eventsList[0];
                if (event) {
                    selection.start = event.start;
                    selection.end = event.end;
                    selection.isAllDay = event.isAllDay;
                    selection.events = [event.uid];
                    selection.index = 0;
                }
            },
            isInRange: function () {
                return true;
            },
            destroy: function () {
                if (this.element) {
                    this.element.off(NS);
                }
                ui.SchedulerView.fn.destroy.call(this);
            },
            options: {
                title: 'Agenda',
                name: 'agenda',
                editable: true,
                selectedDateFormat: '{0:D}-{1:D}',
                selectedShortDateFormat: '{0:d} - {1:d}',
                eventTemplate: '#:title#',
                eventTimeTemplate: '#if(data.isAllDay) {#' + '#=this.options.messages.allDay#' + '#} else { #' + '#=kendo.format(format, start, end)#' + '# } #',
                eventDateTemplate: '<strong class="k-scheduler-agendaday">' + '#=kendo.toString(date, "dd")#' + '</strong>' + '<em class="k-scheduler-agendaweek">' + '#=kendo.toString(date,"dddd")#' + '</em>' + '<span class="k-scheduler-agendadate">' + '#=kendo.toString(date, "y")#' + '</span>',
                eventGroupTemplate: '<strong class="k-scheduler-adgendagroup">' + '#=value#' + '</strong>',
                messages: {
                    event: 'Event',
                    date: 'Date',
                    time: 'Time',
                    allDay: 'all day'
                }
            }
        });
        function rowSpan(tasks) {
            var result = 0;
            for (var idx = 0, length = tasks.length; idx < length; idx++) {
                result += tasks[idx].items.length;
            }
            return result;
        }
        function resourceValue(resource, item) {
            if (resource.valuePrimitive) {
                item = kendo.getter(resource.dataValueField)(item);
            }
            return item;
        }
        function flattenTaskGroups(groups) {
            var idx = 0, length = groups.length, item, result = [];
            for (; idx < length; idx++) {
                item = groups[idx];
                if (item.groups) {
                    item = flattenGroup(item.groups);
                    result = result.concat(item);
                } else {
                    result = result.concat(flattenGroup(item.items));
                }
            }
            return result;
        }
        function flattenGroup(groups) {
            var items = [].concat(groups), item = items.shift(), result = [], push = [].push;
            while (item) {
                if (item.groups) {
                    push.apply(items, item.groups);
                } else if (item.items) {
                    push.apply(items, item.items);
                } else {
                    push.call(result, item);
                }
                item = items.shift();
            }
            return result;
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.monthview', ['kendo.scheduler.view'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.monthview',
        name: 'Scheduler Month View',
        category: 'web',
        description: 'The Scheduler Month View',
        depends: ['scheduler.view'],
        hidden: true
    };
    (function ($) {
        var kendo = window.kendo, ui = kendo.ui, SchedulerView = ui.SchedulerView, NS = '.kendoMonthView', extend = $.extend, getDate = kendo.date.getDate, MS_PER_DAY = kendo.date.MS_PER_DAY, NUMBER_OF_ROWS = 6, NUMBER_OF_COLUMNS = 7, DAY_TEMPLATE = kendo.template('<span class="k-link k-nav-day">#:kendo.toString(date, "dd")#</span>'), EVENT_WRAPPER_STRING = '<div role="gridcell" aria-selected="false" data-#=ns#uid="#=uid#"' + '#if (resources[0]) { #' + 'style="background-color:#=resources[0].color #; border-color: #=resources[0].color#"' + 'class="k-event#=inverseColor ? " k-event-inverse" : ""#"' + '#} else {#' + 'class="k-event"' + '#}#' + '>' + '<span class="k-event-actions">' + '# if(data.tail || data.middle) {#' + '<span class="k-icon k-i-arrow-60-left"></span>' + '#}#' + '# if(data.isException()) {#' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if(data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '#}#' + '</span>' + '{0}' + '<span class="k-event-actions">' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '# if(data.head || data.middle) {#' + '<span class="k-icon k-i-arrow-60-right"></span>' + '#}#' + '</span>' + '# if(resizable && !data.tail && !data.middle) {#' + '<span class="k-resize-handle k-resize-w"></span>' + '#}#' + '# if(resizable && !data.head && !data.middle) {#' + '<span class="k-resize-handle k-resize-e"></span>' + '#}#' + '</div>', EVENT_TEMPLATE = kendo.template('<div title="#=title.replace(/"/g,"&\\#34;")#">' + '<div class="k-event-template">#:title#</div>' + '</div>');
        var MORE_BUTTON_TEMPLATE = kendo.template('<div style="width:#=width#px;left:#=left#px;top:#=top#px" class="k-more-events k-button"><span>...</span></div>');
        var MonthGroupedView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _verticalRowCountForLevel: function (level) {
                var view = this._view;
                return view._rowCountForLevel(level);
            },
            _horizontalGroupCountForLevel: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level);
            },
            _getCalendarRowsLength: function (cellsPerRow, cellCount) {
                return cellCount / cellsPerRow;
            },
            _createRows: function (start, startIdx, horizontalGroupCount, verticalGroupIndex) {
                var view = this._view;
                var cellsPerRow = NUMBER_OF_COLUMNS;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                var html = '';
                for (var groupIdx = 0; groupIdx < horizontalGroupCount; groupIdx++) {
                    html += view._createRow(start, startIdx, cellsPerRow, isVerticallyGrouped ? verticalGroupIndex : groupIdx);
                }
                return html;
            },
            _adjustStartDate: function (start) {
                return kendo.date.addDays(start, NUMBER_OF_COLUMNS);
            },
            _getContent: function (content, startDate, resources) {
                return content({
                    date: startDate,
                    resources: resources
                });
            },
            _getTimeSlotByPosition: function (x, y, groupIndex) {
                var group = this._view.groups[groupIndex];
                return group.daySlotByPosition(x, y);
            },
            _nextSlotStartDate: function (startDate) {
                return kendo.date.nextDay(startDate);
            },
            _createRowsLayout: function (resources, rows, groupHeaderTemplate) {
                var view = this._view;
                return view._createRowsLayout(resources, rows, groupHeaderTemplate);
            },
            _createVerticalColumnsLayout: function (resources, rows, groupHeaderTemplate, columns) {
                return columns;
            },
            _createColumnsLayout: function (resources, columns, groupHeaderTemplate) {
                var view = this._view;
                return view._createColumnsLayout(resources, columns, groupHeaderTemplate);
            },
            _verticalGroupCount: function (level) {
                var view = this._view;
                return view._rowCountForLevel(level);
            },
            _horizontalGroupCount: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level) / view._columnOffsetForResource(level);
            },
            _positionEvent: function (event, group, range, rangeCount, start, end, rangeIndex) {
                var view = this._view;
                var isMobilePhoneView = view._isMobilePhoneView();
                if (rangeCount > 1) {
                    if (rangeIndex === 0) {
                        end = range.end.endDate();
                    } else if (rangeIndex == rangeCount - 1) {
                        start = range.start.startDate();
                    } else {
                        start = range.start.startDate();
                        end = range.end.endDate();
                    }
                }
                var occurrence = event.clone({
                    start: start,
                    end: end,
                    head: range.head,
                    tail: range.tail
                });
                if (isMobilePhoneView) {
                    view._positionMobileEvent(range, view._createEventElement(occurrence), group);
                } else {
                    view._positionEvent(range, view._createEventElement(occurrence), group);
                }
            },
            _addDaySlotCollections: function (groupCount, tableRows, startDate) {
                var view = this._view;
                var columnCount = NUMBER_OF_COLUMNS;
                var rowCount = NUMBER_OF_ROWS;
                for (var groupIndex = 0; groupIndex < groupCount; groupIndex++) {
                    var cellCount = 0;
                    var rowMultiplier = 0;
                    if (view._isVerticallyGrouped()) {
                        rowMultiplier = groupIndex;
                    }
                    for (var rowIndex = rowMultiplier * rowCount; rowIndex < (rowMultiplier + 1) * rowCount; rowIndex++) {
                        var group = view.groups[groupIndex];
                        var collection = group.addDaySlotCollection(kendo.date.addDays(startDate, cellCount), kendo.date.addDays(startDate, cellCount + columnCount));
                        var tableRow = tableRows[rowIndex];
                        var cells = tableRow.children;
                        var cellMultiplier = 0;
                        tableRow.setAttribute('role', 'row');
                        if (!view._isVerticallyGrouped()) {
                            cellMultiplier = groupIndex;
                        }
                        for (var cellIndex = cellMultiplier * columnCount; cellIndex < (cellMultiplier + 1) * columnCount; cellIndex++) {
                            var cell = cells[cellIndex];
                            view.addDaySlot(collection, cell, startDate, cellCount);
                            cellCount++;
                        }
                    }
                }
            },
            _changePeriodGroupIndex: function (reverse) {
                var view = this._view;
                return reverse ? view.groups.length - 1 : 0;
            },
            _createResizeHint: function (range) {
                var view = this._view;
                var left = range.startSlot().offsetLeft;
                var top = range.start.offsetTop;
                var width = range.innerWidth();
                var height = range.start.clientHeight - 2;
                var hint = SchedulerView.fn._createResizeHint.call(view, left, top, width, height);
                view._appendResizeHint(hint);
            },
            _createMoveHint: function (range, event) {
                var view = this._view;
                var startSlot = range.startSlot();
                var endSlot = range.endSlot();
                var hint = view._createEventElement(event.clone({
                    head: range.head,
                    tail: range.tail
                }));
                hint.css({
                    left: startSlot.offsetLeft + 2,
                    top: startSlot.offsetTop + startSlot.firstChildHeight,
                    height: view.options.eventHeight,
                    width: range.innerWidth() - (startSlot.index !== endSlot.index ? 5 : 4)
                });
                hint.addClass('k-event-drag-hint');
                view._appendMoveHint(hint);
            }
        });
        var MonthGroupedByDateView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _verticalRowCountForLevel: function () {
                return 1;
            },
            _horizontalGroupCountForLevel: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level + 1) / NUMBER_OF_COLUMNS;
            },
            _createRows: function (start, startIdx, horizontalGroupCount) {
                var view = this._view;
                var cellsPerRow = NUMBER_OF_COLUMNS;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                var html = '';
                var dateIdx = 0;
                if (isVerticallyGrouped) {
                    var verticalStart = new Date(start);
                    var groupCount = view._groupCount();
                    for (dateIdx; dateIdx < NUMBER_OF_ROWS; dateIdx++) {
                        html += view._createRow(verticalStart, startIdx, groupCount, dateIdx);
                        verticalStart = kendo.date.addDays(verticalStart, cellsPerRow);
                    }
                    start = kendo.date.nextDay(start);
                } else {
                    for (dateIdx; dateIdx < cellsPerRow; dateIdx++) {
                        html += view._createRow(start, startIdx, horizontalGroupCount, dateIdx);
                        start = kendo.date.nextDay(start);
                    }
                    start = kendo.date.addDays(start, cellsPerRow);
                }
                return html;
            },
            _adjustStartDate: function (start, isLastRow) {
                var view = this._view;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                if (isVerticallyGrouped) {
                    if (isLastRow) {
                        return kendo.date.addDays(start, NUMBER_OF_COLUMNS * (NUMBER_OF_ROWS - 1) + 1);
                    } else {
                        return kendo.date.nextDay(start);
                    }
                }
                return kendo.date.addDays(start, NUMBER_OF_COLUMNS);
            },
            _getContent: function (content, startDate, resources, cellIdx) {
                if (cellIdx === 0) {
                    return content({
                        date: startDate,
                        resources: resources
                    });
                }
                return '';
            },
            _getTimeSlotByPosition: function (x, y, groupIndex) {
                var group = this._view.groups[groupIndex];
                return group.daySlotByPosition(x, y, true);
            },
            _nextSlotStartDate: function (startDate) {
                return startDate;
            },
            _getCalendarRowsLength: function () {
                var view = this._view;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                return isVerticallyGrouped ? NUMBER_OF_COLUMNS : NUMBER_OF_ROWS;
            },
            _createRowsLayout: function (resources, rows, groupHeaderTemplate, columns) {
                var view = this._view;
                return view._createDateLayout(columns, null, false);
            },
            _createVerticalColumnsLayout: function (resources, rows, groupHeaderTemplate) {
                var view = this._view;
                var resource = resources[0];
                var configuration = [];
                var data = resource.dataSource.view();
                for (var dataIndex = 0; dataIndex < data.length * NUMBER_OF_ROWS; dataIndex++) {
                    var obj = {
                        text: groupHeaderTemplate({
                            text: kendo.htmlEncode(kendo.getter(resource.dataTextField)(data[dataIndex % data.length])),
                            color: kendo.getter(resource.dataColorField)(data[dataIndex % data.length]),
                            field: resource.field,
                            title: resource.title,
                            name: resource.name,
                            value: kendo.getter(resource.dataValueField)(data[dataIndex % data.length])
                        }),
                        className: 'k-slot-cell'
                    };
                    obj.columns = view._createColumnsLayout(resources.slice(1), null, groupHeaderTemplate);
                    configuration.push(obj);
                }
                return configuration;
            },
            _createColumnsLayout: function (resources, columns, groupHeaderTemplate, subColumns) {
                var view = this._view;
                return view._createColumnsLayout(resources, columns, groupHeaderTemplate, subColumns, true);
            },
            _verticalGroupCount: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level) / NUMBER_OF_ROWS;
            },
            _horizontalGroupCount: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level) / NUMBER_OF_COLUMNS;
            },
            _positionEvent: function (event, group, range, rangeCount, start, end) {
                var view = this._view;
                var startIndex = range.start.index;
                var endIndex = range.end.index;
                var isMobilePhoneView = view._isMobilePhoneView();
                for (var i = range.start.index; i <= range.end.index; i++) {
                    var currentSlot = range.collection._slots[i];
                    var dateRange = group.daySlotRanges(currentSlot.start, currentSlot.start, true)[0];
                    var occurrence = event.clone({
                        start: i === startIndex ? currentSlot.start : start,
                        end: i === endIndex ? currentSlot.end : end,
                        head: i !== endIndex || range.head,
                        tail: i !== startIndex || range.tail
                    });
                    if (isMobilePhoneView) {
                        view._positionMobileEvent(dateRange, view._createEventElement(occurrence), group);
                    } else {
                        view._positionEvent(dateRange, view._createEventElement(occurrence), group);
                    }
                }
            },
            _addDaySlotCollections: function (groupCount, tableRows, startDate) {
                var view = this._view;
                var columnCount = NUMBER_OF_COLUMNS;
                var rowCount = NUMBER_OF_ROWS;
                var isVerticallyGrouped = view._isVerticallyGrouped();
                for (var dateIndex = 0; dateIndex < columnCount; dateIndex++) {
                    for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) {
                        var groupIndex = 0;
                        var currentTableIndex = isVerticallyGrouped ? dateIndex : rowIndex;
                        var tableRow = tableRows[currentTableIndex];
                        var cells = tableRow.children;
                        var cellMultiplier = 0;
                        tableRow.setAttribute('role', 'row');
                        if (!view._isVerticallyGrouped()) {
                            cellMultiplier = dateIndex;
                        }
                        for (var cellIndex = cellMultiplier * groupCount; cellIndex < (cellMultiplier + 1) * groupCount; cellIndex++) {
                            var cellCount = rowIndex * columnCount + dateIndex;
                            var currentCellIndex = isVerticallyGrouped ? cellIndex + rowIndex * groupCount : cellIndex;
                            var cell = cells[currentCellIndex];
                            var currentGroupIndex = isVerticallyGrouped ? cellIndex : groupIndex;
                            var group = view.groups[currentGroupIndex];
                            var collection;
                            if (dateIndex === 0) {
                                collection = group.addDaySlotCollection(kendo.date.addDays(startDate, cellCount), kendo.date.addDays(startDate, cellCount + columnCount));
                            } else {
                                collection = group._daySlotCollections[rowIndex];
                            }
                            view.addDaySlot(collection, cell, startDate, cellCount);
                            groupIndex++;
                        }
                    }
                }
            },
            _changePeriodGroupIndex: function (reverse, vertical, selectionGroupIndex) {
                var view = this._view;
                if (vertical && view._isVerticallyGrouped()) {
                    return reverse ? view.groups.length - 1 : 0;
                }
                return selectionGroupIndex;
            },
            _createResizeHint: function (range) {
                var view = this._view;
                var left, top, width, height, hint;
                if (view._isVerticallyGrouped()) {
                    left = range.startSlot().offsetLeft;
                    top = range.start.offsetTop;
                    width = range.startSlot().offsetWidth;
                    height = range.endSlot().offsetTop + range.startSlot().offsetHeight - range.startSlot().offsetTop - 2;
                    hint = SchedulerView.fn._createResizeHint.call(view, left, top, width, height);
                    view._appendResizeHint(hint);
                } else {
                    for (var slotIdx = range.startSlot().index; slotIdx <= range.endSlot().index; slotIdx++) {
                        var slot = range.collection._slots[slotIdx];
                        left = slot.offsetLeft;
                        top = slot.offsetTop;
                        width = slot.offsetWidth;
                        height = slot.offsetHeight - 2;
                        hint = SchedulerView.fn._createResizeHint.call(view, left, top, width, height);
                        view._appendResizeHint(hint);
                    }
                }
            },
            _createMoveHint: function (range, event) {
                var view = this._view;
                var startSlot = range.startSlot();
                var endSlot = range.endSlot();
                for (var slotIdx = startSlot.index; slotIdx <= endSlot.index; slotIdx++) {
                    var slot = range.collection._slots[slotIdx];
                    var hint = view._createEventElement(event.clone({
                        head: range.head,
                        tail: range.tail
                    }));
                    hint.css({
                        left: slot.offsetLeft,
                        top: slot.offsetTop + slot.firstChildHeight,
                        height: view.options.eventHeight,
                        width: slot.offsetWidth - 2
                    });
                    hint.addClass('k-event-drag-hint');
                    view._appendMoveHint(hint);
                }
            }
        });
        kendo.ui.scheduler.MonthGroupedView = MonthGroupedView;
        kendo.ui.scheduler.MonthGroupedByDateView = MonthGroupedByDateView;
        ui.MonthView = SchedulerView.extend({
            init: function (element, options) {
                var that = this;
                SchedulerView.fn.init.call(that, element, options);
                that._groupedView = that._getGroupedView();
                that.title = that.options.title;
                that._templates();
                that._editable();
                that._renderLayout(that.options.date);
                that._groups();
            },
            name: 'month',
            _getGroupedView: function () {
                if (this._isGroupedByDate()) {
                    return new kendo.ui.scheduler.MonthGroupedByDateView(this);
                } else {
                    return new kendo.ui.scheduler.MonthGroupedView(this);
                }
            },
            _updateDirection: function (selection, ranges, multiple, reverse, vertical) {
                if (multiple) {
                    var startSlot = ranges[0].start;
                    var endSlot = ranges[ranges.length - 1].end;
                    var isSameSlot = startSlot.index === endSlot.index;
                    var isSameCollection = startSlot.collectionIndex === endSlot.collectionIndex;
                    var updateDirection;
                    if (vertical) {
                        updateDirection = isSameSlot && isSameCollection || isSameCollection;
                    } else {
                        updateDirection = isSameSlot && isSameCollection;
                    }
                    if (updateDirection) {
                        selection.backward = reverse;
                    }
                }
            },
            _changeDate: function (selection, slot, previous) {
                var group = this.groups[selection.groupIndex];
                var collections, index;
                if (previous) {
                    collections = group._getCollections(group.daySlotCollectionCount());
                    index = slot.collectionIndex - 1;
                    if (index >= 0) {
                        return collections[index]._slots[collections[index]._slots.length - 1];
                    }
                } else {
                    collections = group._getCollections(group.daySlotCollectionCount());
                    index = slot.collectionIndex + 1;
                    var slotIndex = 0;
                    if (collections[index] && collections[index]._slots[slotIndex]) {
                        return collections[index]._slots[slotIndex];
                    }
                }
            },
            _getNextHorizontalRange: function (group, method, horizontalRange) {
                var isVertical = this._isVerticallyGrouped();
                horizontalRange.startSlot = group[method](horizontalRange.startSlot, isVertical);
                horizontalRange.endSlot = group[method](horizontalRange.endSlot, isVertical);
                return horizontalRange;
            },
            _getNextVerticalRange: function (group, method, verticalRange, multiple) {
                var isVertical = this._isVerticallyGrouped() && this._isGroupedByDate();
                verticalRange.startSlot = group[method](verticalRange.startSlot, multiple, isVertical);
                verticalRange.endSlot = group[method](verticalRange.endSlot, multiple, isVertical);
                return verticalRange;
            },
            _changeViewPeriod: function (selection, reverse, vertical) {
                var pad = vertical ? 7 : 1;
                if (reverse) {
                    pad *= -1;
                }
                selection.start = kendo.date.addDays(selection.start, pad);
                selection.end = kendo.date.addDays(selection.end, pad);
                if (!vertical || vertical && this._isVerticallyGrouped()) {
                    selection.groupIndex = this._groupedView._changePeriodGroupIndex(reverse, vertical, selection.groupIndex);
                }
                selection.events = [];
                return true;
            },
            _continuousSlot: function (selection, ranges, reverse) {
                var index = selection.backward ? 0 : ranges.length - 1;
                var group = this.groups[selection.groupIndex];
                return group.continuousSlot(ranges[index].start, reverse);
            },
            _changeGroupContinuously: function (selection, continuousSlot, multiple, reverse) {
                if (!multiple) {
                    var groupIndex = selection.groupIndex;
                    var lastGroupIndex = this.groups.length - 1;
                    var vertical = this._isVerticallyGrouped();
                    var group = this.groups[groupIndex];
                    if (!continuousSlot && vertical) {
                        continuousSlot = group[reverse ? 'lastSlot' : 'firstSlot']();
                        groupIndex += reverse ? -1 : 1;
                    } else if (continuousSlot && !vertical) {
                        groupIndex = reverse ? lastGroupIndex : 0;
                    }
                    if (groupIndex < 0 || groupIndex > lastGroupIndex) {
                        groupIndex = reverse ? lastGroupIndex : 0;
                        continuousSlot = null;
                    }
                    selection.groupIndex = groupIndex;
                }
                return continuousSlot;
            },
            _normalizeHorizontalSelection: function (selection, ranges, reverse) {
                var slot;
                if (reverse) {
                    slot = ranges[0].start;
                } else {
                    slot = ranges[ranges.length - 1].end;
                }
                return slot;
            },
            _normalizeVerticalSelection: function (selection, ranges) {
                var slot;
                if (selection.backward) {
                    slot = ranges[0].start;
                } else {
                    slot = ranges[ranges.length - 1].end;
                }
                return slot;
            },
            _templates: function () {
                var options = this.options, settings = extend({}, kendo.Template, options.templateSettings);
                this.eventTemplate = this._eventTmpl(options.eventTemplate, EVENT_WRAPPER_STRING);
                this.dayTemplate = kendo.template(options.dayTemplate, settings);
                this.groupHeaderTemplate = kendo.template(options.groupHeaderTemplate, settings);
            },
            dateForTitle: function () {
                return kendo.format(this.options.selectedDateFormat, this._firstDayOfMonth, this._lastDayOfMonth);
            },
            shortDateForTitle: function () {
                return kendo.format(this.options.selectedShortDateFormat, this._firstDayOfMonth, this._lastDayOfMonth);
            },
            nextDate: function () {
                return kendo.date.nextDay(this._lastDayOfMonth);
            },
            previousDate: function () {
                return kendo.date.previousDay(this._firstDayOfMonth);
            },
            startDate: function () {
                return this._startDate;
            },
            endDate: function () {
                return this._endDate;
            },
            _renderLayout: function (date) {
                var that = this;
                this._firstDayOfMonth = kendo.date.firstDayOfMonth(date);
                this._lastDayOfMonth = kendo.date.lastDayOfMonth(date);
                this._startDate = firstVisibleMonthDay(date, this.calendarInfo());
                this.createLayout(this._layout());
                this._content();
                this.refreshLayout();
                this.content.on('click' + NS, '.k-nav-day,.k-more-events', function (e) {
                    var offset = $(e.currentTarget).offset();
                    var slot = that._slotByPosition(offset.left, offset.top);
                    e.preventDefault();
                    that.trigger('navigate', {
                        view: 'day',
                        date: slot.startDate()
                    });
                });
            },
            _editable: function () {
                if (this.options.editable && !this._isMobilePhoneView()) {
                    if (this._isMobile()) {
                        this._touchEditable();
                    } else {
                        this._mouseEditable();
                    }
                }
            },
            _mouseEditable: function () {
                var that = this;
                that.element.on('click' + NS, '.k-scheduler-monthview .k-event a:has(.k-i-close)', function (e) {
                    that.trigger('remove', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                    e.preventDefault();
                });
                if (that.options.editable.create !== false) {
                    that.element.on('dblclick' + NS, '.k-scheduler-monthview .k-scheduler-content td', function (e) {
                        var offset = $(e.currentTarget).offset();
                        var slot = that._slotByPosition(offset.left, offset.top);
                        if (slot) {
                            var resourceInfo = that._resourceBySlot(slot);
                            that.trigger('add', {
                                eventInfo: extend({
                                    isAllDay: true,
                                    start: slot.startDate(),
                                    end: slot.startDate()
                                }, resourceInfo)
                            });
                        }
                        e.preventDefault();
                    });
                }
                if (that.options.editable.update !== false) {
                    that.element.on('dblclick' + NS, '.k-scheduler-monthview .k-event', function (e) {
                        that.trigger('edit', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                        e.preventDefault();
                    });
                }
            },
            _touchEditable: function () {
                var that = this;
                var threshold = 0;
                if (kendo.support.mobileOS.android) {
                    threshold = 5;
                }
                if (that.options.editable.create !== false) {
                    that._addUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        filter: '.k-scheduler-monthview .k-scheduler-content td',
                        tap: function (e) {
                            var offset = $(e.target).offset();
                            var slot = that._slotByPosition(offset.left, offset.top);
                            if (slot) {
                                var resourceInfo = that._resourceBySlot(slot);
                                that.trigger('add', {
                                    eventInfo: extend({
                                        isAllDay: true,
                                        start: slot.startDate(),
                                        end: slot.startDate()
                                    }, resourceInfo)
                                });
                            }
                            e.preventDefault();
                        }
                    });
                }
                if (that.options.editable.update !== false) {
                    that._editUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        filter: '.k-scheduler-monthview .k-event',
                        tap: function (e) {
                            if ($(e.event.target).closest('a:has(.k-i-close)').length === 0) {
                                that.trigger('edit', { uid: $(e.target).closest('.k-event').attr(kendo.attr('uid')) });
                                e.preventDefault();
                            }
                        }
                    });
                }
            },
            selectionByElement: function (cell) {
                var offset = $(cell).offset();
                return this._slotByPosition(offset.left, offset.top);
            },
            _columnCountForLevel: function (level) {
                var columnLevel = this.columnLevels[level];
                return columnLevel ? columnLevel.length : 0;
            },
            _rowCountForLevel: function (level) {
                var rowLevel = this.rowLevels[level];
                return rowLevel ? rowLevel.length : 0;
            },
            _content: function () {
                var html = '<tbody>';
                var verticalGroupCount = 1;
                var groupedView = this._groupedView;
                var resources = this.groupedResources;
                if (resources.length) {
                    if (this._isVerticallyGrouped()) {
                        verticalGroupCount = groupedView._verticalRowCountForLevel(resources.length - 1);
                    }
                }
                for (var verticalGroupIdx = 0; verticalGroupIdx < verticalGroupCount; verticalGroupIdx++) {
                    html += this._createCalendar(verticalGroupIdx);
                }
                html += '</tbody>';
                this.content.find('table').html(html);
            },
            _createCalendar: function (verticalGroupIndex) {
                var start = this.startDate();
                var cellCount = NUMBER_OF_COLUMNS * NUMBER_OF_ROWS;
                var cellsPerRow = NUMBER_OF_COLUMNS;
                var weekStartDates = [start];
                var html = '';
                var horizontalGroupCount = 1;
                var isVerticallyGrouped = this._isVerticallyGrouped();
                var groupedView = this._groupedView;
                var resources = this.groupedResources;
                if (resources.length) {
                    if (!isVerticallyGrouped) {
                        horizontalGroupCount = groupedView._horizontalGroupCountForLevel(resources.length - 1);
                    }
                }
                this._slotIndices = {};
                var calendarRowsLength = groupedView._getCalendarRowsLength(cellsPerRow, cellCount);
                for (var rowIdx = 0; rowIdx < calendarRowsLength; rowIdx++) {
                    html += '<tr>';
                    weekStartDates.push(start);
                    var startIdx = rowIdx * cellsPerRow;
                    html += groupedView._createRows(start, startIdx, horizontalGroupCount, verticalGroupIndex);
                    start = groupedView._adjustStartDate(start, rowIdx === calendarRowsLength - 1);
                    html += '</tr>';
                }
                this._weekStartDates = weekStartDates;
                this._endDate = kendo.date.previousDay(start);
                return html;
            },
            _createRow: function (startDate, startIdx, cellsPerRow, groupIndex) {
                var that = this;
                var min = that._firstDayOfMonth;
                var max = that._lastDayOfMonth;
                var content = that.dayTemplate;
                var classes = '';
                var html = '';
                var groupedView = this._groupedView;
                var resources = function () {
                    return that._resourceBySlot({ groupIndex: groupIndex });
                };
                for (var cellIdx = 0; cellIdx < cellsPerRow; cellIdx++) {
                    classes = '';
                    if (kendo.date.isToday(startDate)) {
                        classes += 'k-today';
                    }
                    if (!kendo.date.isInDateRange(startDate, min, max)) {
                        classes += ' k-other-month';
                    }
                    html += '<td ';
                    if (classes !== '') {
                        html += 'class="' + classes + '"';
                    }
                    html += '>';
                    html += groupedView._getContent(content, startDate, resources, cellIdx);
                    html += '</td>';
                    that._slotIndices[getDate(startDate).getTime()] = startIdx + cellIdx;
                    startDate = groupedView._nextSlotStartDate(startDate);
                }
                return html;
            },
            _layout: function () {
                var calendarInfo = this.calendarInfo();
                var weekDayNames = this._isMobile() ? calendarInfo.days.namesShort : calendarInfo.days.names;
                var names = shiftArray(weekDayNames, calendarInfo.firstDay);
                var columns = $.map(names, function (value) {
                    return { text: value };
                });
                var resources = this.groupedResources;
                var rows;
                var groupedView = this._groupedView;
                if (resources.length) {
                    if (this._isVerticallyGrouped()) {
                        var inner = [];
                        for (var idx = 0; idx < 6; idx++) {
                            inner.push({
                                text: '<div>&nbsp;</div>',
                                className: 'k-hidden k-slot-cell'
                            });
                        }
                        rows = groupedView._createRowsLayout(resources, inner, this.groupHeaderTemplate, columns);
                        columns = groupedView._createVerticalColumnsLayout(resources, inner, this.groupHeaderTemplate, columns);
                    } else {
                        columns = groupedView._createColumnsLayout(resources, columns, this.groupHeaderTemplate, columns);
                    }
                }
                return {
                    columns: columns,
                    rows: rows
                };
            },
            _createEventElement: function (event) {
                var options = this.options;
                var editable = options.editable;
                var isMobile = this._isMobile();
                event.showDelete = editable && editable.destroy !== false && !isMobile;
                event.resizable = editable && editable.resize !== false && !isMobile;
                event.ns = kendo.ns;
                event.resources = this.eventResources(event);
                event.inverseColor = event.resources && event.resources[0] ? this._shouldInverseResourceColor(event.resources[0]) : false;
                event.messages = options.messages || { destroy: 'Delete' };
                var element = $(this.eventTemplate(event));
                this.angular('compile', function () {
                    return {
                        elements: element,
                        data: [{ dataItem: event }]
                    };
                });
                return element;
            },
            _isInDateSlot: function (event) {
                var groups = this.groups[0];
                var slotStart = groups.firstSlot().start;
                var slotEnd = groups.lastSlot().end - 1;
                var startTime = kendo.date.toUtcTime(event.start);
                var endTime = kendo.date.toUtcTime(event.end);
                return (isInDateRange(startTime, slotStart, slotEnd) || isInDateRange(endTime, slotStart, slotEnd) || isInDateRange(slotStart, startTime, endTime) || isInDateRange(slotEnd, startTime, endTime)) && (!isInDateRange(endTime, slotStart, slotStart) || isInDateRange(endTime, startTime, startTime) || event.isAllDay);
            },
            _slotIndex: function (date) {
                return this._slotIndices[getDate(date).getTime()];
            },
            _positionMobileEvent: function (slotRange, element, group) {
                var startSlot = slotRange.start;
                if (slotRange.start.offsetLeft > slotRange.end.offsetLeft) {
                    startSlot = slotRange.end;
                }
                var startIndex = slotRange.start.index;
                var endIndex = startIndex;
                var eventCount = 3;
                var events = SchedulerView.collidingEvents(slotRange.events(), startIndex, endIndex);
                events.push({
                    element: element,
                    start: startIndex,
                    end: endIndex
                });
                var rows = SchedulerView.createRows(events);
                var slot = slotRange.collection.at(startIndex);
                var container = slot.container;
                if (!container) {
                    container = $(kendo.format('<div class="k-events-container" style="top:{0};left:{1};width:{2}"/>', startSlot.offsetTop + startSlot.firstChildTop + startSlot.firstChildHeight - 3 + 'px', startSlot.offsetLeft + 'px', startSlot.offsetWidth + 'px'));
                    slot.container = container;
                    this.content[0].appendChild(container[0]);
                }
                if (rows.length <= eventCount) {
                    slotRange.addEvent({
                        element: element,
                        start: startIndex,
                        end: endIndex,
                        groupIndex: startSlot.groupIndex
                    });
                    group._continuousEvents.push({
                        element: element,
                        uid: element.attr(kendo.attr('uid')),
                        start: slotRange.start,
                        end: slotRange.end
                    });
                    container[0].appendChild(element[0]);
                }
            },
            _positionEvent: function (slotRange, element, group) {
                var eventHeight = this.options.eventHeight;
                var startSlot = slotRange.start;
                if (slotRange.start.offsetLeft > slotRange.end.offsetLeft) {
                    startSlot = slotRange.end;
                }
                var startIndex = slotRange.start.index;
                var endIndex = slotRange.end.index;
                var eventCount = startSlot.eventCount;
                var events = SchedulerView.collidingEvents(slotRange.events(), startIndex, endIndex);
                var rightOffset = startIndex !== endIndex ? 5 : 4;
                events.push({
                    element: element,
                    start: startIndex,
                    end: endIndex
                });
                var rows = SchedulerView.createRows(events);
                for (var idx = 0, length = Math.min(rows.length, eventCount); idx < length; idx++) {
                    var rowEvents = rows[idx].events;
                    var eventTop = startSlot.offsetTop + startSlot.firstChildHeight + idx * eventHeight + 3 * idx + 'px';
                    for (var j = 0, eventLength = rowEvents.length; j < eventLength; j++) {
                        rowEvents[j].element[0].style.top = eventTop;
                    }
                }
                if (rows.length > eventCount) {
                    for (var slotIndex = startIndex; slotIndex <= endIndex; slotIndex++) {
                        var collection = slotRange.collection;
                        var slot = collection.at(slotIndex);
                        if (slot.more) {
                            return;
                        }
                        slot.more = $(MORE_BUTTON_TEMPLATE({
                            ns: kendo.ns,
                            start: slotIndex,
                            end: slotIndex,
                            width: slot.clientWidth - 2,
                            left: slot.offsetLeft + 2,
                            top: slot.offsetTop + slot.firstChildHeight + eventCount * eventHeight + 3 * eventCount
                        }));
                        this.content[0].appendChild(slot.more[0]);
                    }
                } else {
                    slotRange.addEvent({
                        element: element,
                        start: startIndex,
                        end: endIndex,
                        groupIndex: startSlot.groupIndex
                    });
                    element[0].style.width = slotRange.innerWidth() - rightOffset + 'px';
                    element[0].style.left = startSlot.offsetLeft + 2 + 'px';
                    element[0].style.height = eventHeight + 'px';
                    group._continuousEvents.push({
                        element: element,
                        uid: element.attr(kendo.attr('uid')),
                        start: slotRange.start,
                        end: slotRange.end
                    });
                    element.appendTo(this.content);
                }
            },
            _slotByPosition: function (x, y) {
                var offset = this.content.offset();
                x -= offset.left;
                y -= offset.top;
                y += this.content[0].scrollTop;
                x += this.content[0].scrollLeft;
                x = Math.ceil(x);
                y = Math.ceil(y);
                for (var groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    var slot = this._groupedView._getTimeSlotByPosition(x, y, groupIndex);
                    if (slot) {
                        return slot;
                    }
                }
                return null;
            },
            _appendResizeHint: function (hint) {
                hint.appendTo(this.content);
                this._resizeHint = this._resizeHint.add(hint);
            },
            _updateResizeHint: function (event, groupIndex, startTime, endTime) {
                this._removeResizeHint();
                var group = this.groups[groupIndex];
                var ranges = group.ranges(startTime, endTime, true, event.isAllDay);
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    this._groupedView._createResizeHint(ranges[rangeIndex]);
                }
                this._resizeHint.find('.k-label-top,.k-label-bottom').text('');
                this._resizeHint.first().addClass('k-first').find('.k-label-top').text(kendo.toString(kendo.timezone.toLocalDate(startTime), 'M/dd'));
                this._resizeHint.last().addClass('k-last').find('.k-label-bottom').text(kendo.toString(kendo.timezone.toLocalDate(endTime), 'M/dd'));
            },
            _updateMoveHint: function (event, groupIndex, distance) {
                var start = kendo.date.toUtcTime(event.start) + distance;
                var end = start + event.duration();
                var group = this.groups[groupIndex];
                var ranges = group.ranges(start, end, true, event.isAllDay);
                this._removeMoveHint();
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    this._groupedView._createMoveHint(ranges[rangeIndex], event);
                }
            },
            _appendMoveHint: function (hint) {
                hint.appendTo(this.content);
                this._moveHint = this._moveHint.add(hint);
            },
            _groups: function () {
                var groupCount = this._groupCount();
                var tableRows = this.content[0].getElementsByTagName('tr');
                var startDate = this.startDate();
                this.groups = [];
                for (var idx = 0; idx < groupCount; idx++) {
                    this._addResourceView(idx);
                }
                this._groupedView._addDaySlotCollections(groupCount, tableRows, startDate);
            },
            addDaySlot: function (collection, cell, startDate, cellCount) {
                var clientHeight = cell.clientHeight;
                var firstChildHeight = cell.children.length ? cell.children[0].offsetHeight + 3 : 0;
                var start = kendo.date.addDays(startDate, cellCount);
                var end = kendo.date.MS_PER_DAY;
                if (startDate.getHours() !== start.getHours()) {
                    end += (startDate.getHours() - start.getHours()) * kendo.date.MS_PER_HOUR;
                }
                start = kendo.date.toUtcTime(start);
                end += start;
                var eventCount = Math.floor((clientHeight - firstChildHeight - this.options.moreButtonHeight) / (this.options.eventHeight + 3));
                cell.setAttribute('role', 'gridcell');
                cell.setAttribute('aria-selected', false);
                collection.addDaySlot(cell, start, end, eventCount);
            },
            render: function (events) {
                this.content.children('.k-event,.k-more-events,.k-events-container').remove();
                this._groups();
                events = new kendo.data.Query(events).sort([
                    {
                        field: 'start',
                        dir: 'asc'
                    },
                    {
                        field: 'end',
                        dir: 'desc'
                    }
                ]).toArray();
                var resources = this.groupedResources;
                if (resources.length) {
                    this._renderGroups(events, resources, 0, 1);
                } else {
                    this._renderEvents(events, 0);
                }
                this.refreshLayout();
                this.trigger('activate');
            },
            _renderEvents: function (events, groupIndex) {
                var event;
                var idx;
                var length;
                for (idx = 0, length = events.length; idx < length; idx++) {
                    event = events[idx];
                    if (this._isInDateSlot(event)) {
                        var group = this.groups[groupIndex];
                        if (!group._continuousEvents) {
                            group._continuousEvents = [];
                        }
                        var ranges = group.slotRanges(event, true);
                        var rangeCount = ranges.length;
                        for (var rangeIndex = 0; rangeIndex < rangeCount; rangeIndex++) {
                            var range = ranges[rangeIndex];
                            var start = event.start;
                            var end = event.end;
                            this._groupedView._positionEvent(event, group, range, rangeCount, start, end, rangeIndex);
                        }
                    }
                }
            },
            _renderGroups: function (events, resources, offset, columnLevel) {
                var resource = resources[0];
                if (resource) {
                    var view = resource.dataSource.view();
                    for (var itemIdx = 0; itemIdx < view.length; itemIdx++) {
                        var value = this._resourceValue(resource, view[itemIdx]);
                        var tmp = new kendo.data.Query(events).filter({
                            field: resource.field,
                            operator: SchedulerView.groupEqFilter(value)
                        }).toArray();
                        if (resources.length > 1) {
                            offset = this._renderGroups(tmp, resources.slice(1), offset++, columnLevel + 1);
                        } else {
                            this._renderEvents(tmp, offset++);
                        }
                    }
                }
                return offset;
            },
            _groupCount: function () {
                var resources = this.groupedResources;
                var groupedView = this._groupedView;
                if (resources.length) {
                    if (this._isVerticallyGrouped()) {
                        return groupedView._verticalGroupCount(resources.length - 1);
                    } else {
                        return groupedView._horizontalGroupCount(resources.length);
                    }
                }
                return 1;
            },
            _columnOffsetForResource: function (index) {
                return this._columnCountForLevel(index) / this._columnCountForLevel(index - 1);
            },
            destroy: function () {
                if (this.table) {
                    this.table.removeClass('k-scheduler-monthview');
                }
                if (this.content) {
                    this.content.off(NS);
                }
                if (this.element) {
                    this.element.off(NS);
                }
                SchedulerView.fn.destroy.call(this);
                if (this._isMobile() && !this._isMobilePhoneView() && this.options.editable) {
                    if (this.options.editable.create !== false) {
                        this._addUserEvents.destroy();
                    }
                    if (this.options.editable.update !== false) {
                        this._editUserEvents.destroy();
                    }
                }
            },
            events: [
                'remove',
                'add',
                'edit',
                'navigate'
            ],
            options: {
                title: 'Month',
                name: 'month',
                eventHeight: 25,
                moreButtonHeight: 13,
                editable: true,
                selectedDateFormat: '{0:y}',
                selectedShortDateFormat: '{0:y}',
                groupHeaderTemplate: '#=text#',
                dayTemplate: DAY_TEMPLATE,
                eventTemplate: EVENT_TEMPLATE
            }
        });
        function shiftArray(array, idx) {
            return array.slice(idx).concat(array.slice(0, idx));
        }
        function firstVisibleMonthDay(date, calendarInfo) {
            var firstDay = calendarInfo.firstDay, firstVisibleDay = new Date(date.getFullYear(), date.getMonth(), 0, date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
            while (firstVisibleDay.getDay() != firstDay) {
                kendo.date.setTime(firstVisibleDay, -1 * MS_PER_DAY);
            }
            return firstVisibleDay;
        }
        function isInDateRange(value, min, max) {
            var msMin = min, msMax = max, msValue;
            msValue = value;
            return msValue >= msMin && msValue <= msMax;
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.recurrence', [
        'kendo.dropdownlist',
        'kendo.datepicker',
        'kendo.numerictextbox'
    ], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.recurrence',
        name: 'Recurrence',
        category: 'web',
        depends: [
            'dropdownlist',
            'datepicker',
            'numerictextbox'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, timezone = kendo.timezone, Class = kendo.Class, ui = kendo.ui, Widget = ui.Widget, DropDownList = ui.DropDownList, kendoDate = kendo.date, setTime = kendoDate.setTime, setDayOfWeek = kendoDate.setDayOfWeek, adjustDST = kendoDate.adjustDST, firstDayOfMonth = kendoDate.firstDayOfMonth, getMilliseconds = kendoDate.getMilliseconds, DAYS_IN_LEAPYEAR = [
                0,
                31,
                60,
                91,
                121,
                152,
                182,
                213,
                244,
                274,
                305,
                335,
                366
            ], DAYS_IN_YEAR = [
                0,
                31,
                59,
                90,
                120,
                151,
                181,
                212,
                243,
                273,
                304,
                334,
                365
            ], MONTHS = [
                31,
                28,
                30,
                31,
                30,
                31,
                30,
                31,
                30,
                31,
                30,
                31
            ], WEEK_DAYS = {
                0: 'SU',
                1: 'MO',
                2: 'TU',
                3: 'WE',
                4: 'TH',
                5: 'FR',
                6: 'SA'
            }, WEEK_DAYS_IDX = {
                'SU': 0,
                'MO': 1,
                'TU': 2,
                'WE': 3,
                'TH': 4,
                'FR': 5,
                'SA': 6
            }, DATE_FORMATS = [
                'yyyy-MM-ddTHH:mm:ss.fffzzz',
                'yyyy-MM-ddTHH:mm:sszzz',
                'yyyy-MM-ddTHH:mm:ss',
                'yyyy-MM-ddTHH:mm',
                'yyyy-MM-ddTHH',
                'yyyy-MM-dd',
                'yyyyMMddTHHmmssfffzzz',
                'yyyyMMddTHHmmsszzz',
                'yyyyMMddTHHmmss',
                'yyyyMMddTHHmm',
                'yyyyMMddTHH',
                'yyyyMMdd'
            ], RULE_NAMES = [
                'months',
                'weeks',
                'yearDays',
                'monthDays',
                'weekDays',
                'hours',
                'minutes',
                'seconds'
            ], RULE_NAMES_LENGTH = RULE_NAMES.length, RECURRENCE_DATE_FORMAT = 'yyyyMMddTHHmmssZ', limitation = {
                months: function (date, end, rule) {
                    var monthRules = rule.months, months = ruleValues(monthRules, date.getMonth() + 1), changed = false;
                    if (months !== null) {
                        if (months.length) {
                            date.setMonth(months[0] - 1, 1);
                        } else {
                            date.setFullYear(date.getFullYear() + 1, monthRules[0] - 1, 1);
                        }
                        changed = true;
                    }
                    return changed;
                },
                monthDays: function (date, end, rule) {
                    var monthLength, month, days, changed = false, hours = date.getHours(), normalize = function (monthDay) {
                            if (monthDay < 0) {
                                monthDay = monthLength + monthDay;
                            }
                            return monthDay;
                        };
                    while (date <= end) {
                        month = date.getMonth();
                        monthLength = getMonthLength(date);
                        days = ruleValues(rule.monthDays, date.getDate(), normalize);
                        if (days === null) {
                            return changed;
                        }
                        changed = true;
                        if (days.length) {
                            date.setMonth(month, days.sort(numberSortPredicate)[0]);
                            adjustDST(date, hours);
                            if (month === date.getMonth()) {
                                break;
                            }
                        } else {
                            date.setMonth(month + 1, 1);
                        }
                    }
                    return changed;
                },
                yearDays: function (date, end, rule) {
                    var year, yearDays, changed = false, hours = date.getHours(), normalize = function (yearDay) {
                            if (yearDay < 0) {
                                yearDay = year + yearDay;
                            }
                            return yearDay;
                        };
                    while (date < end) {
                        year = leapYear(date) ? 366 : 365;
                        yearDays = ruleValues(rule.yearDays, dayInYear(date), normalize);
                        if (yearDays === null) {
                            return changed;
                        }
                        changed = true;
                        year = date.getFullYear();
                        if (yearDays.length) {
                            date.setFullYear(year, 0, yearDays.sort(numberSortPredicate)[0]);
                            adjustDST(date, hours);
                            break;
                        } else {
                            date.setFullYear(year + 1, 0, 1);
                        }
                    }
                    return changed;
                },
                weeks: function (date, end, rule) {
                    var weekStart = rule.weekStart, year, weeks, day, changed = false, hours = date.getHours(), normalize = function (week) {
                            if (week < 0) {
                                week = 53 + week;
                            }
                            return week;
                        };
                    while (date < end) {
                        weeks = ruleValues(rule.weeks, weekInYear(date, weekStart), normalize);
                        if (weeks === null) {
                            return changed;
                        }
                        changed = true;
                        year = date.getFullYear();
                        if (weeks.length) {
                            day = weeks.sort(numberSortPredicate)[0] * 7 - 1;
                            date.setFullYear(year, 0, day);
                            setDayOfWeek(date, weekStart, -1);
                            adjustDST(date, hours);
                            break;
                        } else {
                            date.setFullYear(year + 1, 0, 1);
                        }
                    }
                    return changed;
                },
                weekDays: function (date, end, rule) {
                    var weekDays = rule.weekDays;
                    var weekStart = rule.weekStart;
                    var weekDayRules = ruleWeekValues(weekDays, date, weekStart);
                    var hours = date.getHours();
                    var weekDayRule, day;
                    if (weekDayRules === null) {
                        return false;
                    }
                    weekDayRule = weekDayRules[0];
                    if (!weekDayRule) {
                        weekDayRule = weekDays[0];
                        setDayOfWeek(date, weekStart);
                    }
                    day = weekDayRule.day;
                    if (weekDayRule.offset) {
                        while (date <= end && !isInWeek(date, weekDayRule, weekStart)) {
                            if (weekInMonth(date, weekStart) === numberOfWeeks(date, weekStart)) {
                                date.setMonth(date.getMonth() + 1, 1);
                                adjustDST(date, hours);
                            } else {
                                date.setDate(date.getDate() + 7);
                                adjustDST(date, hours);
                                setDayOfWeek(date, weekStart, -1);
                            }
                        }
                    }
                    if (date.getDay() !== day) {
                        setDayOfWeek(date, day);
                    }
                    return true;
                },
                hours: function (date, end, rule) {
                    var hourRules = rule.hours, startTime = rule._startTime, startHours = startTime.getHours(), hours = ruleValues(hourRules, startHours), changed = false;
                    if (hours !== null) {
                        changed = true;
                        date.setHours(startHours);
                        adjustDST(date, startHours);
                        if (hours.length) {
                            hours = hours[0];
                            date.setHours(hours);
                        } else {
                            hours = date.getHours();
                            date.setDate(date.getDate() + 1);
                            adjustDST(date, hours);
                            hours = hourRules[0];
                            date.setHours(hours);
                            adjustDST(date, hours);
                        }
                        if (rule.minutes) {
                            date.setMinutes(0);
                        }
                        startTime.setHours(hours, date.getMinutes());
                    }
                    return changed;
                },
                minutes: function (date, end, rule) {
                    var minuteRules = rule.minutes, currentMinutes = date.getMinutes(), minutes = ruleValues(minuteRules, currentMinutes), hours = rule._startTime.getHours(), changed = false;
                    if (minutes !== null) {
                        changed = true;
                        if (minutes.length) {
                            minutes = minutes[0];
                        } else {
                            hours += 1;
                            minutes = minuteRules[0];
                        }
                        if (rule.seconds) {
                            date.setSeconds(0);
                        }
                        date.setHours(hours, minutes);
                        hours = hours % 24;
                        adjustDST(date, hours);
                        rule._startTime.setHours(hours, minutes, date.getSeconds());
                    }
                    return changed;
                },
                seconds: function (date, end, rule) {
                    var secondRules = rule.seconds, hours = rule._startTime.getHours(), seconds = ruleValues(secondRules, date.getSeconds()), minutes = date.getMinutes(), changed = false;
                    if (seconds !== null) {
                        changed = true;
                        if (seconds.length) {
                            date.setSeconds(seconds[0]);
                        } else {
                            minutes += 1;
                            date.setMinutes(minutes, secondRules[0]);
                            if (minutes > 59) {
                                minutes = minutes % 60;
                                hours = (hours + 1) % 24;
                            }
                        }
                        rule._startTime.setHours(hours, minutes, date.getSeconds());
                    }
                    return changed;
                }
            }, BaseFrequency = Class.extend({
                next: function (date, rule) {
                    var startTime = rule._startTime, day = startTime.getDate(), minutes, seconds;
                    if (rule.seconds) {
                        seconds = date.getSeconds() + 1;
                        date.setSeconds(seconds);
                        startTime.setSeconds(seconds);
                        startTime.setDate(day);
                    } else if (rule.minutes) {
                        minutes = date.getMinutes() + 1;
                        date.setMinutes(minutes);
                        startTime.setMinutes(minutes);
                        startTime.setDate(day);
                    } else {
                        return false;
                    }
                    return true;
                },
                normalize: function (options) {
                    var rule = options.rule;
                    if (options.idx === 4 && rule.hours) {
                        rule._startTime.setHours(0);
                        this._hour(options.date, rule);
                    }
                },
                limit: function (date, end, rule) {
                    var interval = rule.interval, ruleName, firstRule, modified, idx, day;
                    while (date <= end) {
                        modified = firstRule = undefined;
                        day = date.getDate();
                        for (idx = 0; idx < RULE_NAMES_LENGTH; idx++) {
                            ruleName = RULE_NAMES[idx];
                            if (rule[ruleName]) {
                                modified = limitation[ruleName](date, end, rule);
                                if (firstRule !== undefined && modified) {
                                    break;
                                } else {
                                    firstRule = modified;
                                }
                            }
                            if (modified) {
                                this.normalize({
                                    date: date,
                                    rule: rule,
                                    day: day,
                                    idx: idx
                                });
                            }
                        }
                        if ((interval === 1 || !this.interval(rule, date)) && idx === RULE_NAMES_LENGTH) {
                            break;
                        }
                    }
                },
                interval: function (rule, current) {
                    var start = new Date(rule._startPeriod);
                    var date = new Date(current);
                    var hours = current.getHours();
                    var weekStart = rule.weekStart;
                    var interval = rule.interval;
                    var frequency = rule.freq;
                    var modified = false;
                    var excess = 0;
                    var month = 0;
                    var day = 1;
                    var diff;
                    var startTimeHours;
                    if (frequency === 'hourly') {
                        diff = date.getTimezoneOffset() - start.getTimezoneOffset();
                        startTimeHours = rule._startTime.getHours();
                        date = date.getTime();
                        if (hours !== startTimeHours) {
                            date += (startTimeHours - hours) * kendoDate.MS_PER_HOUR;
                        }
                        date -= start;
                        if (diff) {
                            date -= diff * kendoDate.MS_PER_MINUTE;
                        }
                        diff = Math.floor(date / kendoDate.MS_PER_HOUR);
                        excess = intervalExcess(diff, interval);
                        if (excess !== 0) {
                            this._hour(current, rule, excess);
                            modified = true;
                        }
                    } else if (frequency === 'daily') {
                        kendoDate.setTime(date, -start, true);
                        diff = Math.ceil(date / kendoDate.MS_PER_DAY);
                        excess = intervalExcess(diff, interval);
                        if (excess !== 0) {
                            this._date(current, rule, excess);
                            modified = true;
                        }
                    } else if (frequency === 'weekly') {
                        excess = this._getNumberOfWeeksBetweenDates(start, current);
                        var normalizedCurrentIndex = normalizeDayIndex(current.getDay(), weekStart);
                        var normalizedStartIndex = normalizeDayIndex(start.getDay(), weekStart);
                        if (normalizedCurrentIndex < normalizedStartIndex) {
                            excess += 1;
                        }
                        excess = intervalExcess(excess, interval);
                        if (excess !== 0) {
                            kendoDate.setDayOfWeek(current, rule.weekStart, -1);
                            current.setDate(current.getDate() + excess * 7);
                            adjustDST(current, hours);
                            modified = true;
                        }
                    } else if (frequency === 'monthly') {
                        diff = current.getFullYear() - start.getFullYear();
                        diff = current.getMonth() - start.getMonth() + diff * 12;
                        excess = intervalExcess(diff, interval);
                        if (excess !== 0) {
                            day = rule._hasRuleValue ? 1 : current.getDate();
                            current.setFullYear(current.getFullYear(), current.getMonth() + excess, day);
                            adjustDST(current, hours);
                            modified = true;
                        }
                    } else if (frequency === 'yearly') {
                        diff = current.getFullYear() - start.getFullYear();
                        excess = intervalExcess(diff, interval);
                        if (!rule.months) {
                            month = current.getMonth();
                        }
                        if (!rule.yearDays && !rule.monthDays && !rule.weekDays) {
                            day = current.getDate();
                        }
                        if (excess !== 0) {
                            current.setFullYear(current.getFullYear() + excess, month, day);
                            adjustDST(current, hours);
                            modified = true;
                        }
                    }
                    return modified;
                },
                _getNumberOfWeeksBetweenDates: function (first, second) {
                    var weeks = (second - first) / 604800000;
                    var exactWeeks = Math.floor(weeks);
                    if (weeks - exactWeeks > 0.99) {
                        exactWeeks = Math.round(weeks);
                    }
                    return exactWeeks;
                },
                _hour: function (date, rule, interval) {
                    var startTime = rule._startTime, hours = startTime.getHours();
                    if (interval) {
                        hours += interval;
                    }
                    date.setHours(hours);
                    hours = hours % 24;
                    startTime.setHours(hours);
                    adjustDST(date, hours);
                },
                _date: function (date, rule, interval) {
                    var hours = date.getHours();
                    date.setDate(date.getDate() + interval);
                    if (!adjustDST(date, hours)) {
                        this._hour(date, rule);
                    }
                }
            }), HourlyFrequency = BaseFrequency.extend({
                next: function (date, rule) {
                    if (!BaseFrequency.fn.next(date, rule)) {
                        this._hour(date, rule, 1);
                    }
                },
                normalize: function (options) {
                    var rule = options.rule;
                    if (options.idx === 4) {
                        rule._startTime.setHours(0);
                        this._hour(options.date, rule);
                    }
                }
            }), DailyFrequency = BaseFrequency.extend({
                next: function (date, rule) {
                    if (!BaseFrequency.fn.next(date, rule)) {
                        this[rule.hours ? '_hour' : '_date'](date, rule, 1);
                    }
                }
            }), WeeklyFrequency = DailyFrequency.extend({
                setup: function (rule, eventStartDate) {
                    if (!rule.weekDays) {
                        rule.weekDays = [{
                                day: eventStartDate.getDay(),
                                offset: 0
                            }];
                    }
                }
            }), MonthlyFrequency = BaseFrequency.extend({
                next: function (date, rule) {
                    var day, hours;
                    if (!BaseFrequency.fn.next(date, rule)) {
                        if (rule.hours) {
                            this._hour(date, rule, 1);
                        } else if (rule.monthDays || rule.weekDays || rule.yearDays || rule.weeks) {
                            this._date(date, rule, 1);
                        } else {
                            day = date.getDate();
                            hours = date.getHours();
                            date.setMonth(date.getMonth() + 1);
                            adjustDST(date, hours);
                            while (date.getDate() !== day) {
                                date.setDate(day);
                                adjustDST(date, hours);
                            }
                            this._hour(date, rule);
                        }
                    }
                },
                normalize: function (options) {
                    var rule = options.rule, date = options.date, hours = date.getHours();
                    if (options.idx === 0 && !rule.monthDays && !rule.weekDays) {
                        date.setDate(options.day);
                        adjustDST(date, hours);
                    } else {
                        BaseFrequency.fn.normalize(options);
                    }
                },
                setup: function (rule, eventStartDate, date) {
                    if (!rule.monthDays && !rule.weekDays) {
                        date.setDate(eventStartDate.getDate());
                    }
                }
            }), YearlyFrequency = MonthlyFrequency.extend({
                next: function (date, rule) {
                    var day, hours = date.getHours();
                    if (!BaseFrequency.fn.next(date, rule)) {
                        if (rule.hours) {
                            this._hour(date, rule, 1);
                        } else if (rule.monthDays || rule.weekDays || rule.yearDays || rule.weeks) {
                            this._date(date, rule, 1);
                        } else if (rule.months) {
                            day = date.getDate();
                            date.setMonth(date.getMonth() + 1);
                            adjustDST(date, hours);
                            while (date.getDate() !== day) {
                                date.setDate(day);
                                adjustDST(date, hours);
                            }
                            this._hour(date, rule);
                        } else {
                            date.setFullYear(date.getFullYear() + 1);
                            adjustDST(date, hours);
                            this._hour(date, rule);
                        }
                    }
                },
                setup: function () {
                }
            }), frequencies = {
                'hourly': new HourlyFrequency(),
                'daily': new DailyFrequency(),
                'weekly': new WeeklyFrequency(),
                'monthly': new MonthlyFrequency(),
                'yearly': new YearlyFrequency()
            }, CLICK = 'click';
        function intervalExcess(diff, interval) {
            var excess;
            if (diff !== 0 && diff < interval) {
                excess = interval - diff;
            } else {
                excess = diff % interval;
                if (excess) {
                    excess = interval - excess;
                }
            }
            return excess;
        }
        function dayInYear(date) {
            var month = date.getMonth();
            var days = leapYear(date) ? DAYS_IN_LEAPYEAR[month] : DAYS_IN_YEAR[month];
            return days + date.getDate();
        }
        function weekInYear(date, weekStart) {
            var year, days;
            date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
            adjustDST(date, 0);
            year = date.getFullYear();
            if (weekStart !== undefined) {
                setDayOfWeek(date, weekStart, -1);
                date.setDate(date.getDate() + 4);
            } else {
                date.setDate(date.getDate() + (4 - (date.getDay() || 7)));
            }
            adjustDST(date, 0);
            days = Math.floor((date.getTime() - new Date(year, 0, 1, -6)) / 86400000);
            return 1 + Math.floor(days / 7);
        }
        function weekInMonth(date, weekStart) {
            var firstWeekDay = firstDayOfMonth(date).getDay();
            var firstWeekLength = 7 - (firstWeekDay + 7 - (weekStart || 7)) || 7;
            if (firstWeekLength < 0) {
                firstWeekLength += 7;
            }
            return Math.ceil((date.getDate() - firstWeekLength) / 7) + 1;
        }
        function normalizeDayIndex(weekDay, weekStart) {
            return weekDay + (weekDay < weekStart ? 7 : 0);
        }
        function normalizeOffset(date, rule, weekStart) {
            var offset = rule.offset;
            if (!offset) {
                return weekInMonth(date, weekStart);
            }
            var lastDate = new Date(date.getFullYear(), date.getMonth() + 1, 0);
            var weeksInMonth = weekInMonth(lastDate, weekStart);
            var day = normalizeDayIndex(rule.day, weekStart);
            var skipFirst = day < normalizeDayIndex(new Date(date.getFullYear(), date.getMonth(), 1).getDay(), weekStart);
            var skipLast = day > normalizeDayIndex(lastDate.getDay(), weekStart);
            if (offset < 0) {
                offset = weeksInMonth + (offset + 1 - (skipLast ? 1 : 0));
            } else if (skipFirst) {
                offset += 1;
            }
            weeksInMonth -= skipLast ? 1 : 0;
            if (offset < (skipFirst ? 1 : 0) || offset > weeksInMonth) {
                return null;
            }
            return offset;
        }
        function numberOfWeeks(date, weekStart) {
            return weekInMonth(new Date(date.getFullYear(), date.getMonth() + 1, 0), weekStart);
        }
        function isInWeek(date, rule, weekStart) {
            return weekInMonth(date, weekStart) === normalizeOffset(date, rule, weekStart);
        }
        function ruleWeekValues(weekDays, date, weekStart) {
            var currentDay = normalizeDayIndex(date.getDay(), weekStart);
            var length = weekDays.length;
            var ruleWeekOffset;
            var weekDay, day;
            var weekNumber;
            var result = [];
            var idx = 0;
            for (; idx < length; idx++) {
                weekDay = weekDays[idx];
                weekNumber = weekInMonth(date, weekStart);
                ruleWeekOffset = normalizeOffset(date, weekDay, weekStart);
                if (ruleWeekOffset === null) {
                    continue;
                }
                if (weekNumber < ruleWeekOffset) {
                    result.push(weekDay);
                } else if (weekNumber === ruleWeekOffset) {
                    day = normalizeDayIndex(weekDay.day, weekStart);
                    if (currentDay < day) {
                        result.push(weekDay);
                    } else if (currentDay === day) {
                        return null;
                    }
                }
            }
            return result;
        }
        function ruleValues(rules, value, normalize) {
            var idx = 0, length = rules.length, availableRules = [], ruleValue;
            for (; idx < length; idx++) {
                ruleValue = rules[idx];
                if (normalize) {
                    ruleValue = normalize(ruleValue);
                }
                if (value === ruleValue) {
                    return null;
                } else if (value < ruleValue) {
                    availableRules.push(ruleValue);
                }
            }
            return availableRules;
        }
        function parseArray(list, range) {
            var idx = 0, length = list.length, value;
            for (; idx < length; idx++) {
                value = parseInt(list[idx], 10);
                if (isNaN(value) || value < range.start || value > range.end || value === 0 && range.start < 0) {
                    return null;
                }
                list[idx] = value;
            }
            return list.sort(numberSortPredicate);
        }
        function parseWeekDayList(list) {
            var idx = 0, length = list.length, value, valueLength, day;
            for (; idx < length; idx++) {
                value = list[idx];
                valueLength = value.length;
                day = value.substring(valueLength - 2).toUpperCase();
                day = WEEK_DAYS_IDX[day];
                if (day === undefined) {
                    return null;
                }
                list[idx] = {
                    offset: parseInt(value.substring(0, valueLength - 2), 10) || 0,
                    day: day
                };
            }
            return list;
        }
        function serializeWeekDayList(list) {
            var idx = 0, length = list.length, value, valueString, result = [];
            for (; idx < length; idx++) {
                value = list[idx];
                if (typeof value === 'string') {
                    valueString = value;
                } else {
                    valueString = '' + WEEK_DAYS[value.day];
                    if (value.offset) {
                        valueString = value.offset + valueString;
                    }
                }
                result.push(valueString);
            }
            return result.toString();
        }
        function getMonthLength(date) {
            var month = date.getMonth();
            if (month === 1) {
                if (new Date(date.getFullYear(), 1, 29).getMonth() === 1) {
                    return 29;
                }
                return 28;
            }
            return MONTHS[month];
        }
        function leapYear(year) {
            year = year.getFullYear();
            return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
        }
        function numberSortPredicate(a, b) {
            return a - b;
        }
        function parseExceptions(exceptions, zone) {
            var idx = 0, length, date, dates = [];
            if (exceptions) {
                exceptions = exceptions.split(exceptions.indexOf(';') !== -1 ? ';' : ',');
                length = exceptions.length;
                for (; idx < length; idx++) {
                    date = parseUTCDate(exceptions[idx], zone);
                    if (date) {
                        dates.push(date);
                    }
                }
            }
            return dates;
        }
        function isException(exceptions, date, zone) {
            var dates = $.isArray(exceptions) ? exceptions : parseExceptions(exceptions, zone), dateTime = date.getTime() - date.getMilliseconds(), idx = 0, length = dates.length;
            for (; idx < length; idx++) {
                if (dates[idx].getTime() === dateTime) {
                    return true;
                }
            }
            return false;
        }
        function toExceptionString(dates, zone) {
            var idx = 0;
            var length;
            var date;
            var result = [].concat(dates);
            for (length = result.length; idx < length; idx++) {
                date = result[idx];
                date = kendo.timezone.convert(date, zone || date.getTimezoneOffset(), 'Etc/UTC');
                result[idx] = kendo.toString(date, RECURRENCE_DATE_FORMAT);
            }
            return result.join(',');
        }
        function startPeriodByFreq(start, rule) {
            var date = new Date(start);
            switch (rule.freq) {
            case 'yearly':
                date.setFullYear(date.getFullYear(), 0, 1);
                break;
            case 'monthly':
                date.setFullYear(date.getFullYear(), date.getMonth(), 1);
                break;
            case 'weekly':
                setDayOfWeek(date, rule.weekStart, -1);
                break;
            default:
                break;
            }
            if (rule.hours) {
                date.setHours(0);
            }
            if (rule.minutes) {
                date.setMinutes(0);
            }
            if (rule.seconds) {
                date.setSeconds(0);
            }
            return date;
        }
        function endPeriodByFreq(start, rule) {
            var date = new Date(start);
            switch (rule.freq) {
            case 'yearly':
                date.setFullYear(date.getFullYear(), 11, 31);
                break;
            case 'monthly':
                date.setFullYear(date.getFullYear(), date.getMonth() + 1, 0);
                break;
            case 'weekly':
                setDayOfWeek(date, rule.weekStart, -1);
                date.setDate(date.getDate() + 6);
                break;
            default:
                break;
            }
            if (rule.hours) {
                date.setHours(23);
            }
            if (rule.minutes) {
                date.setMinutes(59);
            }
            if (rule.seconds) {
                date.setSeconds(59);
            }
            return date;
        }
        function eventsByPosition(periodEvents, start, positions) {
            var periodEventsLength = periodEvents.length;
            var events = [];
            var position;
            var event;
            for (var idx = 0, length = positions.length; idx < length; idx++) {
                position = positions[idx];
                if (position < 0) {
                    position = periodEventsLength + position;
                } else {
                    position -= 1;
                }
                event = periodEvents[position];
                if (event && event.start >= start) {
                    events.push(event);
                }
            }
            return events;
        }
        function removeExceptionDates(periodEvents, exceptionDates, zone) {
            var events = [];
            var event;
            for (var idx = 0; idx < periodEvents.length; idx++) {
                event = periodEvents[idx];
                if (!isException(exceptionDates, event.start, zone)) {
                    events.push(event);
                }
            }
            return events;
        }
        function expand(event, start, end, zone) {
            var rule = parseRule(event.recurrenceRule, zone), startTime, endTime, endDate, hours, minutes, seconds, durationMS, startPeriod, inPeriod, ruleStart, ruleEnd, useEventStart, freqName, exceptionDates, eventStartTime, eventStartMS, eventStart, count, freq, positions, currentIdx, periodEvents, events = [];
            if (!rule) {
                return [event];
            }
            positions = rule.positions;
            currentIdx = positions ? 0 : 1;
            ruleStart = rule.start;
            ruleEnd = rule.end;
            if (ruleStart || ruleEnd) {
                event = event.clone({
                    start: ruleStart ? new Date(ruleStart.value[0]) : undefined,
                    end: ruleEnd ? new Date(ruleEnd.value[0]) : undefined
                });
            }
            eventStart = event.start;
            eventStartMS = eventStart.getTime();
            eventStartTime = getMilliseconds(eventStart);
            exceptionDates = parseExceptions(event.recurrenceException, zone);
            if (!exceptionDates[0] && rule.exdates) {
                exceptionDates = rule.exdates.value;
                event.set('recurrenceException', toExceptionString(exceptionDates, zone));
            }
            startPeriod = start = new Date(start);
            end = new Date(end);
            freqName = rule.freq;
            freq = frequencies[freqName];
            count = rule.count;
            if (rule.until && rule.until < end) {
                end = new Date(rule.until);
            }
            useEventStart = freqName === 'yearly' || freqName === 'monthly' || freqName === 'weekly';
            if (start < eventStartMS || count || rule.interval > 1 || useEventStart) {
                start = new Date(eventStartMS);
            } else {
                hours = start.getHours();
                minutes = start.getMinutes();
                seconds = start.getSeconds();
                if (!rule.hours) {
                    hours = eventStart.getHours();
                }
                if (!rule.minutes) {
                    minutes = eventStart.getMinutes();
                }
                if (!rule.seconds) {
                    seconds = eventStart.getSeconds();
                }
                start.setHours(hours, minutes, seconds, eventStart.getMilliseconds());
            }
            rule._startPeriod = new Date(start);
            if (positions) {
                start = startPeriodByFreq(start, rule);
                end = endPeriodByFreq(end, rule);
                var diff = getMilliseconds(end) - getMilliseconds(start);
                if (diff < 0) {
                    hours = start.getHours();
                    end.setHours(hours, start.getMinutes(), start.getSeconds(), start.getMilliseconds());
                    kendoDate.adjustDST(end, hours);
                }
                rule._startPeriod = new Date(start);
                rule._endPeriod = endPeriodByFreq(start, rule);
            }
            durationMS = event.duration();
            rule._startTime = startTime = kendoDate.toInvariantTime(start);
            if (freq.setup) {
                freq.setup(rule, eventStart, start);
            }
            freq.limit(start, end, rule);
            while (start <= end) {
                endDate = new Date(start);
                setTime(endDate, durationMS);
                inPeriod = start >= startPeriod || endDate > startPeriod;
                if (inPeriod && !isException(exceptionDates, start, zone) || positions) {
                    startTime = kendoDate.toUtcTime(kendoDate.getDate(start)) + getMilliseconds(rule._startTime);
                    endTime = startTime + durationMS;
                    if (eventStartMS !== start.getTime() || eventStartTime !== getMilliseconds(rule._startTime)) {
                        events.push(event.toOccurrence({
                            start: new Date(start),
                            end: endDate,
                            _startTime: startTime,
                            _endTime: endTime
                        }));
                    } else {
                        event._startTime = startTime;
                        event._endTime = endTime;
                        events.push(event);
                    }
                }
                if (positions) {
                    freq.next(start, rule);
                    freq.limit(start, end, rule);
                    if (start > rule._endPeriod) {
                        periodEvents = eventsByPosition(events.slice(currentIdx), eventStart, positions);
                        periodEvents = removeExceptionDates(periodEvents, exceptionDates, zone);
                        events = events.slice(0, currentIdx).concat(periodEvents);
                        rule._endPeriod = endPeriodByFreq(start, rule);
                        currentIdx = events.length;
                    }
                    if (count && count === currentIdx) {
                        break;
                    }
                } else {
                    if (count && count === currentIdx) {
                        break;
                    }
                    currentIdx += 1;
                    freq.next(start, rule);
                    freq.limit(start, end, rule);
                }
            }
            return events;
        }
        function parseUTCDate(value, zone) {
            value = kendo.parseDate(value, DATE_FORMATS);
            if (value && zone) {
                value = timezone.convert(value, value.getTimezoneOffset(), zone);
            }
            return value;
        }
        function parseDateRule(dateRule, zone) {
            var pairs = dateRule.split(';');
            var pair;
            var property;
            var value;
            var tzid;
            var valueIdx, valueLength;
            for (var idx = 0, length = pairs.length; idx < length; idx++) {
                pair = pairs[idx].split(':');
                property = pair[0];
                value = pair[1];
                if (property.indexOf('TZID') !== -1) {
                    tzid = property.substring(property.indexOf('TZID')).split('=')[1];
                }
                if (value) {
                    value = value.split(',');
                    for (valueIdx = 0, valueLength = value.length; valueIdx < valueLength; valueIdx++) {
                        value[valueIdx] = parseUTCDate(value[valueIdx], tzid || zone);
                    }
                }
            }
            if (value) {
                return {
                    value: value,
                    tzid: tzid
                };
            }
        }
        function parseRule(recur, zone) {
            var instance = {};
            var splits, value;
            var idx = 0, length;
            var ruleValue = false;
            var rule, part, parts;
            var property, weekStart, weekDays;
            var predicate = function (a, b) {
                var day1 = a.day, day2 = b.day;
                if (day1 < weekStart) {
                    day1 += 7;
                }
                if (day2 < weekStart) {
                    day2 += 7;
                }
                return day1 - day2;
            };
            if (!recur) {
                return null;
            }
            parts = recur.split('\n');
            if (!parts[1] && (recur.indexOf('DTSTART') !== -1 || recur.indexOf('DTEND') !== -1 || recur.indexOf('EXDATE') !== -1)) {
                parts = recur.split(' ');
            }
            for (idx = 0, length = parts.length; idx < length; idx++) {
                part = $.trim(parts[idx]);
                if (part.indexOf('DTSTART') !== -1) {
                    instance.start = parseDateRule(part, zone);
                } else if (part.indexOf('DTEND') !== -1) {
                    instance.end = parseDateRule(part, zone);
                } else if (part.indexOf('EXDATE') !== -1) {
                    instance.exdates = parseDateRule(part, zone);
                } else if (part.indexOf('RRULE') !== -1) {
                    rule = part.substring(6);
                } else if ($.trim(part)) {
                    rule = part;
                }
            }
            rule = rule.split(';');
            for (idx = 0, length = rule.length; idx < length; idx++) {
                property = rule[idx];
                splits = property.split('=');
                value = $.trim(splits[1]).split(',');
                switch ($.trim(splits[0]).toUpperCase()) {
                case 'FREQ':
                    instance.freq = value[0].toLowerCase();
                    break;
                case 'UNTIL':
                    instance.until = parseUTCDate(value[0], zone);
                    break;
                case 'COUNT':
                    instance.count = parseInt(value[0], 10);
                    break;
                case 'INTERVAL':
                    instance.interval = parseInt(value[0], 10);
                    break;
                case 'BYSECOND':
                    instance.seconds = parseArray(value, {
                        start: 0,
                        end: 60
                    });
                    ruleValue = true;
                    break;
                case 'BYMINUTE':
                    instance.minutes = parseArray(value, {
                        start: 0,
                        end: 59
                    });
                    ruleValue = true;
                    break;
                case 'BYHOUR':
                    instance.hours = parseArray(value, {
                        start: 0,
                        end: 23
                    });
                    ruleValue = true;
                    break;
                case 'BYMONTHDAY':
                    instance.monthDays = parseArray(value, {
                        start: -31,
                        end: 31
                    });
                    ruleValue = true;
                    break;
                case 'BYYEARDAY':
                    instance.yearDays = parseArray(value, {
                        start: -366,
                        end: 366
                    });
                    ruleValue = true;
                    break;
                case 'BYMONTH':
                    instance.months = parseArray(value, {
                        start: 1,
                        end: 12
                    });
                    ruleValue = true;
                    break;
                case 'BYDAY':
                    instance.weekDays = weekDays = parseWeekDayList(value);
                    ruleValue = true;
                    break;
                case 'BYWEEKNO':
                    instance.weeks = parseArray(value, {
                        start: -53,
                        end: 53
                    });
                    ruleValue = true;
                    break;
                case 'BYSETPOS':
                    instance.positions = parseArray(value, {
                        start: -366,
                        end: 366
                    });
                    break;
                case 'WKST':
                    instance.weekStart = weekStart = WEEK_DAYS_IDX[value[0]];
                    break;
                }
            }
            if (instance.freq === undefined || instance.count !== undefined && instance.until) {
                return null;
            }
            if (!instance.interval) {
                instance.interval = 1;
            }
            if (weekStart === undefined) {
                instance.weekStart = weekStart = kendo.culture().calendar.firstDay;
            }
            if (weekDays) {
                instance.weekDays = weekDays.sort(predicate);
            }
            if (instance.positions && !ruleValue) {
                instance.positions = null;
            }
            instance._hasRuleValue = ruleValue;
            return instance;
        }
        function serializeDateRule(dateRule, zone) {
            var value = dateRule.value;
            var tzid = dateRule.tzid || '';
            var length = value.length;
            var idx = 0;
            var val;
            for (; idx < length; idx++) {
                val = value[idx];
                val = timezone.convert(val, tzid || zone || val.getTimezoneOffset(), 'Etc/UTC');
                value[idx] = kendo.toString(val, 'yyyyMMddTHHmmssZ');
            }
            if (tzid) {
                tzid = ';TZID=' + tzid;
            }
            return tzid + ':' + value.join(',') + ' ';
        }
        function serialize(rule, zone) {
            var weekStart = rule.weekStart;
            var ruleString = 'FREQ=' + rule.freq.toUpperCase();
            var exdates = rule.exdates || '';
            var start = rule.start || '';
            var end = rule.end || '';
            var until = rule.until;
            if (rule.interval > 1) {
                ruleString += ';INTERVAL=' + rule.interval;
            }
            if (rule.count) {
                ruleString += ';COUNT=' + rule.count;
            }
            if (until) {
                until = timezone.convert(until, zone || until.getTimezoneOffset(), 'Etc/UTC');
                ruleString += ';UNTIL=' + kendo.toString(until, 'yyyyMMddTHHmmssZ');
            }
            if (rule.months) {
                ruleString += ';BYMONTH=' + rule.months;
            }
            if (rule.weeks) {
                ruleString += ';BYWEEKNO=' + rule.weeks;
            }
            if (rule.yearDays) {
                ruleString += ';BYYEARDAY=' + rule.yearDays;
            }
            if (rule.monthDays) {
                ruleString += ';BYMONTHDAY=' + rule.monthDays;
            }
            if (rule.weekDays) {
                ruleString += ';BYDAY=' + serializeWeekDayList(rule.weekDays);
            }
            if (rule.hours) {
                ruleString += ';BYHOUR=' + rule.hours;
            }
            if (rule.minutes) {
                ruleString += ';BYMINUTE=' + rule.minutes;
            }
            if (rule.seconds) {
                ruleString += ';BYSECOND=' + rule.seconds;
            }
            if (rule.positions) {
                ruleString += ';BYSETPOS=' + rule.positions;
            }
            if (weekStart !== undefined) {
                ruleString += ';WKST=' + WEEK_DAYS[weekStart];
            }
            if (start) {
                start = 'DTSTART' + serializeDateRule(start, zone);
            }
            if (end) {
                end = 'DTEND' + serializeDateRule(end, zone);
            }
            if (exdates) {
                exdates = 'EXDATE' + serializeDateRule(exdates, zone);
            }
            if (start || end || exdates) {
                ruleString = start + end + exdates + 'RRULE:' + ruleString;
            }
            return ruleString;
        }
        kendo.recurrence = {
            rule: {
                parse: parseRule,
                serialize: serialize
            },
            expand: expand,
            dayInYear: dayInYear,
            weekInYear: weekInYear,
            weekInMonth: weekInMonth,
            numberOfWeeks: numberOfWeeks,
            isException: isException,
            toExceptionString: toExceptionString
        };
        var weekDayCheckBoxes = function (firstDay) {
            var shortNames = kendo.culture().calendar.days.namesShort, length = shortNames.length, result = '', idx = 0, values = [];
            for (; idx < length; idx++) {
                values.push(idx);
            }
            shortNames = shortNames.slice(firstDay).concat(shortNames.slice(0, firstDay));
            values = values.slice(firstDay).concat(values.slice(0, firstDay));
            for (idx = 0; idx < length; idx++) {
                result += '<label class="k-check"><input class="k-recur-weekday-checkbox" type="checkbox" value="' + values[idx] + '" /> ' + shortNames[idx] + '</label>';
            }
            return result;
        };
        var RECURRENCE_VIEW_TEMPLATE = kendo.template('# if (frequency !== "never") { #' + '<div class="k-edit-label"><label>#:messages.repeatEvery#</label></div>' + '<div class="k-edit-field"><input class="k-recur-interval" title="#:messages.interval#"/>#:messages.interval#</div>' + '# } #' + '# if (frequency === "weekly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">#=weekDayCheckBoxes(firstWeekDay)#</div>' + '# } else if (frequency === "monthly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">' + '<ul class="k-reset">' + '<li>' + '<label><input class="k-recur-month-radio" type="radio" name="month" value="monthday" title="#:messages.day#" />#:messages.day#</label>' + '<input class="k-recur-monthday" title="#:messages.day#" />' + '</li>' + '<li>' + '<input class="k-recur-month-radio" type="radio" name="month" value="weekday" title="#:messages.repeatOn#" />' + '<input class="k-recur-weekday-offset" title="#:messages.repeatOn#" /><input class="k-recur-weekday" title="#:messages.day#" />' + '</li>' + '</ul>' + '</div>' + '# } else if (frequency === "yearly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">' + '<ul class="k-reset">' + '<li>' + '<input class="k-recur-year-radio" type="radio" name="year" value="monthday" title="#:messages.repeatOn#" />' + '<input class="k-recur-month" title="#:messages.repeatOn#" /><input class="k-recur-monthday" title="#:messages.day#" />' + '</li>' + '<li>' + '<input class="k-recur-year-radio" type="radio" name="year" value="weekday" title="#:messages.repeatOn#" />' + '<input class="k-recur-weekday-offset" title="#:messages.repeatOn#" /><input class="k-recur-weekday" title="#:messages.day#"  />#:messages.of#<input class="k-recur-month" title="#:messages.of#"/>' + '</li>' + '</ul>' + '</div>' + '# } #' + '# if (frequency !== "never") { #' + '<div class="k-edit-label"><label>#:end.label#</label></div>' + '<div class="k-edit-field">' + '<ul class="k-reset">' + '<li>' + '<label><input class="k-recur-end-never" type="radio" name="end" value="never" />#:end.never#</label>' + '</li>' + '<li>' + '<label><input class="k-recur-end-count" type="radio" name="end" value="count" />#:end.after#</label>' + '<input class="k-recur-count" title="#:end.occurrence#" />#:end.occurrence#' + '</li>' + '<li>' + '<label><input class="k-recur-end-until" type="radio" name="end" value="until" />#:end.on#</label>' + '<input class="k-recur-until" title="#:end.on#" />' + '</li>' + '</ul>' + '</div>' + '# } #');
        var DAY_RULE = [
            {
                day: 0,
                offset: 0
            },
            {
                day: 1,
                offset: 0
            },
            {
                day: 2,
                offset: 0
            },
            {
                day: 3,
                offset: 0
            },
            {
                day: 4,
                offset: 0
            },
            {
                day: 5,
                offset: 0
            },
            {
                day: 6,
                offset: 0
            }
        ];
        var WEEKDAY_RULE = [
            {
                day: 1,
                offset: 0
            },
            {
                day: 2,
                offset: 0
            },
            {
                day: 3,
                offset: 0
            },
            {
                day: 4,
                offset: 0
            },
            {
                day: 5,
                offset: 0
            }
        ];
        var WEEKEND_RULE = [
            {
                day: 0,
                offset: 0
            },
            {
                day: 6,
                offset: 0
            }
        ];
        var BaseRecurrenceEditor = Widget.extend({
            init: function (element, options) {
                var start;
                var that = this;
                var frequencies = options && options.frequencies;
                Widget.fn.init.call(that, element, options);
                that.wrapper = that.element;
                options = that.options;
                options.start = start = options.start || kendoDate.today();
                if (frequencies) {
                    options.frequencies = frequencies;
                }
                if (typeof start === 'string') {
                    options.start = kendo.parseDate(start, 'yyyyMMddTHHmmss');
                }
                if (options.firstWeekDay === null) {
                    options.firstWeekDay = kendo.culture().calendar.firstDay;
                }
                that._namespace = '.' + options.name;
            },
            options: {
                value: '',
                start: '',
                timezone: '',
                spinners: true,
                firstWeekDay: null,
                frequencies: [
                    'never',
                    'daily',
                    'weekly',
                    'monthly',
                    'yearly'
                ],
                mobile: false,
                messages: {
                    recurrenceEditorTitle: 'Recurrence editor',
                    frequencies: {
                        never: 'Never',
                        hourly: 'Hourly',
                        daily: 'Daily',
                        weekly: 'Weekly',
                        monthly: 'Monthly',
                        yearly: 'Yearly'
                    },
                    hourly: {
                        repeatEvery: 'Repeat every: ',
                        interval: ' hour(s)'
                    },
                    daily: {
                        repeatEvery: 'Repeat every: ',
                        interval: ' day(s)'
                    },
                    weekly: {
                        interval: ' week(s)',
                        repeatEvery: 'Repeat every: ',
                        repeatOn: 'Repeat on: '
                    },
                    monthly: {
                        repeatEvery: 'Repeat every: ',
                        repeatOn: 'Repeat on: ',
                        interval: ' month(s)',
                        day: 'Day '
                    },
                    yearly: {
                        repeatEvery: 'Repeat every: ',
                        repeatOn: 'Repeat on: ',
                        interval: ' year(s)',
                        of: ' of '
                    },
                    end: {
                        label: 'End:',
                        mobileLabel: 'Ends',
                        never: 'Never',
                        after: 'After ',
                        occurrence: ' occurrence(s)',
                        on: 'On '
                    },
                    offsetPositions: {
                        first: 'first',
                        second: 'second',
                        third: 'third',
                        fourth: 'fourth',
                        last: 'last'
                    },
                    weekdays: {
                        day: 'day',
                        weekday: 'weekday',
                        weekend: 'weekend day'
                    }
                }
            },
            events: ['change'],
            _initInterval: function () {
                var that = this;
                var rule = that._value;
                that._container.find('.k-recur-interval').kendoNumericTextBox({
                    spinners: that.options.spinners,
                    value: rule.interval || 1,
                    decimals: 0,
                    format: '#',
                    min: 1,
                    change: function () {
                        rule.interval = this.value();
                        that._trigger();
                    }
                });
            },
            _weekDayRule: function (clear) {
                var that = this;
                var weekday = (that._weekDay.element || that._weekDay).val();
                var offset = Number((that._weekDayOffset.element || that._weekDayOffset).val());
                var weekDays = null;
                var positions = null;
                if (!clear) {
                    if (weekday === 'day') {
                        weekDays = DAY_RULE;
                        positions = offset;
                    } else if (weekday === 'weekday') {
                        weekDays = WEEKDAY_RULE;
                        positions = offset;
                    } else if (weekday === 'weekend') {
                        weekDays = WEEKEND_RULE;
                        positions = offset;
                    } else {
                        weekDays = [{
                                offset: offset,
                                day: Number(weekday)
                            }];
                    }
                }
                that._value.weekDays = weekDays;
                that._value.positions = positions;
            },
            _weekDayView: function () {
                var that = this;
                var weekDays = that._value.weekDays;
                var positions = that._value.positions;
                var weekDayOffsetWidget = that._weekDayOffset;
                var weekDayOffset;
                var weekDayValue;
                var length;
                var method;
                if (weekDays) {
                    length = weekDays.length;
                    if (positions) {
                        if (length === 7) {
                            weekDayValue = 'day';
                            weekDayOffset = positions;
                        } else if (length === 5) {
                            weekDayValue = 'weekday';
                            weekDayOffset = positions;
                        } else if (length === 2) {
                            weekDayValue = 'weekend';
                            weekDayOffset = positions;
                        }
                    }
                    if (!weekDayValue) {
                        weekDays = weekDays[0];
                        weekDayValue = weekDays.day;
                        weekDayOffset = weekDays.offset || '';
                    }
                    method = weekDayOffsetWidget.value ? 'value' : 'val';
                    weekDayOffsetWidget[method](weekDayOffset);
                    that._weekDay[method](weekDayValue);
                }
            },
            _initWeekDay: function () {
                var that = this, data;
                var weekdayMessage = that.options.messages.weekdays;
                var offsetMessage = that.options.messages.offsetPositions;
                var weekDayInput = that._container.find('.k-recur-weekday');
                var change = function () {
                    that._weekDayRule();
                    that._trigger();
                };
                if (weekDayInput[0]) {
                    that._weekDayOffset = new DropDownList(that._container.find('.k-recur-weekday-offset'), {
                        change: change,
                        dataTextField: 'text',
                        dataValueField: 'value',
                        dataSource: [
                            {
                                text: offsetMessage.first,
                                value: '1'
                            },
                            {
                                text: offsetMessage.second,
                                value: '2'
                            },
                            {
                                text: offsetMessage.third,
                                value: '3'
                            },
                            {
                                text: offsetMessage.fourth,
                                value: '4'
                            },
                            {
                                text: offsetMessage.last,
                                value: '-1'
                            }
                        ]
                    });
                    data = [
                        {
                            text: weekdayMessage.day,
                            value: 'day'
                        },
                        {
                            text: weekdayMessage.weekday,
                            value: 'weekday'
                        },
                        {
                            text: weekdayMessage.weekend,
                            value: 'weekend'
                        }
                    ];
                    that._weekDay = new DropDownList(weekDayInput, {
                        value: that.options.start.getDay(),
                        change: change,
                        dataTextField: 'text',
                        dataValueField: 'value',
                        dataSource: data.concat($.map(kendo.culture().calendar.days.names, function (dayName, idx) {
                            return {
                                text: dayName,
                                value: idx
                            };
                        }))
                    });
                    that._weekDayView();
                }
            },
            _initWeekDays: function () {
                var that = this;
                var rule = that._value;
                var weekDays = that._container.find('.k-recur-weekday-checkbox');
                if (weekDays[0]) {
                    weekDays.on(CLICK + that._namespace, function () {
                        rule.weekDays = $.map(weekDays.filter(':checked'), function (checkbox) {
                            return {
                                day: Number(checkbox.value),
                                offset: 0
                            };
                        });
                        if (!that.options.mobile) {
                            that._trigger();
                        }
                    });
                    if (rule.weekDays) {
                        var idx, weekDay;
                        var i = 0, l = weekDays.length;
                        var length = rule.weekDays.length;
                        for (; i < l; i++) {
                            weekDay = weekDays[i];
                            for (idx = 0; idx < length; idx++) {
                                if (weekDay.value == rule.weekDays[idx].day) {
                                    weekDay.checked = true;
                                }
                            }
                        }
                    }
                }
            },
            _initMonthDay: function () {
                var that = this;
                var rule = that._value;
                var monthDayInput = that._container.find('.k-recur-monthday');
                if (monthDayInput[0]) {
                    that._monthDay = new kendo.ui.NumericTextBox(monthDayInput, {
                        spinners: that.options.spinners,
                        min: 1,
                        max: 31,
                        decimals: 0,
                        format: '#',
                        value: rule.monthDays ? rule.monthDays[0] : that.options.start.getDate(),
                        change: function () {
                            var value = this.value();
                            rule.monthDays = value ? [value] : value;
                            that._trigger();
                        }
                    });
                }
            },
            _initCount: function () {
                var that = this, input = that._container.find('.k-recur-count'), rule = that._value;
                that._count = input.kendoNumericTextBox({
                    spinners: that.options.spinners,
                    value: rule.count || 1,
                    decimals: 0,
                    format: '#',
                    min: 1,
                    change: function () {
                        rule.count = this.value();
                        that._trigger();
                    }
                }).data('kendoNumericTextBox');
            },
            _initUntil: function () {
                var that = this, input = that._container.find('.k-recur-until'), start = that.options.start, rule = that._value, until = rule.until;
                that._until = input.kendoDatePicker({
                    min: until && until < start ? until : start,
                    value: until || new Date(start.getFullYear(), start.getMonth(), start.getDate(), 23, 59, 59),
                    change: function () {
                        var date = this.value();
                        rule.until = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
                        that._trigger();
                    }
                }).data('kendoDatePicker');
            },
            _trigger: function () {
                if (!this.options.mobile) {
                    this.trigger('change');
                }
            }
        });
        var RecurrenceEditor = BaseRecurrenceEditor.extend({
            init: function (element, options) {
                var that = this;
                BaseRecurrenceEditor.fn.init.call(that, element, options);
                that._initFrequency();
                that._initContainer();
                that.value(that.options.value);
            },
            options: { name: 'RecurrenceEditor' },
            events: ['change'],
            destroy: function () {
                var that = this;
                that._frequency.destroy();
                that._container.find('input[type=radio],input[type=checkbox]').off(CLICK + that._namespace);
                kendo.destroy(that._container);
                BaseRecurrenceEditor.fn.destroy.call(that);
            },
            value: function (value) {
                var that = this;
                var timezone = that.options.timezone;
                var freq;
                if (value === undefined) {
                    if (!that._value.freq) {
                        return '';
                    }
                    return serialize(that._value, timezone);
                }
                that._value = parseRule(value, timezone) || {};
                freq = that._value.freq;
                if (freq) {
                    that._frequency.value(freq);
                } else {
                    that._frequency.select(0);
                }
                that._initView(that._frequency.value());
            },
            _initContainer: function () {
                var element = this.element, container = $('<div class="k-recur-view" />'), editContainer = element.parent('.k-edit-field');
                if (editContainer[0]) {
                    container.insertAfter(editContainer);
                } else {
                    element.append(container);
                }
                this._container = container;
            },
            _initFrequency: function () {
                var that = this, options = that.options, frequencies = options.frequencies, messages = options.messages.frequencies, ddl = $('<input />').attr({ title: options.messages.recurrenceEditorTitle }), frequency;
                frequencies = $.map(frequencies, function (frequency) {
                    return {
                        text: messages[frequency],
                        value: frequency
                    };
                });
                frequency = frequencies[0];
                if (frequency && frequency.value === 'never') {
                    frequency.value = '';
                }
                that.element.append(ddl);
                that._frequency = new DropDownList(ddl, {
                    dataTextField: 'text',
                    dataValueField: 'value',
                    dataSource: frequencies,
                    change: function () {
                        that._value = {};
                        that._initView(that._frequency.value());
                        that.trigger('change');
                    }
                });
            },
            _initView: function (frequency) {
                var that = this;
                var rule = that._value;
                var options = that.options;
                var data = {
                    frequency: frequency || 'never',
                    weekDayCheckBoxes: weekDayCheckBoxes,
                    firstWeekDay: options.firstWeekDay,
                    messages: options.messages[frequency],
                    end: options.messages.end
                };
                kendo.destroy(that._container);
                that._container.html(RECURRENCE_VIEW_TEMPLATE(data));
                if (!frequency) {
                    that._value = {};
                    return;
                }
                rule.freq = frequency;
                if (frequency === 'weekly' && !rule.weekDays) {
                    rule.weekDays = [{
                            day: options.start.getDay(),
                            offset: 0
                        }];
                }
                that._initInterval();
                that._initWeekDays();
                that._initMonthDay();
                that._initWeekDay();
                that._initMonth();
                that._initCount();
                that._initUntil();
                that._period();
                that._end();
            },
            _initMonth: function () {
                var that = this;
                var rule = that._value;
                var month = rule.months || [that.options.start.getMonth() + 1];
                var monthInputs = that._container.find('.k-recur-month');
                var options;
                if (monthInputs[0]) {
                    options = {
                        change: function () {
                            rule.months = [Number(this.value())];
                            that.trigger('change');
                        },
                        dataTextField: 'text',
                        dataValueField: 'value',
                        dataSource: $.map(kendo.culture().calendar.months.names, function (monthName, idx) {
                            return {
                                text: monthName,
                                value: idx + 1
                            };
                        })
                    };
                    that._month1 = new DropDownList(monthInputs[0], options);
                    that._month2 = new DropDownList(monthInputs[1], options);
                    if (month) {
                        month = month[0];
                        that._month1.value(month);
                        that._month2.value(month);
                    }
                }
            },
            _end: function () {
                var that = this;
                var rule = that._value;
                var container = that._container;
                var namespace = that._namespace;
                var click = function (e) {
                    that._toggleEnd(e.currentTarget.value);
                    that.trigger('change');
                };
                var endRule;
                that._buttonNever = container.find('.k-recur-end-never').on(CLICK + namespace, click);
                that._buttonCount = container.find('.k-recur-end-count').on(CLICK + namespace, click);
                that._buttonUntil = container.find('.k-recur-end-until').on(CLICK + namespace, click);
                if (rule.count) {
                    endRule = 'count';
                } else if (rule.until) {
                    endRule = 'until';
                }
                that._toggleEnd(endRule);
            },
            _period: function () {
                var that = this;
                var rule = that._value;
                var monthly = rule.freq === 'monthly';
                var toggleRule = monthly ? that._toggleMonthDay : that._toggleYear;
                var selector = '.k-recur-' + (monthly ? 'month' : 'year') + '-radio';
                var radioButtons = that._container.find(selector);
                if (!monthly && rule.freq !== 'yearly') {
                    return;
                }
                radioButtons.on(CLICK + that._namespace, function (e) {
                    toggleRule.call(that, e.currentTarget.value);
                    that.trigger('change');
                });
                that._buttonMonthDay = radioButtons.eq(0);
                that._buttonWeekDay = radioButtons.eq(1);
                toggleRule.call(that, rule.weekDays ? 'weekday' : 'monthday');
            },
            _toggleEnd: function (endRule) {
                var that = this;
                var count, until;
                var enableCount, enableUntil;
                if (endRule === 'count') {
                    that._buttonCount.prop('checked', true);
                    enableCount = true;
                    enableUntil = false;
                    count = that._count.value();
                    until = null;
                } else if (endRule === 'until') {
                    that._buttonUntil.prop('checked', true);
                    enableCount = false;
                    enableUntil = true;
                    count = null;
                    until = that._until.value();
                } else {
                    that._buttonNever.prop('checked', true);
                    enableCount = enableUntil = false;
                    count = until = null;
                }
                that._count.enable(enableCount);
                that._until.enable(enableUntil);
                that._value.count = count;
                that._value.until = until;
            },
            _toggleMonthDay: function (monthRule) {
                var that = this;
                var enableMonthDay = false;
                var enableWeekDay = true;
                var clear = false;
                var monthDays;
                if (monthRule === 'monthday') {
                    that._buttonMonthDay.prop('checked', true);
                    monthDays = [that._monthDay.value()];
                    enableMonthDay = true;
                    enableWeekDay = false;
                    clear = true;
                } else {
                    that._buttonWeekDay.prop('checked', true);
                    monthDays = null;
                }
                that._weekDay.enable(enableWeekDay);
                that._weekDayOffset.enable(enableWeekDay);
                that._monthDay.enable(enableMonthDay);
                that._value.monthDays = monthDays;
                that._weekDayRule(clear);
            },
            _toggleYear: function (yearRule) {
                var that = this;
                var enableMonth1 = false;
                var enableMonth2 = true;
                var month;
                if (yearRule === 'monthday') {
                    enableMonth1 = true;
                    enableMonth2 = false;
                    month = that._month1.value();
                } else {
                    month = that._month2.value();
                }
                that._month1.enable(enableMonth1);
                that._month2.enable(enableMonth2);
                that._value.months = [month];
                that._toggleMonthDay(yearRule);
            }
        });
        ui.plugin(RecurrenceEditor);
        var RECURRENCE_HEADER_TEMPLATE = kendo.template('<div class="k-edit-label"><label>#:headerTitle#</label></div>' + '<div class="k-edit-field k-recur-pattern k-scheduler-toolbar"></div>' + '<div class="k-recur-view"></div>');
        var RECURRENCE_REPEAT_PATTERN_TEMPLATE = kendo.template('# if (frequency !== "never") { #' + '<div class="k-edit-label"><label>#:messages.repeatEvery#</label></div>' + '<div class="k-edit-field"><input class="k-recur-interval" pattern="\\\\d*"/>#:messages.interval#</div>' + '# } #' + '# if (frequency === "weekly") { #' + '<div class="k-edit-label"><label>#:messages.repeatOn#</label></div>' + '<div class="k-edit-field">#=weekDayCheckBoxes(firstWeekDay)#</div>' + '# } else if (frequency === "monthly") { #' + '<div class="k-edit-label"><label>#:messages.repeatBy#</label></div>' + '<div class="k-edit-field k-scheduler-toolbar k-repeat-rule"></div>' + '<div class="k-monthday-view" style="display:none">' + '<div class="k-edit-label"><label>#:messages.day#</label></div>' + '<div class="k-edit-field"><input class="k-recur-monthday" title="#:messages.day#" pattern="\\\\d*"/></div>' + '</div>' + '<div class="k-weekday-view" style="display:none">' + '<div class="k-edit-label"><label>#:messages.every#</label></div>' + '<div class="k-edit-field"><select class="k-recur-weekday-offset" title="#:messages.every#"></select></div>' + '<div class="k-edit-label"><label>#:messages.day#</label></div>' + '<div class="k-edit-field"><select class="k-recur-weekday" title="#:messages.day#"></select></div>' + '</div>' + '# } else if (frequency === "yearly") { #' + '<div class="k-edit-label"><label>#:messages.repeatBy#</label></div>' + '<div class="k-edit-field k-scheduler-toolbar k-repeat-rule"></div>' + '<div class="k-monthday-view" style="display:none">' + '<div class="k-edit-label"><label>#:messages.day#</label></div>' + '<div class="k-edit-field"><input class="k-recur-monthday" title="#:messages.day#" pattern="\\\\d*"/></div>' + '</div>' + '<div class="k-weekday-view" style="display:none">' + '<div class="k-edit-label"><label>#:messages.every#</label></div>' + '<div class="k-edit-field"><select class="k-recur-weekday-offset" title="#:messages.every#"></select></div>' + '<div class="k-edit-label"><label>#:messages.day#</label></div>' + '<div class="k-edit-field"><select class="k-recur-weekday" title="#:messages.day#"></select></div>' + '</div>' + '<div class="k-edit-label"><label>#:messages.month#</label></div>' + '<div class="k-edit-field"><select class="k-recur-month" title="#:messages.month#"></select></div>' + '# } #');
        var RECURRENCE_END_PATTERN_TEMPLATE = kendo.template('# if (endPattern === "count") { #' + '<div class="k-edit-label"><label>#:messages.after#</label></div>' + '<div class="k-edit-field"><input class="k-recur-count" pattern="\\\\d*" /></div>' + '# } else if (endPattern === "until") { #' + '<div class="k-edit-label"><label>#:messages.on#</label></div>' + '<div class="k-edit-field"><input type="date" class="k-recur-until" /></div>' + '# } #');
        var RECURRENCE_GROUP_BUTTON_TEMPLATE = kendo.template('<ul class="k-reset k-header k-scheduler-navigation">' + '#for (var i = 0, length = dataSource.length; i < length; i++) {#' + '<li class="k-state-default #= value === dataSource[i].value ? "k-state-selected" : "" #">' + '<a role="button" href="\\#" class="k-link" data-#=ns#value="#=dataSource[i].value#">#:dataSource[i].text#</a>' + '</li>' + '#}#' + '</ul>');
        var MobileRecurrenceEditor = BaseRecurrenceEditor.extend({
            init: function (element, options) {
                var that = this;
                BaseRecurrenceEditor.fn.init.call(that, element, options);
                options = that.options;
                that._optionTemplate = kendo.template('<option value="#:value#">#:text#</option>');
                that.value(options.value);
                that._pane = options.pane;
                that._initRepeatButton();
                that._initRepeatEnd();
                that._defaultValue = that._value;
            },
            options: {
                name: 'MobileRecurrenceEditor',
                animations: {
                    left: 'slide',
                    right: 'slide:right'
                },
                mobile: true,
                messages: {
                    cancel: 'Cancel',
                    update: 'Save',
                    endTitle: 'Repeat ends',
                    repeatTitle: 'Repeat pattern',
                    headerTitle: 'Repeat event',
                    end: {
                        patterns: {
                            never: 'Never',
                            after: 'After...',
                            on: 'On...'
                        },
                        never: 'Never',
                        after: 'End repeat after',
                        on: 'End repeat on'
                    },
                    daily: { interval: '' },
                    hourly: { interval: '' },
                    weekly: { interval: '' },
                    monthly: {
                        interval: '',
                        repeatBy: 'Repeat by: ',
                        dayOfMonth: 'Day of the month',
                        dayOfWeek: 'Day of the week',
                        repeatEvery: 'Repeat every',
                        every: 'Every',
                        day: 'Day '
                    },
                    yearly: {
                        interval: '',
                        repeatBy: 'Repeat by: ',
                        dayOfMonth: 'Day of the month',
                        dayOfWeek: 'Day of the week',
                        repeatEvery: 'Repeat every: ',
                        every: 'Every',
                        month: 'Month',
                        day: 'Day'
                    }
                }
            },
            events: ['change'],
            value: function (value) {
                var that = this;
                var timezone = that.options.timezone;
                if (value === undefined) {
                    if (!that._value.freq) {
                        return '';
                    }
                    return serialize(that._value, timezone);
                }
                that._value = parseRule(value, timezone) || {};
            },
            destroy: function () {
                this._destroyView();
                kendo.destroy(this._endFields);
                this._repeatButton.off(CLICK + this._namespace);
                BaseRecurrenceEditor.fn.destroy.call(this);
            },
            _initRepeatButton: function () {
                var that = this;
                var freq = that.options.messages.frequencies[this._value.freq || 'never'];
                that._repeatButton = $('<a href="#" class="k-button k-scheduler-recur">' + freq + '</a>').on(CLICK + that._namespace, function (e) {
                    e.preventDefault();
                    that._createView('repeat');
                    that._pane.navigate('recurrence', that.options.animations.left);
                });
                that.element.append(that._repeatButton);
            },
            _initRepeatEnd: function () {
                var that = this;
                var endLabelField = $('<div class="k-edit-label"><label>' + that.options.messages.end.mobileLabel + '</label></div>').insertAfter(that.element.parent('.k-edit-field'));
                var endEditField = $('<div class="k-edit-field"><a href="#" class="k-button k-scheduler-recur-end"></a></div>').on(CLICK + that._namespace, function (e) {
                    e.preventDefault();
                    if (!that._value.freq) {
                        return;
                    }
                    that._createView('end');
                    that._pane.navigate('recurrence', that.options.animations.left);
                }).insertAfter(endLabelField);
                that._endFields = endLabelField.add(endEditField).toggleClass('k-state-disabled', !that._value.freq);
                that._endButton = endEditField.find('.k-scheduler-recur-end').text(that._endText());
            },
            _endText: function () {
                var rule = this._value;
                var messages = this.options.messages.end;
                var text = messages.never;
                if (rule.count) {
                    text = kendo.format('{0} {1}', messages.after, rule.count);
                } else if (rule.until) {
                    text = kendo.format('{0} {1:d}', messages.on, rule.until);
                }
                return text;
            },
            _initFrequency: function () {
                var that = this;
                var frequencyMessages = that.options.messages.frequencies;
                var html = RECURRENCE_GROUP_BUTTON_TEMPLATE({
                    dataSource: $.map(this.options.frequencies, function (frequency) {
                        return {
                            text: frequencyMessages[frequency],
                            value: frequency !== 'never' ? frequency : ''
                        };
                    }),
                    value: that._value.freq || '',
                    ns: kendo.ns
                });
                that._view.element.find('.k-recur-pattern').append(html).on(CLICK + that._namespace, '.k-scheduler-navigation li', function (e) {
                    var li = $(this);
                    e.preventDefault();
                    li.addClass('k-state-selected').siblings().removeClass('k-state-selected');
                    that._value = { freq: li.children('a').attr(kendo.attr('value')) };
                    that._initRepeatView();
                });
            },
            _initEndNavigation: function () {
                var that = this;
                var endMessages = that.options.messages.end.patterns;
                var rule = that._value;
                var value = '';
                if (rule.count) {
                    value = 'count';
                } else if (rule.until) {
                    value = 'until';
                }
                var html = RECURRENCE_GROUP_BUTTON_TEMPLATE({
                    dataSource: [
                        {
                            text: endMessages.never,
                            value: ''
                        },
                        {
                            text: endMessages.after,
                            value: 'count'
                        },
                        {
                            text: endMessages.on,
                            value: 'until'
                        }
                    ],
                    value: value,
                    ns: kendo.ns
                });
                that._view.element.find('.k-recur-pattern').append(html).on(CLICK + that._namespace, '.k-scheduler-navigation li', function (e) {
                    var li = $(this);
                    var count = null;
                    var until = null;
                    e.preventDefault();
                    li.addClass('k-state-selected').siblings().removeClass('k-state-selected');
                    that._initEndView(li.children('a').attr(kendo.attr('value')));
                    if (that._count) {
                        count = that._count.value();
                        until = null;
                    } else if (that._until) {
                        count = null;
                        until = that._until.val ? kendo.parseDate(that._until.val(), 'yyyy-MM-dd') : that._until.value();
                    }
                    rule.count = count;
                    rule.until = until;
                });
            },
            _createView: function (viewType) {
                var that = this;
                var options = that.options;
                var messages = options.messages;
                var headerTitle = messages[viewType === 'repeat' ? 'repeatTitle' : 'endTitle'];
                var html = '<div data-role="view" class="k-popup-edit-form k-scheduler-edit-form k-mobile-list" id="recurrence">' + '<div data-role="header" class="k-header">' + '<a href="#" class="k-button k-scheduler-cancel">' + messages.cancel + '</a>' + messages.headerTitle + '<a href="#" class="k-button k-scheduler-update">' + messages.update + '</a>' + '</div>';
                var returnViewId = that._pane.view().id;
                that._view = that._pane.append(html + RECURRENCE_HEADER_TEMPLATE({ headerTitle: headerTitle }));
                that._view.element.on(CLICK + that._namespace, 'a.k-scheduler-cancel, a.k-scheduler-update', function (e) {
                    e.preventDefault();
                    e.stopPropagation();
                    if ($(this).hasClass('k-scheduler-update')) {
                        that.trigger('change');
                        that._defaultValue = $.extend({}, that._value);
                    } else {
                        that._value = that._defaultValue;
                    }
                    var frequency = that._value.freq;
                    that._endButton.text(that._endText());
                    that._endFields.toggleClass('k-state-disabled', !frequency);
                    that._repeatButton.text(messages.frequencies[frequency || 'never']);
                    that._pane.one('viewShow', function () {
                        that._destroyView();
                    });
                    that._pane.navigate(returnViewId, that.options.animations.right);
                });
                that._container = that._view.element.find('.k-recur-view');
                if (viewType === 'repeat') {
                    that._initFrequency();
                    that._initRepeatView();
                } else {
                    that._initEndNavigation();
                    that._initEndView();
                }
            },
            _destroyView: function () {
                if (this._view) {
                    this._view.destroy();
                    this._view.element.remove();
                }
                this._view = null;
            },
            _initRepeatView: function () {
                var that = this;
                var frequency = that._value.freq || 'never';
                var data = {
                    frequency: frequency,
                    weekDayCheckBoxes: weekDayCheckBoxes,
                    firstWeekDay: that.options.firstWeekDay,
                    messages: that.options.messages[frequency]
                };
                var html = RECURRENCE_REPEAT_PATTERN_TEMPLATE(data);
                var container = that._container;
                var rule = that._value;
                kendo.destroy(container);
                container.html(html);
                if (!html) {
                    that._value = {};
                    return;
                }
                if (frequency === 'weekly' && !rule.weekDays) {
                    rule.weekDays = [{
                            day: that.options.start.getDay(),
                            offset: 0
                        }];
                }
                that._initInterval();
                that._initMonthDay();
                that._initWeekDays();
                that._initWeekDay();
                that._initMonth();
                that._period();
            },
            _initEndView: function (endPattern) {
                var that = this;
                var rule = that._value;
                if (endPattern === undefined) {
                    if (rule.count) {
                        endPattern = 'count';
                    } else if (rule.until) {
                        endPattern = 'until';
                    }
                }
                var data = {
                    endPattern: endPattern,
                    messages: that.options.messages.end
                };
                kendo.destroy(that._container);
                that._container.html(RECURRENCE_END_PATTERN_TEMPLATE(data));
                that._initCount();
                that._initUntil();
            },
            _initWeekDay: function () {
                var that = this, data;
                var weekdayMessage = that.options.messages.weekdays;
                var offsetMessage = that.options.messages.offsetPositions;
                var weekDaySelect = that._container.find('.k-recur-weekday');
                var change = function () {
                    that._weekDayRule();
                    that.trigger('change');
                };
                if (weekDaySelect[0]) {
                    that._weekDayOffset = that._container.find('.k-recur-weekday-offset').html(that._options([
                        {
                            text: offsetMessage.first,
                            value: '1'
                        },
                        {
                            text: offsetMessage.second,
                            value: '2'
                        },
                        {
                            text: offsetMessage.third,
                            value: '3'
                        },
                        {
                            text: offsetMessage.fourth,
                            value: '4'
                        },
                        {
                            text: offsetMessage.last,
                            value: '-1'
                        }
                    ])).change(change);
                    data = [
                        {
                            text: weekdayMessage.day,
                            value: 'day'
                        },
                        {
                            text: weekdayMessage.weekday,
                            value: 'weekday'
                        },
                        {
                            text: weekdayMessage.weekend,
                            value: 'weekend'
                        }
                    ];
                    data = data.concat($.map(kendo.culture().calendar.days.names, function (dayName, idx) {
                        return {
                            text: dayName,
                            value: idx
                        };
                    }));
                    that._weekDay = weekDaySelect.html(that._options(data)).change(change).val(that.options.start.getDay());
                    that._weekDayView();
                }
            },
            _initMonth: function () {
                var that = this;
                var rule = that._value;
                var start = that.options.start;
                var month = rule.months || [start.getMonth() + 1];
                var monthSelect = that._container.find('.k-recur-month');
                var monthNames = kendo.culture().calendar.months.names;
                if (monthSelect[0]) {
                    var data = $.map(monthNames, function (monthName, idx) {
                        return {
                            text: monthName,
                            value: idx + 1
                        };
                    });
                    monthSelect.html(that._options(data)).change(function () {
                        rule.months = [Number(this.value)];
                    });
                    that._monthSelect = monthSelect;
                    if (month) {
                        monthSelect.val(month[0]);
                    }
                }
            },
            _period: function () {
                var that = this;
                var rule = that._value;
                var container = that._container;
                var messages = that.options.messages[rule.freq];
                var repeatRuleGroupButton = container.find('.k-repeat-rule');
                var weekDayView = container.find('.k-weekday-view');
                var monthDayView = container.find('.k-monthday-view');
                if (repeatRuleGroupButton[0]) {
                    var currentValue = rule.weekDays ? 'weekday' : 'monthday';
                    var html = RECURRENCE_GROUP_BUTTON_TEMPLATE({
                        value: currentValue,
                        dataSource: [
                            {
                                text: messages.dayOfMonth,
                                value: 'monthday'
                            },
                            {
                                text: messages.dayOfWeek,
                                value: 'weekday'
                            }
                        ],
                        ns: kendo.ns
                    });
                    var init = function (val) {
                        var weekDayName = that._weekDay.val();
                        var weekDayOffset = that._weekDayOffset.val();
                        var monthDay = that._monthDay.value();
                        var month = that._monthSelect ? that._monthSelect.val() : null;
                        if (val === 'monthday') {
                            rule.weekDays = null;
                            rule.monthDays = monthDay ? [monthDay] : monthDay;
                            rule.months = month ? [Number(month)] : month;
                            weekDayView.hide();
                            monthDayView.show();
                        } else {
                            rule.monthDays = null;
                            rule.months = month ? [Number(month)] : month;
                            rule.weekDays = [{
                                    offset: Number(weekDayOffset),
                                    day: Number(weekDayName)
                                }];
                            weekDayView.show();
                            monthDayView.hide();
                        }
                    };
                    repeatRuleGroupButton.append(html).on(CLICK + that._namespace, '.k-scheduler-navigation li', function (e) {
                        var li = $(this).addClass('k-state-selected');
                        e.preventDefault();
                        li.siblings().removeClass('k-state-selected');
                        var value = li.children('a').attr(kendo.attr('value'));
                        init(value);
                    });
                    init(currentValue);
                }
            },
            _initUntil: function () {
                var that = this;
                var input = that._container.find('.k-recur-until');
                var start = that.options.start;
                var rule = that._value;
                var until = rule.until;
                var min = until && until < start ? until : start;
                if (kendo.support.input.date) {
                    that._until = input.attr('min', kendo.toString(min, 'yyyy-MM-dd')).val(kendo.toString(until || start, 'yyyy-MM-dd')).on('change', function () {
                        rule.until = kendo.parseDate(this.value, 'yyyy-MM-dd');
                    });
                } else {
                    that._until = input.kendoDatePicker({
                        min: min,
                        value: until || start,
                        change: function () {
                            rule.until = this.value();
                        }
                    }).data('kendoDatePicker');
                }
            },
            _options: function (data, optionLabel) {
                var idx = 0;
                var html = '';
                var length = data.length;
                var template = this._optionTemplate;
                if (optionLabel) {
                    html += template({
                        value: '',
                        text: optionLabel
                    });
                }
                for (; idx < length; idx++) {
                    html += template(data[idx]);
                }
                return html;
            }
        });
        ui.plugin(MobileRecurrenceEditor);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler.timelineview', ['kendo.scheduler.view'], f);
}(function () {
    var __meta__ = {
        id: 'scheduler.timelineview',
        name: 'Scheduler Timeline View',
        category: 'web',
        description: 'The Scheduler Timeline View',
        depends: ['scheduler.view'],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, setTime = kendo.date.setTime, SchedulerView = ui.SchedulerView, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, extend = $.extend, proxy = $.proxy, getDate = kendo.date.getDate, getMilliseconds = kendo.date.getMilliseconds, MS_PER_DAY = kendo.date.MS_PER_DAY, MS_PER_MINUTE = kendo.date.MS_PER_MINUTE, CURRENT_TIME_MARKER_CLASS = 'k-current-time', CURRENT_TIME_MARKER_ARROW_CLASS = 'k-current-time-arrow', SCHEDULER_HEADER_WRAP_CLASS = 'k-scheduler-header-wrap', BORDER_SIZE_COEFF = 0.8666, NS = '.kendoTimelineView';
        var EVENT_TEMPLATE = kendo.template('<div>' + '<div class="k-event-template k-event-time">#:kendo.format("{0:t} - {1:t}", start, end)#</div>' + '<div class="k-event-template">${title}</div></div>'), DATA_HEADER_TEMPLATE = kendo.template('<span class=\'k-link k-nav-day\'>#=kendo.format(\'{0:m}\', date)#</span>'), EVENT_WRAPPER_STRING = '<div role="gridcell" aria-selected="false" ' + 'data-#=ns#uid="#=uid#"' + '#if (resources[0]) { #' + 'style="background-color:#=resources[0].color#; border-color: #=resources[0].color#"' + 'class="k-event#=inverseColor ? " k-event-inverse" : ""#" ' + '#} else {#' + 'class="k-event"' + '#}#' + '>' + '<span class="k-event-actions">' + '# if(data.tail) {#' + '<span class="k-icon k-i-arrow-60-left"></span>' + '#}#' + '# if(data.isException()) {#' + '<span class="k-icon k-i-non-recurrence"></span>' + '# } else if(data.isRecurring()) {#' + '<span class="k-icon k-i-reload"></span>' + '# } #' + '</span>' + '{0}' + '<span class="k-event-actions">' + '#if (showDelete) {#' + '<a href="\\#" class="k-link k-event-delete" title="${data.messages.destroy}" aria-label="${data.messages.destroy}"><span class="k-icon k-i-close"></span></a>' + '#}#' + '# if(data.head) {#' + '<span class="k-icon k-i-arrow-60-right"></span>' + '#}#' + '</span>' + '#if(resizable && !data.tail){#' + '<span class="k-resize-handle k-resize-w"></span>' + '#}#' + '#if(resizable && !data.head){#' + '<span class="k-resize-handle k-resize-e"></span>' + '#}#' + '</div>';
        function toInvariantTime(date) {
            var staticDate = new Date(1980, 1, 1, 0, 0, 0);
            setTime(staticDate, getMilliseconds(date));
            return staticDate;
        }
        function getWorkDays(options) {
            var workDays = [];
            var dayIndex = options.workWeekStart;
            workDays.push(dayIndex);
            while (options.workWeekEnd != dayIndex) {
                if (dayIndex > 6) {
                    dayIndex -= 7;
                } else {
                    dayIndex++;
                }
                workDays.push(dayIndex);
            }
            return workDays;
        }
        function setColspan(columnLevel) {
            var count = 0;
            if (columnLevel.columns) {
                for (var i = 0; i < columnLevel.columns.length; i++) {
                    count += setColspan(columnLevel.columns[i]);
                }
                columnLevel.colspan = count;
                return count;
            } else {
                columnLevel.colspan = 1;
                return 1;
            }
        }
        function collidingEvents(elements, left, right) {
            var idx, startPosition, overlaps, endPosition;
            for (idx = elements.length - 1; idx >= 0; idx--) {
                startPosition = elements[idx].rectLeft;
                endPosition = elements[idx].rectRight;
                overlaps = startPosition <= left && endPosition >= left;
                if (overlaps || startPosition >= left && endPosition <= right || left <= startPosition && right >= startPosition) {
                    if (startPosition < left) {
                        left = startPosition;
                    }
                    if (endPosition > right) {
                        right = endPosition;
                    }
                }
            }
            return eventsForSlot(elements, left, right);
        }
        function eventsForSlot(elements, left, right) {
            var events = [];
            for (var idx = 0; idx < elements.length; idx++) {
                var event = {
                    rectLeft: elements[idx].rectLeft,
                    rectRight: elements[idx].rectRight
                };
                if (event.rectLeft < left && event.rectRight > left || event.rectLeft >= left && event.rectRight <= right) {
                    events.push(elements[idx]);
                }
            }
            return events;
        }
        var TimelineGroupedView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _getTimeSlotByPosition: function (x, y, groupIndex) {
                var group = this._view.groups[groupIndex];
                return group.timeSlotByPosition(x, y);
            },
            _hideHeaders: function () {
                var view = this._view;
                view.timesHeader.find('table tr:last').hide();
                view.datesHeader.find('table tr:last').hide();
            },
            _setColspan: function (timeColumn) {
                setColspan(timeColumn);
            },
            _createRowsLayout: function (resources, rows, groupHeaderTemplate) {
                var view = this._view;
                return view._createRowsLayout(resources, rows, groupHeaderTemplate);
            },
            _createVerticalColumnsLayout: function (resources, rows, groupHeaderTemplate, columns) {
                return columns;
            },
            _createColumnsLayout: function (resources, columns, groupHeaderTemplate) {
                var view = this._view;
                return view._createColumnsLayout(resources, columns, groupHeaderTemplate);
            },
            _getRowCount: function () {
                var view = this._view;
                return view._groupCount();
            },
            _getGroupsCount: function () {
                return 1;
            },
            _addContent: function (dates, columnCount, groupsCount, rowCount, start, end, slotTemplate, isVerticalGrouped) {
                var view = this._view;
                var html = '';
                var options = view.options;
                var appendRow = function (date) {
                    var content = '';
                    var classes = '';
                    var tmplDate;
                    var resources = function (groupIndex) {
                        return function () {
                            return view._resourceBySlot({ groupIndex: groupIndex });
                        };
                    };
                    if (kendo.date.isToday(dates[idx])) {
                        classes += 'k-today';
                    }
                    if (kendo.date.getMilliseconds(date) < kendo.date.getMilliseconds(options.workDayStart) || kendo.date.getMilliseconds(date) >= kendo.date.getMilliseconds(options.workDayEnd) || !view._isWorkDay(dates[idx])) {
                        classes += ' k-nonwork-hour';
                    }
                    content += '<td' + (classes !== '' ? ' class="' + classes + '"' : '') + '>';
                    tmplDate = kendo.date.getDate(dates[idx]);
                    kendo.date.setTime(tmplDate, kendo.date.getMilliseconds(date));
                    content += slotTemplate({
                        date: tmplDate,
                        resources: resources(isVerticalGrouped ? rowIdx : groupIdx)
                    });
                    content += '</td>';
                    return content;
                };
                for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
                    html += '<tr>';
                    for (var groupIdx = 0; groupIdx < groupsCount; groupIdx++) {
                        for (var idx = 0, length = columnCount; idx < length; idx++) {
                            html += view._forTimeRange(start, end, appendRow);
                        }
                    }
                    html += '</tr>';
                }
                return html;
            },
            _addTimeSlotsCollections: function (groupCount, datesCount, tableRows, interval, isVerticallyGrouped) {
                var view = this._view;
                var rowCount = tableRows.length;
                if (isVerticallyGrouped) {
                    rowCount = Math.floor(rowCount / groupCount);
                }
                for (var groupIndex = 0; groupIndex < groupCount; groupIndex++) {
                    var rowMultiplier = 0;
                    var group = view.groups[groupIndex];
                    var time;
                    if (isVerticallyGrouped) {
                        rowMultiplier = groupIndex;
                    }
                    var rowIndex = rowMultiplier * rowCount;
                    var cellMultiplier = 0;
                    if (!isVerticallyGrouped) {
                        cellMultiplier = groupIndex;
                    }
                    var cells = tableRows[rowIndex].children;
                    var cellsPerGroup = cells.length / (!isVerticallyGrouped ? groupCount : 1);
                    var cellsPerDay = cellsPerGroup / datesCount;
                    for (var dateIndex = 0; dateIndex < datesCount; dateIndex++) {
                        var cellOffset = dateIndex * cellsPerDay + cellsPerGroup * cellMultiplier;
                        time = getMilliseconds(new Date(+view.startTime()));
                        for (var cellIndex = 0; cellIndex < cellsPerDay; cellIndex++) {
                            view._addTimeSlotToCollection(group, cells, cellIndex, cellOffset, dateIndex, time, interval);
                            time += interval;
                        }
                    }
                }
            },
            _getVerticalGroupCount: function (groupsCount) {
                return groupsCount;
            },
            _getVerticalRowCount: function (eventGroups, groupIndex, maxRowCount) {
                var view = this._view;
                return view._isVerticallyGrouped() ? eventGroups[groupIndex].maxRowCount : maxRowCount;
            },
            _renderEvent: function (eventGroup, event, adjustedEvent, group, range, container) {
                var view = this._view;
                var element;
                element = view._createEventElement(adjustedEvent.occurrence, event, range.head || adjustedEvent.head, range.tail || adjustedEvent.tail);
                element.appendTo(container).css({
                    top: 0,
                    height: view.options.eventHeight
                });
                var eventObject = {
                    start: adjustedEvent.occurrence._startTime || adjustedEvent.occurrence.start,
                    end: adjustedEvent.occurrence._endTime || adjustedEvent.occurrence.end,
                    element: element,
                    uid: event.uid,
                    slotRange: range,
                    rowIndex: 0,
                    offsetTop: 0
                };
                eventGroup.events[event.uid] = eventObject;
                view.addContinuousEvent(group, range, element, event.isAllDay);
                view._arrangeRows(eventObject, range, eventGroup);
            },
            _verticalCountForLevel: function (level) {
                var view = this._view;
                return view._rowCountForLevel(level);
            },
            _horizontalCountForLevel: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level);
            },
            _updateCurrentVerticalTimeMarker: function (ranges, currentTime) {
                var view = this._view;
                var elementHtml = '<div class=\'' + CURRENT_TIME_MARKER_CLASS + '\'></div>';
                var headerWrap = view.datesHeader.find('.' + SCHEDULER_HEADER_WRAP_CLASS);
                var left = Math.round(ranges[0].innerRect(currentTime, new Date(currentTime.getTime() + 1), false).left);
                var timesTableMarker = $(elementHtml).prependTo(headerWrap).addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-down');
                timesTableMarker.css({
                    left: view._adjustLeftPosition(left - outerWidth(timesTableMarker) * BORDER_SIZE_COEFF / 2),
                    top: headerWrap.find('tr:last').prev().position().top
                });
                $(elementHtml).prependTo(view.content).css({
                    left: view._adjustLeftPosition(left),
                    width: '1px',
                    height: view.content[0].scrollHeight - 1,
                    top: 0
                });
            },
            _changeGroup: function () {
                return undefined;
            },
            _prevGroupSlot: function (slot, group, isDay) {
                var view = this._view;
                if (view._isVerticallyGrouped()) {
                    return slot;
                } else {
                    var collection = group._collection(0, isDay);
                    return collection.last();
                }
            },
            _nextGroupSlot: function (slot, group, isDay) {
                var view = this._view;
                if (view._isVerticallyGrouped()) {
                    return slot;
                } else {
                    var collection = group._collection(0, isDay);
                    return collection.first();
                }
            },
            _verticalSlots: function (selection, reverse) {
                var view = this._view;
                return view._changeGroup(selection, reverse);
            },
            _verticalMethod: function (reverse) {
                return reverse ? 'leftSlot' : 'rightSlot';
            },
            _normalizeVerticalSelection: function () {
                return undefined;
            },
            _horizontalSlots: function (selection, group, method, startSlot, endSlot, multiple, reverse) {
                var view = this._view;
                var result = {};
                result.startSlot = group[method](startSlot);
                result.endSlot = group[method](endSlot);
                if (!multiple && view._isHorizontallyGrouped() && (!result.startSlot || !result.endSlot)) {
                    result.startSlot = result.endSlot = view._changeGroup(selection, reverse);
                }
                return result;
            },
            _changeVerticalViewPeriod: function () {
                return false;
            },
            _changeHorizontalViewPeriod: function (slots, shift, selection, reverse) {
                var view = this._view;
                if ((!slots.startSlot || !slots.endSlot) && !shift && view._changeViewPeriod(selection, reverse, false)) {
                    return true;
                }
                return false;
            },
            _updateDirection: function (selection, ranges, shift, reverse) {
                var view = this._view;
                view._updateDirection(selection, ranges, shift, reverse, true);
            },
            _createMoveHint: function (range, adjustedEvent) {
                var view = this._view;
                var startSlot = range.start;
                var hint = view._createEventElement(adjustedEvent.occurrence, adjustedEvent.occurrence, false, false);
                hint.addClass('k-event-drag-hint');
                var rect = range.innerRect(adjustedEvent.occurrence.start, adjustedEvent.occurrence.end, view.options.snap);
                var width = rect.right - rect.left - 2;
                if (width < 0) {
                    width = 0;
                }
                var left = view._adjustLeftPosition(rect.left);
                var css = {
                    left: left,
                    top: startSlot.offsetTop,
                    height: startSlot.offsetHeight - 2,
                    width: width
                };
                hint.css(css);
                view._moveHint = view._moveHint.add(hint);
            },
            _adjustLeftPosition: function (left) {
                var view = this._view;
                if (view._isRtl) {
                    left -= view.content[0].scrollWidth - view.content[0].offsetWidth;
                }
                return left;
            }
        });
        var TimelineGroupedByDateView = kendo.Class.extend({
            init: function (view) {
                this._view = view;
            },
            _getTimeSlotByPosition: function (x, y, groupIndex) {
                var group = this._view.groups[groupIndex];
                return group.timeSlotByPosition(x, y, true);
            },
            _hideHeaders: function () {
                var view = this._view;
                if (!view._isVerticallyGrouped()) {
                    view.timesHeader.find('table tr').eq(2).hide();
                    view.datesHeader.find('table tr').eq(2).hide();
                } else {
                    view.times.find('.k-last').hide();
                }
            },
            _setColspan: function () {
            },
            _createRowsLayout: function (resources, rows, groupHeaderTemplate, columns) {
                var view = this._view;
                return view._createDateLayout(columns, null, true);
            },
            _createVerticalColumnsLayout: function (resources, rows, groupHeaderTemplate) {
                var view = this._view;
                return view._createColumnsLayout(resources, null, groupHeaderTemplate);
            },
            _createColumnsLayout: function (resources, columns, groupHeaderTemplate, subColumns) {
                var view = this._view;
                return view._createColumnsLayout(resources, columns, groupHeaderTemplate, subColumns, true);
            },
            _getRowCount: function (level) {
                var view = this._view;
                return view._rowCountForLevel(level);
            },
            _getGroupsCount: function () {
                var view = this._view;
                return view._groupCount();
            },
            _addContent: function (dates, columnCount, groupsCount, rowCount, start, end, slotTemplate, isVerticalGrouped) {
                var view = this._view;
                var html = '';
                var options = view.options;
                var appendRow = function (date, isMajorTickColumn, isMiddleColumn, isLastSlotColumn, minorTickColumns, groupIdx) {
                    var content = '';
                    var classes = '';
                    var tmplDate;
                    var workDateIndex = view._isVerticallyGrouped() ? dateIndex : idx;
                    var resources = function (groupIndex) {
                        return function () {
                            return view._resourceBySlot({ groupIndex: groupIndex });
                        };
                    };
                    if (kendo.date.isToday(dates[idx])) {
                        classes += 'k-today';
                    }
                    if (kendo.date.getMilliseconds(date) < kendo.date.getMilliseconds(options.workDayStart) || kendo.date.getMilliseconds(date) >= kendo.date.getMilliseconds(options.workDayEnd) || !view._isWorkDay(dates[workDateIndex])) {
                        classes += ' k-nonwork-hour';
                    }
                    content += '<td' + (classes !== '' ? ' class="' + classes + '"' : '') + '>';
                    tmplDate = kendo.date.getDate(dates[idx]);
                    kendo.date.setTime(tmplDate, kendo.date.getMilliseconds(date));
                    content += slotTemplate({
                        date: tmplDate,
                        resources: resources(groupIdx)
                    });
                    content += '</td>';
                    return content;
                };
                var tempStart = new Date(start), minorTickCount = view.options.minorTickCount, msMajorInterval = view.options.majorTick * MS_PER_MINUTE, msInterval = msMajorInterval / minorTickCount || 1, dateIndex;
                for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
                    html += '<tr>';
                    if (rowIdx % (rowCount / view._dates.length) === 0) {
                        dateIndex = rowIdx / (rowCount / view._dates.length);
                        tempStart = new Date(view._dates[dateIndex]);
                        kendo.date.setTime(tempStart, kendo.date.getMilliseconds(start));
                    }
                    for (var idx = 0, length = columnCount; idx < length; idx++) {
                        html += view._forTimeRange(tempStart, end, appendRow, isVerticalGrouped, groupsCount);
                        if (isVerticalGrouped) {
                            setTime(tempStart, msInterval, false);
                            break;
                        }
                    }
                    html += '</tr>';
                }
                return html;
            },
            _addTimeSlotsCollections: function (groupCount, datesCount, tableRows, interval, isVerticallyGrouped) {
                var view = this._view;
                var rowCount = tableRows.length;
                if (isVerticallyGrouped) {
                    rowCount = rowCount / datesCount;
                }
                for (var dateIndex = 0; dateIndex < datesCount; dateIndex++) {
                    var rowMultiplier = 0;
                    var time;
                    if (isVerticallyGrouped) {
                        rowMultiplier = dateIndex;
                    }
                    var rowIndex = rowMultiplier * rowCount;
                    var cellMultiplier = 0;
                    var cells = tableRows[rowIndex].children;
                    var cellsPerGroup = isVerticallyGrouped ? rowCount : cells.length / (datesCount * groupCount);
                    var cellsPerDay = cells.length / datesCount;
                    var cellOffset;
                    time = getMilliseconds(new Date(+view.startTime()));
                    for (var cellIndex = 0; cellIndex < cellsPerGroup; cellIndex++) {
                        if (!isVerticallyGrouped) {
                            cellOffset = dateIndex * cellsPerDay + groupCount * cellIndex;
                            cellMultiplier++;
                        } else {
                            cellOffset = 0;
                            cells = tableRows[cellIndex + cellsPerGroup * dateIndex].children;
                        }
                        for (var groupIndex = 0; groupIndex < groupCount; groupIndex++) {
                            var group = view.groups[groupIndex];
                            view._addTimeSlotToCollection(group, cells, groupIndex, cellOffset, dateIndex, time, interval);
                        }
                        time += interval;
                    }
                }
            },
            _getVerticalGroupCount: function () {
                var view = this._view;
                return view.content.find('tr').length;
            },
            _getVerticalRowCount: function (eventGroups, groupIndex, maxRowCount) {
                return maxRowCount;
            },
            _renderEvent: function (eventGroup, event, adjustedEvent, group, range, container, startIndex, endIndex) {
                var view = this._view;
                var element;
                var eventObjects = [];
                for (var i = range.start.index; i <= range.end.index; i++) {
                    element = view._createEventElement(adjustedEvent.occurrence, event, i !== endIndex, i !== startIndex);
                    element.appendTo(container).css({
                        top: 0,
                        height: view.options.eventHeight
                    });
                    var currentSlot = group._timeSlotCollections[0]._slots[i];
                    var dateRange = group.timeSlotRanges(currentSlot.start, currentSlot.end, false)[0];
                    var eventObject = {
                        start: i === startIndex ? adjustedEvent.occurrence._startTime || adjustedEvent.occurrence.start : currentSlot.start,
                        end: i === endIndex ? adjustedEvent.occurrence._endTime || adjustedEvent.occurrence.end : currentSlot.end,
                        element: element,
                        uid: event.uid,
                        slotRange: dateRange,
                        rowIndex: 0,
                        offsetTop: 0
                    };
                    eventGroup.events[event.uid] = eventObject;
                    eventObjects.push(eventObject);
                    view.addContinuousEvent(group, dateRange, element, event.isAllDay);
                    view._arrangeRows(eventObject, dateRange, eventGroup);
                }
                eventGroup.events[event.uid] = eventObjects;
            },
            _verticalCountForLevel: function (level) {
                var view = this._view;
                return view._columnCountForLevel(level);
            },
            _horizontalCountForLevel: function (level, columnLevel) {
                var view = this._view;
                return view._columnCountForLevel(columnLevel) / view._columnCountForLevel(2);
            },
            _updateCurrentVerticalTimeMarker: function (ranges, currentTime) {
                var view = this._view;
                var firstTimesCell = view.times.find('tr:first th:first');
                var lastTimesCell = view.times.find('tr:first th:last');
                var elementHtml = '<div class=\'' + CURRENT_TIME_MARKER_CLASS + '\'></div>';
                var timesTableMarker = $(elementHtml).prependTo(view.times);
                var markerTopPosition = Math.round(ranges[0].innerRect(currentTime, new Date(currentTime.getTime() + 1), false).top);
                var timesTableMarkerCss = {};
                if (this._isRtl) {
                    timesTableMarkerCss.right = firstTimesCell.position().left + outerHeight(firstTimesCell) - outerHeight(lastTimesCell);
                    timesTableMarker.addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-left');
                } else {
                    timesTableMarkerCss.left = lastTimesCell.position().left;
                    timesTableMarker.addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-right');
                }
                timesTableMarkerCss.top = markerTopPosition - outerWidth(timesTableMarker) * BORDER_SIZE_COEFF / 2;
                timesTableMarker.css(timesTableMarkerCss);
                $(elementHtml).prependTo(view.content).css({
                    top: markerTopPosition,
                    height: '1px',
                    right: '1px',
                    width: view.content[0].scrollWidth,
                    left: 0
                });
            },
            _changeGroup: function (selection, previous, slot) {
                var view = this._view;
                if (!slot) {
                    selection.groupIndex = previous ? view.groups.length - 1 : 0;
                }
            },
            _prevGroupSlot: function (slot) {
                return slot;
            },
            _nextGroupSlot: function (slot) {
                return slot;
            },
            _changeDate: function (selection, reverse, slot) {
                var view = this._view;
                var group = view.groups[selection.groupIndex];
                var collections, index;
                if (reverse) {
                    collections = group._getCollections(false);
                    index = slot.index - 1;
                    if (index >= 0) {
                        return collections[0]._slots[index];
                    }
                } else {
                    collections = group._getCollections(false);
                    index = slot.index + 1;
                    if (collections[0] && collections[0]._slots[index]) {
                        return collections[0]._slots[index];
                    }
                }
            },
            _verticalSlots: function (selection, reverse, slot) {
                return this._changeDate(selection, reverse, slot);
            },
            _verticalMethod: function (reverse, multiple) {
                if (multiple) {
                    return reverse ? 'upSlot' : 'downSlot';
                } else {
                    return reverse ? 'leftSlot' : 'rightSlot';
                }
            },
            _normalizeVerticalSelection: function (selection, ranges, reverse, multiple) {
                var view = this._view;
                if (!multiple) {
                    return view._normalizeVerticalSelection(selection, ranges, reverse);
                }
                return undefined;
            },
            _horizontalSlots: function (selection, group, method, startSlot, endSlot, multiple, reverse) {
                var view = this._view;
                var tempSlot = view._changeGroup(selection, reverse);
                var result = {};
                if (!tempSlot) {
                    if (!view._isVerticallyGrouped()) {
                        result.startSlot = group[method](startSlot);
                        result.endSlot = group[method](endSlot);
                    }
                } else {
                    result.startSlot = result.endSlot = tempSlot;
                }
                return result;
            },
            _changeVerticalViewPeriod: function (slots, shift, selection, reverse) {
                var view = this._view;
                if ((!slots.startSlot || !slots.endSlot) && !shift && view._changeViewPeriod(selection, reverse, view._isVerticallyGrouped())) {
                    return true;
                }
                return false;
            },
            _changeHorizontalViewPeriod: function (slots, shift, selection, reverse) {
                var view = this._view;
                if (view._isVerticallyGrouped()) {
                    return false;
                }
                if ((!slots.startSlot || !slots.endSlot) && !shift && view._changeViewPeriod(selection, reverse, false)) {
                    return true;
                }
                return false;
            },
            _updateDirection: function (selection, ranges, shift, reverse) {
                var view = this._view;
                view._updateDirection(selection, ranges, shift, reverse, !view._isVerticallyGrouped());
            },
            _createMoveHint: function (range, adjustedEvent) {
                var view = this._view;
                var startSlot = range.start;
                var startEnd = range.end;
                for (var slotIdx = startSlot.index; slotIdx <= startEnd.index; slotIdx++) {
                    var slot = range.collection._slots[slotIdx];
                    var hint = view._createEventElement(adjustedEvent.occurrence, adjustedEvent.occurrence, false, false);
                    hint.addClass('k-event-drag-hint');
                    var css = {
                        left: slot.offsetLeft + 2,
                        top: slot.offsetTop,
                        height: view.options.eventHeight,
                        width: slot.offsetWidth
                    };
                    hint.css(css);
                    view._moveHint = view._moveHint.add(hint);
                }
            },
            _adjustLeftPosition: function (left) {
                var view = this._view;
                if (view._isRtl && !view._isVerticallyGrouped()) {
                    left -= view.content[0].scrollWidth - view.content[0].offsetWidth;
                }
                return left;
            }
        });
        kendo.ui.scheduler.TimelineGroupedView = TimelineGroupedView;
        kendo.ui.scheduler.TimelineGroupedByDateView = TimelineGroupedByDateView;
        var TimelineView = SchedulerView.extend({
            init: function (element, options) {
                var that = this;
                SchedulerView.fn.init.call(that, element, options);
                that._groupedView = that._getGroupedView();
                that.title = that.options.title || that.options.name;
                that._workDays = getWorkDays(that.options);
                that._templates();
                that._editable();
                that.calculateDateRange();
                that._groups();
                that._currentTime(true);
            },
            name: 'timeline',
            _getGroupedView: function () {
                if (this._isGroupedByDate()) {
                    return new kendo.ui.scheduler.TimelineGroupedByDateView(this);
                } else {
                    return new kendo.ui.scheduler.TimelineGroupedView(this);
                }
            },
            _getNextEventIndexBySlot: function (slot, sortedEvents, groupIndex) {
                if (this._isVerticallyGrouped()) {
                    return kendo.ui.SchedulerView.fn._getNextEventIndexBySlot.call(this, slot, sortedEvents, groupIndex);
                }
                var tempIndex = 0;
                for (var i = 0; i < sortedEvents.length; i++) {
                    if (slot.startDate() > sortedEvents[i].start.startDate()) {
                        tempIndex++;
                        continue;
                    }
                    if (slot.startDate().getTime() === sortedEvents[i].start.startDate().getTime() && groupIndex > sortedEvents[i].start.groupIndex) {
                        tempIndex++;
                        continue;
                    }
                    break;
                }
                return tempIndex;
            },
            _getSelectedSlot: function (slot, sortedEvents, event, idx, pad, prev) {
                if (this._isVerticallyGrouped()) {
                    return kendo.ui.SchedulerView.fn._getSelectedSlot.call(this, slot, sortedEvents, event, idx, pad, prev);
                }
                return slot;
            },
            _getSortedEvents: function (uniqueAllEvents) {
                if (this._isVerticallyGrouped()) {
                    return kendo.ui.SchedulerView.fn._getSortedEvents.call(this, uniqueAllEvents);
                }
                return uniqueAllEvents.sort(function (first, second) {
                    var result = first.start.startDate().getTime() - second.start.startDate().getTime();
                    if (result === 0) {
                        if (first.start.isDaySlot && !second.start.isDaySlot) {
                            result = -1;
                        }
                        if (!first.start.isDaySlot && second.start.isDaySlot) {
                            result = 1;
                        }
                    }
                    if (result === 0) {
                        result = first.start.groupIndex - second.start.groupIndex;
                    }
                    if (result === 0) {
                        result = $(first.element).index() - $(second.element).index();
                    }
                    return result;
                });
            },
            _currentTimeMarkerUpdater: function () {
                this._updateCurrentTimeMarker(new Date());
            },
            _updateCurrentTimeMarker: function (currentTime) {
                var options = this.options;
                this.datesHeader.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                this.times.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                this.content.find('.' + CURRENT_TIME_MARKER_CLASS).remove();
                if (!this._isInDateSlot({
                        start: currentTime,
                        end: currentTime
                    })) {
                    return;
                }
                if (options.currentTimeMarker.useLocalTimezone === false) {
                    var timezone = options.dataSource.options.schema.timezone;
                    if (options.dataSource && timezone) {
                        var timezoneOffset = kendo.timezone.offset(currentTime, timezone);
                        currentTime = kendo.timezone.convert(currentTime, currentTime.getTimezoneOffset(), timezoneOffset);
                    }
                }
                var groupsCount = !options.group || options.group.orientation == 'vertical' ? 1 : this.groups.length;
                for (var groupIndex = 0; groupIndex < groupsCount; groupIndex++) {
                    var currentGroup = this.groups[groupIndex];
                    if (!currentGroup) {
                        return;
                    }
                    var utcCurrentTime = kendo.date.toUtcTime(currentTime);
                    var ranges = currentGroup.timeSlotRanges(utcCurrentTime, utcCurrentTime + 1);
                    if (ranges.length === 0) {
                        return;
                    }
                    var collection = ranges[0].collection;
                    var slotElement = collection.slotByStartDate(currentTime);
                    if (slotElement) {
                        if (this._isVerticallyGrouped()) {
                            this._groupedView._updateCurrentVerticalTimeMarker(ranges, currentTime);
                        } else {
                            var elementHtml = '<div class=\'' + CURRENT_TIME_MARKER_CLASS + '\'></div>';
                            var headerWrap = this.datesHeader.find('.' + SCHEDULER_HEADER_WRAP_CLASS);
                            var left = Math.round(ranges[0].innerRect(currentTime, new Date(currentTime.getTime() + 1), false).left);
                            var timesTableMarker = $(elementHtml).prependTo(headerWrap).addClass(CURRENT_TIME_MARKER_ARROW_CLASS + '-down');
                            timesTableMarker.css({
                                left: this._adjustLeftPosition(left - outerWidth(timesTableMarker) * BORDER_SIZE_COEFF / 2),
                                top: headerWrap.find('tr:last').prev().position().top
                            });
                            $(elementHtml).prependTo(this.content).css({
                                left: this._adjustLeftPosition(left),
                                width: '1px',
                                height: this.content[0].scrollHeight - 1,
                                top: 0
                            });
                        }
                    }
                }
            },
            _adjustLeftPosition: function (left) {
                return this._groupedView._adjustLeftPosition(left);
            },
            _currentTime: function (setUpdateTimer) {
                var that = this;
                var markerOptions = that.options.currentTimeMarker;
                if (markerOptions !== false && markerOptions.updateInterval !== undefined) {
                    that._currentTimeMarkerUpdater();
                    if (setUpdateTimer) {
                        that._currentTimeUpdateTimer = setInterval(proxy(this._currentTimeMarkerUpdater, that), markerOptions.updateInterval);
                    }
                }
            },
            _editable: function () {
                if (this.options.editable) {
                    if (this._isMobile()) {
                        this._touchEditable();
                    } else {
                        this._mouseEditable();
                    }
                }
            },
            _mouseEditable: function () {
                var that = this;
                that.element.on('click' + NS, '.k-event a:has(.k-i-close)', function (e) {
                    that.trigger('remove', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                    e.preventDefault();
                });
                if (that.options.editable.create !== false) {
                    that.element.on('dblclick' + NS, '.k-scheduler-content td', function (e) {
                        var slot = that._slotByPosition(e.pageX, e.pageY);
                        if (slot) {
                            var resourceInfo = that._resourceBySlot(slot);
                            that.trigger('add', {
                                eventInfo: extend({
                                    start: slot.startDate(),
                                    end: slot.endDate()
                                }, resourceInfo)
                            });
                        }
                        e.preventDefault();
                    });
                }
                if (that.options.editable.update !== false) {
                    that.element.on('dblclick' + NS, '.k-event', function (e) {
                        that.trigger('edit', { uid: $(this).closest('.k-event').attr(kendo.attr('uid')) });
                        e.preventDefault();
                    });
                }
            },
            _touchEditable: function () {
                var that = this;
                var threshold = 0;
                if (kendo.support.mobileOS.android) {
                    threshold = 5;
                }
                if (that.options.editable.create !== false) {
                    that._addUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        filter: '.k-scheduler-content td',
                        tap: function (e) {
                            var x = e.x.location !== undefined ? e.x.location : e.x;
                            var y = e.y.location !== undefined ? e.y.location : e.y;
                            var slot = that._slotByPosition(x, y);
                            if (slot) {
                                var resourceInfo = that._resourceBySlot(slot);
                                that.trigger('add', {
                                    eventInfo: extend({
                                        start: slot.startDate(),
                                        end: slot.endDate()
                                    }, resourceInfo)
                                });
                            }
                            e.preventDefault();
                        }
                    });
                }
                if (that.options.editable.update !== false) {
                    that._editUserEvents = new kendo.UserEvents(that.element, {
                        threshold: threshold,
                        filter: '.k-event',
                        tap: function (e) {
                            var eventElement = $(e.target).closest('.k-event');
                            if (!eventElement.hasClass('k-event-active')) {
                                that.trigger('edit', { uid: eventElement.attr(kendo.attr('uid')) });
                            }
                            e.preventDefault();
                        }
                    });
                }
            },
            _slotByPosition: function (x, y) {
                var slot;
                var content = this.content;
                var offset = content.offset();
                var groupIndex;
                x -= offset.left;
                y -= offset.top;
                if (this._isRtl) {
                    var browser = kendo.support.browser;
                    if (browser.mozilla) {
                        x += content[0].scrollWidth - content[0].offsetWidth;
                        x += content[0].scrollLeft;
                    } else if (browser.msie) {
                        x -= content.scrollLeft();
                        x += content[0].scrollWidth - content[0].offsetWidth;
                    } else if (browser.webkit) {
                        x += content[0].scrollLeft;
                    }
                } else {
                    x += content[0].scrollLeft;
                }
                y += content[0].scrollTop;
                x = Math.ceil(x);
                y = Math.ceil(y);
                for (groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    slot = this._groupedView._getTimeSlotByPosition(x, y, groupIndex);
                    if (slot) {
                        return slot;
                    }
                }
                return null;
            },
            options: {
                name: 'TimelineView',
                title: 'Timeline',
                selectedDateFormat: '{0:D}',
                selectedShortDateFormat: '{0:d}',
                date: kendo.date.today(),
                startTime: kendo.date.today(),
                endTime: kendo.date.today(),
                showWorkHours: false,
                minorTickCount: 2,
                editable: true,
                workDayStart: new Date(1980, 1, 1, 8, 0, 0),
                workDayEnd: new Date(1980, 1, 1, 17, 0, 0),
                workWeekStart: 1,
                workWeekEnd: 5,
                majorTick: 60,
                eventHeight: 25,
                eventMinWidth: 0,
                columnWidth: 100,
                groupHeaderTemplate: '#=text#',
                majorTimeHeaderTemplate: '#=kendo.toString(date, \'t\')#',
                slotTemplate: '&nbsp;',
                eventTemplate: EVENT_TEMPLATE,
                dateHeaderTemplate: DATA_HEADER_TEMPLATE,
                footer: { command: 'workDay' },
                currentTimeMarker: {
                    updateInterval: 10000,
                    useLocalTimezone: true
                },
                messages: {
                    defaultRowText: 'All events',
                    showFullDay: 'Show full day',
                    showWorkDay: 'Show business hours'
                }
            },
            events: [
                'remove',
                'add',
                'edit'
            ],
            _templates: function () {
                var options = this.options, settings = extend({}, kendo.Template, options.templateSettings);
                this.eventTemplate = this._eventTmpl(options.eventTemplate, EVENT_WRAPPER_STRING);
                this.majorTimeHeaderTemplate = kendo.template(options.majorTimeHeaderTemplate, settings);
                this.dateHeaderTemplate = kendo.template(options.dateHeaderTemplate, settings);
                this.slotTemplate = kendo.template(options.slotTemplate, settings);
                this.groupHeaderTemplate = kendo.template(options.groupHeaderTemplate, settings);
            },
            _render: function (dates) {
                var that = this;
                dates = dates || [];
                that._dates = dates;
                that._startDate = dates[0];
                that._endDate = dates[dates.length - 1 || 0];
                that._calculateSlotRanges();
                that.createLayout(that._layout(dates));
                that._content(dates);
                that._footer();
                that._setContentWidth();
                that.refreshLayout();
                that.datesHeader.on('click' + NS, '.k-nav-day', function (e) {
                    var th = $(e.currentTarget).closest('th');
                    var slot = that._slotByPosition(th.offset().left, that.content.offset().top);
                    that.trigger('navigate', {
                        view: 'timeline',
                        date: slot.startDate()
                    });
                });
                that._groupedView._hideHeaders();
            },
            _setContentWidth: function () {
                var content = this.content;
                var contentWidth = content.width();
                var contentTable = this.content.find('table');
                var columnCount = contentTable.find('tr:first').children().length;
                var minWidth = 100;
                var calculatedWidth = columnCount * this.options.columnWidth;
                if (contentWidth < calculatedWidth) {
                    minWidth = Math.ceil(calculatedWidth / contentWidth * 100);
                }
                contentTable.add(this.datesHeader.find('table')).css('width', minWidth + '%');
            },
            _calculateSlotRanges: function () {
                var dates = this._dates;
                var slotStartTime = this.startTime();
                var slotEndTime = this.endTime();
                if (getMilliseconds(slotEndTime) === getMilliseconds(kendo.date.getDate(slotEndTime))) {
                    slotEndTime = kendo.date.getDate(slotEndTime);
                    setTime(slotEndTime, MS_PER_DAY - 1);
                }
                slotEndTime = getMilliseconds(slotEndTime);
                slotStartTime = getMilliseconds(slotStartTime);
                var slotRanges = [];
                for (var i = 0; i < dates.length; i++) {
                    var rangeStart = getDate(dates[i]);
                    setTime(rangeStart, slotStartTime);
                    var rangeEnd = getDate(dates[i]);
                    setTime(rangeEnd, slotEndTime);
                    slotRanges.push({
                        start: kendo.date.toUtcTime(rangeStart),
                        end: kendo.date.toUtcTime(rangeEnd)
                    });
                }
                this._slotRanges = slotRanges;
            },
            _forTimeRange: function (min, max, action, verticalByDate, groupsCount) {
                min = toInvariantTime(min);
                max = toInvariantTime(max);
                var that = this, msMin = getMilliseconds(min), msMax = getMilliseconds(max), minorTickCount = that.options.minorTickCount, msMajorInterval = that.options.majorTick * MS_PER_MINUTE, msInterval = msMajorInterval / minorTickCount || 1, start = new Date(+min), startDay = start.getDate(), msStart, idx = 0, length, html = '';
                length = MS_PER_DAY / msInterval;
                if (msMin != msMax) {
                    if (msMin > msMax) {
                        msMax += MS_PER_DAY;
                    }
                    length = (msMax - msMin) / msInterval;
                }
                length = verticalByDate ? 1 : Math.round(length);
                if (groupsCount) {
                    length = length * groupsCount;
                }
                for (; idx < length; idx++) {
                    var majorTickDivider = idx % (msMajorInterval / msInterval);
                    var isMajorTickColumn = majorTickDivider === 0;
                    var isMiddleColumn = majorTickDivider < minorTickCount - 1;
                    var isLastSlotColumn = majorTickDivider === minorTickCount - 1;
                    var minorTickColumns = minorTickCount;
                    if (length % minorTickCount !== 0) {
                        var isLastMajorSlot = length - (idx + 1) < minorTickCount;
                        if (isMajorTickColumn && isLastMajorSlot) {
                            minorTickColumns = length % minorTickCount;
                        }
                    }
                    html += action(start, isMajorTickColumn, isMiddleColumn, isLastSlotColumn, minorTickColumns, idx % groupsCount);
                    if (!verticalByDate) {
                        if (groupsCount) {
                            if (idx % groupsCount === groupsCount - 1) {
                                setTime(start, msInterval, false);
                            }
                        } else {
                            setTime(start, msInterval, false);
                        }
                    }
                }
                if (msMax) {
                    msStart = getMilliseconds(start);
                    if (startDay < start.getDate()) {
                        msStart += MS_PER_DAY;
                    }
                    if (msStart > msMax) {
                        start = new Date(+max);
                    }
                }
                return html;
            },
            _layout: function (dates) {
                var timeColumns = [];
                var columns = [];
                var that = this;
                var rows = [{ text: that.options.messages.defaultRowText }];
                var groupedView = that._groupedView;
                var minorTickSlots = [];
                for (var minorTickIndex = 0; minorTickIndex < that.options.minorTickCount; minorTickIndex++) {
                    minorTickSlots.push({
                        text: '&#8203;',
                        className: 'k-last',
                        minorTicks: true
                    });
                }
                this._forTimeRange(that.startTime(), that.endTime(), function (date, majorTick, middleColumn, lastSlotColumn, minorSlotsCount) {
                    var template = that.majorTimeHeaderTemplate;
                    if (majorTick) {
                        var timeColumn = {
                            text: template({ date: date }),
                            className: lastSlotColumn ? 'k-slot-cell' : '',
                            columns: minorTickSlots.slice(0, minorSlotsCount)
                        };
                        groupedView._setColspan(timeColumn);
                        timeColumns.push(timeColumn);
                    }
                });
                for (var idx = 0; idx < dates.length; idx++) {
                    columns.push({
                        text: that.dateHeaderTemplate({ date: dates[idx] }),
                        className: 'k-slot-cell',
                        columns: timeColumns.slice(0)
                    });
                }
                var resources = this.groupedResources;
                if (resources.length) {
                    if (this._groupOrientation() === 'vertical') {
                        rows = groupedView._createRowsLayout(resources, null, this.groupHeaderTemplate, columns);
                        columns = groupedView._createVerticalColumnsLayout(resources, null, this.groupHeaderTemplate, columns);
                    } else {
                        columns = groupedView._createColumnsLayout(resources, columns, this.groupHeaderTemplate, columns);
                    }
                }
                return {
                    columns: columns,
                    rows: rows
                };
            },
            _footer: function () {
                var options = this.options;
                if (options.footer !== false) {
                    var html = '<div class="k-header k-scheduler-footer">';
                    var command = options.footer.command;
                    if (command && command === 'workDay') {
                        html += '<ul class="k-reset k-header">';
                        html += '<li class="k-state-default k-scheduler-fullday"><a href="#" class="k-link"><span class="k-icon k-i-clock"></span>';
                        html += (options.showWorkHours ? options.messages.showFullDay : options.messages.showWorkDay) + '</a></li>';
                        html += '</ul>';
                    } else {
                        html += '&nbsp;';
                    }
                    html += '</div>';
                    this.footer = $(html).appendTo(this.element);
                    var that = this;
                    this.footer.on('click' + NS, '.k-scheduler-fullday', function (e) {
                        e.preventDefault();
                        that.trigger('navigate', {
                            view: that.name || options.name,
                            date: that.startDate(),
                            isWorkDay: !options.showWorkHours
                        });
                    });
                }
            },
            _columnCountForLevel: function (level) {
                var columnLevel = this.columnLevels[level];
                return columnLevel ? columnLevel.length : 0;
            },
            _rowCountForLevel: function (level) {
                var rowLevel = this.rowLevels[level];
                return rowLevel ? rowLevel.length : 0;
            },
            _isWorkDay: function (date) {
                var day = date.getDay();
                var workDays = this._workDays;
                for (var i = 0; i < workDays.length; i++) {
                    if (workDays[i] === day) {
                        return true;
                    }
                }
                return false;
            },
            _content: function (dates) {
                var that = this;
                var start = that.startTime();
                var end = this.endTime();
                var groupsCount = 1;
                var rowCount = 1;
                var columnCount = dates.length;
                var html = '';
                var resources = this.groupedResources;
                var slotTemplate = this.slotTemplate;
                var isVerticalGrouped = false;
                if (resources.length) {
                    isVerticalGrouped = that._groupOrientation() === 'vertical';
                    if (isVerticalGrouped) {
                        rowCount = that._groupedView._getRowCount(this.rowLevels.length - 1);
                        groupsCount = that._groupedView._getGroupsCount();
                    } else {
                        groupsCount = that._groupCount();
                    }
                }
                html += '<tbody>';
                html += that._groupedView._addContent(dates, columnCount, groupsCount, rowCount, start, end, slotTemplate, isVerticalGrouped);
                html += '</tbody>';
                this.content.find('table').append(html);
            },
            _groups: function () {
                var groupCount = this._groupCount();
                var dates = this._dates;
                var columnCount = dates.length;
                this.groups = [];
                for (var idx = 0; idx < groupCount; idx++) {
                    var view = this._addResourceView(idx);
                    var start = dates[0];
                    var end = dates[dates.length - 1 || 0];
                    view.addTimeSlotCollection(start, kendo.date.addDays(end, 1));
                }
                this._timeSlotGroups(groupCount, columnCount);
            },
            _isHorizontallyGrouped: function () {
                return this.groupedResources.length && this._groupOrientation() === 'horizontal';
            },
            _timeSlotGroups: function (groupCount, datesCount) {
                var interval = this._timeSlotInterval();
                var isVerticallyGrouped = this._isVerticallyGrouped();
                var tableRows = this.content.find('tr');
                tableRows.attr('role', 'row');
                this._groupedView._addTimeSlotsCollections(groupCount, datesCount, tableRows, interval, isVerticallyGrouped);
            },
            _addTimeSlotToCollection: function (group, cells, cellIndex, cellOffset, dateIndex, time, interval) {
                var cell = cells[cellIndex + cellOffset];
                var collection = group.getTimeSlotCollection(0);
                var currentDate = this._dates[dateIndex];
                var currentTime = Date.UTC(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate());
                var start = currentTime + time;
                var end = start + interval;
                cell.setAttribute('role', 'gridcell');
                cell.setAttribute('aria-selected', false);
                collection.addTimeSlot(cell, start, end, true);
            },
            startDate: function () {
                return this._startDate;
            },
            endDate: function () {
                return this._endDate;
            },
            startTime: function () {
                var options = this.options;
                return options.showWorkHours ? options.workDayStart : options.startTime;
            },
            endTime: function () {
                var options = this.options;
                return options.showWorkHours ? options.workDayEnd : options.endTime;
            },
            _timeSlotInterval: function () {
                var options = this.options;
                return options.majorTick / options.minorTickCount * MS_PER_MINUTE;
            },
            nextDate: function () {
                return kendo.date.nextDay(this.endDate());
            },
            previousDate: function () {
                return kendo.date.previousDay(this.startDate());
            },
            calculateDateRange: function () {
                this._render([this.options.date]);
            },
            render: function (events) {
                this._headerColumnCount = 0;
                this._groups();
                this.element.find('.k-event').remove();
                events = new kendo.data.Query(events).sort([
                    {
                        field: 'start',
                        dir: 'asc'
                    },
                    {
                        field: 'end',
                        dir: 'desc'
                    }
                ]).toArray();
                var eventsByResource = [];
                this._eventsByResource(events, this.groupedResources, eventsByResource);
                var eventGroups = [];
                var maxRowCount = 0;
                for (var groupIndex = 0; groupIndex < eventsByResource.length; groupIndex++) {
                    var eventGroup = {
                        groupIndex: groupIndex,
                        maxRowCount: 0,
                        events: {}
                    };
                    eventGroups.push(eventGroup);
                    this._renderEvents(eventsByResource[groupIndex], groupIndex, eventGroup);
                    if (maxRowCount < eventGroup.maxRowCount) {
                        maxRowCount = eventGroup.maxRowCount;
                    }
                }
                this._setRowsHeight(eventGroups, eventsByResource.length, maxRowCount);
                this._positionEvents(eventGroups, eventsByResource.length);
                this._currentTime(false);
                this.trigger('activate');
            },
            _positionEvents: function (eventGroups, groupsCount) {
                for (var groupIndex = 0; groupIndex < groupsCount; groupIndex++) {
                    var eventsForGroup = eventGroups[groupIndex].events;
                    for (var eventUid in eventsForGroup) {
                        var eventObject = eventsForGroup[eventUid];
                        if ($.isArray(eventObject)) {
                            for (var eventIndex = 0; eventIndex < eventObject.length; eventIndex++) {
                                this._positionEvent(eventObject[eventIndex]);
                            }
                        } else {
                            this._positionEvent(eventObject);
                        }
                    }
                }
            },
            _setRowsHeight: function (eventGroups, groupsCount, maxRowCount) {
                var eventHeight = this.options.eventHeight + 2;
                var eventBottomOffset = this._getBottomRowOffset();
                var groupedView = this._groupedView;
                var verticalGroupCount = groupedView._getVerticalGroupCount(groupsCount);
                groupsCount = this._isVerticallyGrouped() ? verticalGroupCount : 1;
                for (var groupIndex = 0; groupIndex < groupsCount; groupIndex++) {
                    var rowsCount = groupedView._getVerticalRowCount(eventGroups, groupIndex, maxRowCount);
                    rowsCount = rowsCount ? rowsCount : 1;
                    var rowHeight = (eventHeight + 2) * rowsCount + eventBottomOffset;
                    var timesRow = $(this.times.find('tr')[groupIndex]);
                    var row = $(this.content.find('tr')[groupIndex]);
                    timesRow.height(rowHeight);
                    row.height(rowHeight);
                }
                this._setContentWidth();
                this.refreshLayout();
                this._refreshSlots();
            },
            _getBottomRowOffset: function () {
                var eventBottomOffset = this.options.eventHeight * 0.5;
                var isMobile = this._isMobile();
                var minOffset;
                var maxOffset;
                if (isMobile) {
                    minOffset = 30;
                    maxOffset = 60;
                } else {
                    minOffset = 15;
                    maxOffset = 30;
                }
                if (eventBottomOffset > maxOffset) {
                    eventBottomOffset = maxOffset;
                } else if (eventBottomOffset < minOffset) {
                    eventBottomOffset = minOffset;
                }
                return eventBottomOffset;
            },
            _positionEvent: function (eventObject) {
                var eventHeight = this.options.eventHeight + 2;
                var rect = eventObject.slotRange.innerRect(eventObject.start, eventObject.end, false);
                var left = this._adjustLeftPosition(rect.left);
                var width = rect.right - rect.left - 2;
                if (width < 0) {
                    width = 0;
                }
                if (width < this.options.eventMinWidth) {
                    var slotsCollection = eventObject.slotRange.collection;
                    var lastSlot = slotsCollection._slots[slotsCollection._slots.length - 1];
                    var offsetRight = lastSlot.offsetLeft + lastSlot.offsetWidth;
                    width = this.options.eventMinWidth;
                    if (offsetRight < left + width) {
                        width = offsetRight - rect.left - 2;
                    }
                }
                eventObject.element.css({
                    top: eventObject.slotRange.start.offsetTop + eventObject.rowIndex * (eventHeight + 2) + 'px',
                    left: left,
                    width: width
                });
            },
            _refreshSlots: function () {
                for (var groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
                    this.groups[groupIndex].refresh();
                }
            },
            _eventsByResource: function (events, resources, result) {
                var resource = resources[0];
                if (resource) {
                    var view = resource.dataSource.view();
                    for (var itemIdx = 0; itemIdx < view.length; itemIdx++) {
                        var value = this._resourceValue(resource, view[itemIdx]);
                        var eventsFilteredByResource = new kendo.data.Query(events).filter({
                            field: resource.field,
                            operator: SchedulerView.groupEqFilter(value)
                        }).toArray();
                        if (resources.length > 1) {
                            this._eventsByResource(eventsFilteredByResource, resources.slice(1), result);
                        } else {
                            result.push(eventsFilteredByResource);
                        }
                    }
                } else {
                    result.push(events);
                }
            },
            _isInDateSlot: function (event) {
                var startTime = event.start;
                var endTime = event.end;
                var rangeStart = getDate(this._startDate);
                var rangeEnd = kendo.date.addDays(getDate(this._endDate), 1);
                if (startTime < rangeEnd && rangeStart <= endTime) {
                    return true;
                }
                return false;
            },
            _isInTimeSlot: function (event) {
                var startTime = event._startTime || kendo.date.toUtcTime(event.start);
                var endTime = event._endTime || kendo.date.toUtcTime(event.end);
                var slotRanges = this._slotRanges;
                if (startTime === endTime) {
                    endTime = endTime + 1;
                }
                for (var slotIndex = 0; slotIndex < slotRanges.length; slotIndex++) {
                    if (startTime < slotRanges[slotIndex].end && slotRanges[slotIndex].start < endTime) {
                        return true;
                    }
                }
                return false;
            },
            _adjustEvent: function (event) {
                var start = event.start;
                var end = event.end;
                var eventStartTime = event._time('start');
                var eventEndTime = event._time('end');
                var startTime = getMilliseconds(this.startTime());
                var endTime = getMilliseconds(this.endTime());
                var adjustedStartDate = null;
                var adjustedEndDate = null;
                var occurrence;
                var head = false;
                var tail = false;
                if (event.isAllDay) {
                    adjustedStartDate = getDate(start);
                    if (startTime > eventStartTime) {
                        setTime(adjustedStartDate, startTime);
                        tail = true;
                    }
                    adjustedEndDate = getDate(end);
                    if (endTime === getMilliseconds(getDate(this.endTime()))) {
                        adjustedEndDate = kendo.date.addDays(adjustedEndDate, 1);
                    } else {
                        setTime(adjustedEndDate, endTime);
                        head = true;
                    }
                } else {
                    endTime = endTime === 0 ? MS_PER_DAY : endTime;
                    if (startTime > eventStartTime) {
                        adjustedStartDate = getDate(start);
                        setTime(adjustedStartDate, startTime);
                        tail = true;
                    } else if (endTime < eventStartTime) {
                        adjustedStartDate = getDate(start);
                        adjustedStartDate = kendo.date.addDays(adjustedStartDate, 1);
                        setTime(adjustedStartDate, startTime);
                        tail = true;
                    }
                    if (endTime < eventEndTime) {
                        adjustedEndDate = getDate(end);
                        setTime(adjustedEndDate, endTime);
                        head = true;
                    } else if (startTime > eventEndTime) {
                        adjustedEndDate = getDate(end);
                        adjustedEndDate = kendo.date.addDays(adjustedEndDate, -1);
                        setTime(adjustedEndDate, endTime);
                        head = true;
                    }
                }
                occurrence = event.clone({
                    start: adjustedStartDate ? adjustedStartDate : start,
                    end: adjustedEndDate ? adjustedEndDate : end,
                    _startTime: adjustedStartDate ? kendo.date.toUtcTime(adjustedStartDate) : event._startTime,
                    _endTime: adjustedEndDate ? kendo.date.toUtcTime(adjustedEndDate) : event._endTime,
                    isAllDay: false
                });
                return {
                    occurrence: occurrence,
                    head: head,
                    tail: tail
                };
            },
            _renderEvents: function (events, groupIndex, eventGroup) {
                var event;
                var idx;
                var length;
                for (idx = 0, length = events.length; idx < length; idx++) {
                    event = events[idx];
                    if (this._isInDateSlot(event)) {
                        var isMultiDayEvent = event.isAllDay || event.end.getTime() - event.start.getTime() >= MS_PER_DAY;
                        var container = this.content;
                        if (isMultiDayEvent || this._isInTimeSlot(event)) {
                            var adjustedEvent = this._adjustEvent(event);
                            var group = this.groups[groupIndex];
                            if (!group._continuousEvents) {
                                group._continuousEvents = [];
                            }
                            var ranges = group.slotRanges(adjustedEvent.occurrence, false);
                            var range = ranges[0];
                            var startIndex = range.start.index;
                            var endIndex = range.end.index;
                            if (this._isInTimeSlot(adjustedEvent.occurrence)) {
                                this._groupedView._renderEvent(eventGroup, event, adjustedEvent, group, range, container, startIndex, endIndex);
                            }
                        }
                    }
                }
            },
            addContinuousEvent: function (group, range, element, isAllDay) {
                var events = group._continuousEvents;
                events.push({
                    element: element,
                    isAllDay: isAllDay,
                    uid: element.attr(kendo.attr('uid')),
                    start: range.start,
                    end: range.end
                });
            },
            _createEventElement: function (occurrence, event, head, tail) {
                var template = this.eventTemplate;
                var editable = this.options.editable;
                var isMobile = this._isMobile();
                var showDelete = editable && editable.destroy !== false && !isMobile;
                var resizable = editable && editable.resize !== false;
                var eventStartTime = event._time('start');
                var eventEndTime = event._time('end');
                var eventStartDate = event.start;
                var eventEndDate = event.end;
                var resources = this.eventResources(event);
                if (event._startTime && eventStartTime !== kendo.date.getMilliseconds(event.start)) {
                    eventStartDate = new Date(eventStartTime);
                    eventStartDate = kendo.timezone.apply(eventStartDate, 'Etc/UTC');
                }
                if (event._endTime && eventEndTime !== kendo.date.getMilliseconds(event.end)) {
                    eventEndDate = new Date(eventEndTime);
                    eventEndDate = kendo.timezone.apply(eventEndDate, 'Etc/UTC');
                }
                var data = extend({}, {
                    ns: kendo.ns,
                    resizable: resizable,
                    showDelete: showDelete,
                    head: head,
                    tail: tail,
                    singleDay: this._dates.length == 1,
                    resources: resources,
                    inverseColor: resources && resources[0] ? this._shouldInverseResourceColor(resources[0]) : false,
                    messages: this.options.messages
                }, event, {
                    start: eventStartDate,
                    end: eventEndDate
                });
                var element = $(template(data));
                this.angular('compile', function () {
                    return {
                        elements: element,
                        data: [{ dataItem: data }]
                    };
                });
                return element;
            },
            _arrangeRows: function (eventObject, slotRange, eventGroup) {
                var startIndex = slotRange.start.index;
                var endIndex = slotRange.end.index;
                var rect = eventObject.slotRange.innerRect(eventObject.start, eventObject.end, false);
                var rectRight = rect.right + this.options.eventMinWidth;
                var events = collidingEvents(slotRange.events(), rect.left, rectRight);
                slotRange.addEvent({
                    slotIndex: startIndex,
                    start: startIndex,
                    end: endIndex,
                    rectLeft: rect.left,
                    rectRight: rectRight,
                    element: eventObject.element,
                    uid: eventObject.uid
                });
                events.push({
                    start: startIndex,
                    end: endIndex,
                    uid: eventObject.uid
                });
                var rows = SchedulerView.createRows(events);
                if (eventGroup.maxRowCount < rows.length) {
                    eventGroup.maxRowCount = rows.length;
                }
                for (var idx = 0, length = rows.length; idx < length; idx++) {
                    var rowEvents = rows[idx].events;
                    for (var j = 0, eventLength = rowEvents.length; j < eventLength; j++) {
                        eventGroup.events[rowEvents[j].uid].rowIndex = idx;
                    }
                }
            },
            _groupCount: function () {
                var resources = this.groupedResources;
                var groupedView = this._groupedView;
                if (resources.length) {
                    if (this._groupOrientation() === 'vertical') {
                        return groupedView._verticalCountForLevel(resources.length - 1);
                    } else {
                        return groupedView._horizontalCountForLevel(resources.length - 1, this.columnLevels.length - 1);
                    }
                }
                return 1;
            },
            _updateEventForSelection: function (event) {
                var adjustedEvent = this._adjustEvent(event.clone());
                return adjustedEvent.occurrence;
            },
            _eventOptionsForMove: function (event) {
                if (event.isAllDay) {
                    return { isAllDay: false };
                }
                return {};
            },
            _updateEventForResize: function (event) {
                if (event.isAllDay) {
                    event.set('isAllDay', false);
                }
            },
            _updateMoveHint: function (event, groupIndex, distance) {
                var group = this.groups[groupIndex];
                var clonedEvent = event.clone({
                    start: event.start,
                    end: event.end
                });
                var eventDuraton = clonedEvent.duration();
                clonedEvent.start = new Date(clonedEvent.start.getTime() + distance);
                clonedEvent.end = new Date(+clonedEvent.start + eventDuraton);
                var adjustedEvent = this._adjustEvent(clonedEvent);
                var ranges = group.slotRanges(adjustedEvent.occurrence, false);
                this._removeMoveHint();
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    this._groupedView._createMoveHint(ranges[rangeIndex], adjustedEvent);
                }
                var content = this.content;
                this._moveHint.appendTo(content);
            },
            _updateResizeHint: function (event, groupIndex, startTime, endTime) {
                var group = this.groups[groupIndex];
                var ranges = group.ranges(startTime, endTime, false, false);
                this._removeResizeHint();
                for (var rangeIndex = 0; rangeIndex < ranges.length; rangeIndex++) {
                    var range = ranges[rangeIndex];
                    var start = range.startSlot();
                    var startRect = range.innerRect(startTime, endTime, false);
                    startRect.top = start.offsetTop;
                    var width = startRect.right - startRect.left;
                    var height = range.endSlot().offsetTop + start.offsetHeight - startRect.top;
                    var left = this._adjustLeftPosition(startRect.left);
                    var hint = SchedulerView.fn._createResizeHint.call(this, left, startRect.top, width, height);
                    this._resizeHint = this._resizeHint.add(hint);
                }
                var format = 't';
                var container = this.content;
                this._resizeHint.appendTo(container);
                this._resizeHint.find('.k-label-top,.k-label-bottom').text('');
                this._resizeHint.first().addClass('k-first').find('.k-label-top').text(kendo.toString(kendo.timezone.toLocalDate(startTime), format));
                this._resizeHint.last().addClass('k-last').find('.k-label-bottom').text(kendo.toString(kendo.timezone.toLocalDate(endTime), format));
            },
            selectionByElement: function (cell) {
                var offset = cell.offset();
                return this._slotByPosition(offset.left, offset.top);
            },
            _updateDirection: function (selection, ranges, multiple, reverse, vertical) {
                var startSlot = ranges[0].start;
                var endSlot = ranges[ranges.length - 1].end;
                if (multiple && !vertical) {
                    if (startSlot.index === endSlot.index && startSlot.collectionIndex === endSlot.collectionIndex) {
                        selection.backward = reverse;
                    }
                }
            },
            _changeGroup: function (selection, previous) {
                var method = previous ? 'prevGroupSlot' : 'nextGroupSlot';
                var slot = this[method](selection.start, selection.groupIndex, false);
                if (slot) {
                    selection.groupIndex += previous ? -1 : 1;
                }
                this._groupedView._changeGroup(selection, previous, slot);
                return slot;
            },
            prevGroupSlot: function (date, groupIndex, isDay) {
                var group = this.groups[groupIndex];
                var slot = group.ranges(date, date, isDay, false)[0].start;
                if (groupIndex <= 0) {
                    return;
                }
                return this._groupedView._prevGroupSlot(slot, group, isDay);
            },
            nextGroupSlot: function (date, groupIndex, isDay) {
                var group = this.groups[groupIndex];
                var slot = group.ranges(date, date, isDay, false)[0].start;
                if (groupIndex >= this.groups.length - 1) {
                    return;
                }
                return this._groupedView._nextGroupSlot(slot, group, isDay);
            },
            _verticalSlots: function (selection, ranges, multiple, reverse) {
                var groupedView = this._groupedView;
                var method = groupedView._verticalMethod(reverse, multiple);
                var startSlot = ranges[0].start;
                var endSlot = ranges[ranges.length - 1].end;
                var group = this.groups[selection.groupIndex];
                var slot = groupedView._normalizeVerticalSelection(selection, ranges, reverse, multiple);
                if (slot) {
                    startSlot = endSlot = slot;
                }
                startSlot = group[method](startSlot);
                endSlot = group[method](endSlot);
                if (!multiple && this._isVerticallyGrouped() && (!startSlot || !endSlot)) {
                    startSlot = endSlot = groupedView._verticalSlots(selection, reverse, slot);
                }
                return {
                    startSlot: startSlot,
                    endSlot: endSlot
                };
            },
            _horizontalSlots: function (selection, ranges, multiple, reverse) {
                var method = reverse ? 'upSlot' : 'downSlot';
                var startSlot = ranges[0].start;
                var endSlot = ranges[ranges.length - 1].end;
                var group = this.groups[selection.groupIndex];
                var result = {};
                if (!multiple) {
                    result = this._groupedView._horizontalSlots(selection, group, method, startSlot, endSlot, multiple, reverse);
                } else {
                    result.startSlot = group[method](startSlot);
                    result.endSlot = group[method](endSlot);
                    if (!multiple && this._isHorizontallyGrouped() && (!startSlot || !endSlot)) {
                        result.startSlot = result.endSlot = this._changeGroup(selection, reverse);
                    }
                }
                return result;
            },
            _changeViewPeriod: function (selection, reverse) {
                var date = reverse ? this.previousDate() : this.nextDate();
                var start = selection.start;
                var end = selection.end;
                selection.start = new Date(date);
                selection.end = new Date(date);
                if (this._isHorizontallyGrouped()) {
                    selection.groupIndex = reverse ? this.groups.length - 1 : 0;
                }
                var duration = end - start;
                if (reverse) {
                    end = getMilliseconds(this.endTime());
                    end = end === 0 ? MS_PER_DAY : end;
                    setTime(selection.start, end - duration);
                    setTime(selection.end, end);
                } else {
                    start = getMilliseconds(this.startTime());
                    setTime(selection.start, start);
                    setTime(selection.end, start + duration);
                }
                selection.events = [];
                return true;
            },
            move: function (selection, key, shift) {
                var handled = false;
                var group = this.groups[selection.groupIndex];
                var keys = kendo.keys;
                var groupedView = this._groupedView;
                var ranges = group.ranges(selection.start, selection.end, false, false);
                var startSlot, endSlot, reverse, slots;
                if (key === keys.DOWN || key === keys.UP) {
                    handled = true;
                    reverse = key === keys.UP;
                    groupedView._updateDirection(selection, ranges, shift, reverse);
                    slots = this._verticalSlots(selection, ranges, shift, reverse);
                    if (groupedView._changeVerticalViewPeriod(slots, shift, selection, reverse)) {
                        return handled;
                    }
                } else if (key === keys.LEFT || key === keys.RIGHT) {
                    handled = true;
                    reverse = key === keys.LEFT;
                    this._updateDirection(selection, ranges, shift, reverse, false);
                    slots = this._horizontalSlots(selection, ranges, shift, reverse);
                    if (groupedView._changeHorizontalViewPeriod(slots, shift, selection, reverse)) {
                        return handled;
                    }
                }
                if (handled) {
                    startSlot = slots.startSlot;
                    endSlot = slots.endSlot;
                    if (shift) {
                        var backward = selection.backward;
                        if (backward && startSlot) {
                            selection.start = startSlot.startDate();
                        } else if (!backward && endSlot) {
                            selection.end = endSlot.endDate();
                        }
                    } else if (startSlot && endSlot) {
                        selection.start = startSlot.startDate();
                        selection.end = endSlot.endDate();
                    }
                    selection.events = [];
                }
                return handled;
            },
            destroy: function () {
                var that = this;
                if (that.element) {
                    that.element.off(NS);
                }
                if (that.footer) {
                    that.footer.remove();
                }
                if (that._currentTimeUpdateTimer) {
                    clearInterval(that._currentTimeUpdateTimer);
                }
                SchedulerView.fn.destroy.call(this);
                if (this._isMobile() && that.options.editable) {
                    if (that.options.editable.create !== false) {
                        that._addUserEvents.destroy();
                    }
                    if (that.options.editable.update !== false) {
                        that._editUserEvents.destroy();
                    }
                }
            }
        });
        extend(true, ui, {
            TimelineView: TimelineView,
            TimelineWeekView: TimelineView.extend({
                options: {
                    name: 'TimelineWeekView',
                    title: 'Timeline Week',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}',
                    majorTick: 120
                },
                name: 'timelineWeek',
                calculateDateRange: function () {
                    var selectedDate = this.options.date, start = kendo.date.dayOfWeek(selectedDate, this.calendarInfo().firstDay, -1), idx, length, dates = [];
                    for (idx = 0, length = 7; idx < length; idx++) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            }),
            TimelineWorkWeekView: TimelineView.extend({
                options: {
                    name: 'TimelineWorkWeekView',
                    title: 'Timeline Work Week',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}',
                    majorTick: 120
                },
                name: 'timelineWorkWeek',
                nextDate: function () {
                    var weekStart = kendo.date.dayOfWeek(kendo.date.nextDay(this.endDate()), this.calendarInfo().firstDay, 1);
                    return kendo.date.addDays(weekStart, this._workDays[0]);
                },
                previousDate: function () {
                    var weekStart = kendo.date.dayOfWeek(this.startDate(), this.calendarInfo().firstDay, -1);
                    var workDays = this._workDays;
                    return kendo.date.addDays(weekStart, workDays[workDays.length - 1] - 7);
                },
                calculateDateRange: function () {
                    var selectedDate = this.options.date, start = kendo.date.dayOfWeek(selectedDate, this.options.workWeekStart, -1), end = kendo.date.dayOfWeek(start, this.options.workWeekEnd, 1), dates = [];
                    while (start <= end) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            }),
            TimelineMonthView: TimelineView.extend({
                options: {
                    name: 'TimelineMonthView',
                    title: 'Timeline Month',
                    selectedDateFormat: '{0:D} - {1:D}',
                    selectedShortDateFormat: '{0:d} - {1:d}',
                    workDayStart: new Date(1980, 1, 1, 0, 0, 0),
                    workDayEnd: new Date(1980, 1, 1, 23, 59, 59),
                    footer: false,
                    majorTick: 1440,
                    minorTickCount: 1
                },
                name: 'timelineMonth',
                calculateDateRange: function () {
                    var selectedDate = this.options.date, start = kendo.date.firstDayOfMonth(selectedDate), end = kendo.date.lastDayOfMonth(selectedDate), idx, length, dates = [];
                    for (idx = 0, length = end.getDate(); idx < length; idx++) {
                        dates.push(start);
                        start = kendo.date.nextDay(start);
                    }
                    this._render(dates);
                }
            })
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.scheduler', [
        'kendo.dropdownlist',
        'kendo.editable',
        'kendo.multiselect',
        'kendo.window',
        'kendo.datetimepicker',
        'kendo.scheduler.recurrence',
        'kendo.scheduler.view',
        'kendo.scheduler.dayview',
        'kendo.scheduler.agendaview',
        'kendo.scheduler.monthview',
        'kendo.scheduler.timelineview',
        'kendo.mobile.actionsheet',
        'kendo.mobile.pane',
        'kendo.pdf'
    ], f);
}(function () {
    var __meta__ = {
        id: 'scheduler',
        name: 'Scheduler',
        category: 'web',
        description: 'The Scheduler is an event calendar.',
        depends: [
            'dropdownlist',
            'editable',
            'multiselect',
            'window',
            'datepicker',
            'datetimepicker',
            'scheduler.recurrence',
            'scheduler.view'
        ],
        features: [
            {
                id: 'scheduler-dayview',
                name: 'Scheduler Day View',
                description: 'Scheduler Day View',
                depends: ['scheduler.dayview']
            },
            {
                id: 'scheduler-agendaview',
                name: 'Scheduler Agenda View',
                description: 'Scheduler Agenda View',
                depends: ['scheduler.agendaview']
            },
            {
                id: 'scheduler-monthview',
                name: 'Scheduler Month View',
                description: 'Scheduler Month View',
                depends: ['scheduler.monthview']
            },
            {
                id: 'scheduler-timelineview',
                name: 'Scheduler Timeline View',
                description: 'Scheduler Timeline View',
                depends: ['scheduler.timelineview']
            },
            {
                id: 'scheduler-mobile',
                name: 'Scheduler adaptive rendering',
                description: 'Support for adaptive rendering',
                depends: [
                    'mobile.actionsheet',
                    'mobile.pane'
                ]
            },
            {
                id: 'scheduler-pdf-export',
                name: 'PDF export',
                description: 'Export the scheduler events as PDF',
                depends: [
                    'pdf',
                    'drawing'
                ]
            },
            {
                id: 'scheduler-timezones',
                name: 'Timezones',
                description: 'Allow selecting timezones different than Etc/UTC',
                depends: ['timezones']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, date = kendo.date, input_support = kendo.support.input, MS_PER_DAY = date.MS_PER_DAY, getDate = date.getDate, getMilliseconds = kendo.date.getMilliseconds, recurrence = kendo.recurrence, keys = kendo.keys, ui = kendo.ui, Widget = ui.Widget, DataBoundWidget = ui.DataBoundWidget, STRING = 'string', Popup = ui.Popup, Calendar = ui.Calendar, DataSource = kendo.data.DataSource, isPlainObject = $.isPlainObject, extend = $.extend, proxy = $.proxy, toString = Object.prototype.toString, isArray = $.isArray, NS = '.kendoScheduler', CLICK = 'click', MOUSEDOWN = 'mousedown', CHANGE = 'change', CANCEL = 'cancel', REMOVE = 'remove', SAVE = 'save', ADD = 'add', EDIT = 'edit', valueStartEndBoundRegex = /(?:value:start|value:end)(?:,|$)/, TODAY = getDate(new Date()), EXCEPTION_SEPARATOR = ',', OLD_EXCEPTION_SEPARATOR_REGEXP = /\;/g, RECURRENCE_EXCEPTION = 'recurrenceException', DELETECONFIRM = 'Are you sure you want to delete this event?', DELETERECURRING = 'Do you want to delete only this event occurrence or the whole series?', EDITRECURRING = 'Do you want to edit only this event occurrence or the whole series?', DELETERECURRINGCONFIRM = 'Are you sure you want to delete this event occurrence?', DELETESERIESCONFIRM = 'Are you sure you want to delete the whole series?', COMMANDBUTTONTMPL = '<a class="k-button #=className#" #=attr# href="\\#">#=text#</a>', VIEWBUTTONTEMPLATE = kendo.template('<li class="k-current-view" data-#=ns#name="#=view#"><a role="button" href="\\#" class="k-link">${views[view].title}</a></li>'), TOOLBARTEMPLATE = kendo.template('<div class="k-floatwrap k-header k-scheduler-toolbar">' + '# if (pdf) { #' + '<ul class="k-reset k-scheduler-tools">' + '<li><a role="button" href="\\#" class="k-button k-pdf"><span class="k-icon k-i-file-pdf"></span>${messages.pdf}</a></li>' + '</ul>' + '# } #' + '<ul class="k-reset k-scheduler-navigation">' + '<li class="k-state-default k-header k-nav-today"><a role="button" href="\\#" class="k-link" title="${messages.today}">${messages.today}</a></li>' + '<li class="k-state-default k-header k-nav-prev"><a role="button" href="\\#" class="k-link" title="${messages.previous}" aria-label="${messages.previous}"><span class="k-icon k-i-arrow-60-left"></span></a></li>' + '<li class="k-state-default k-header k-nav-next"><a role="button" href="\\#" class="k-link" title="${messages.next}" aria-label="${messages.next}"><span class="k-icon k-i-arrow-60-right"></span></a></li>' + '<li class="k-state-default k-nav-current">' + '<a role="button" href="\\#" class="k-link">' + '<span class="k-icon k-i-calendar"></span>' + '<span class="k-sm-date-format" data-#=ns#bind="text: formattedShortDate"></span>' + '<span class="k-lg-date-format" data-#=ns#bind="text: formattedDate"></span>' + '</a>' + '</li>' + '</ul>' + '#if(viewsCount === 1){#' + '<a role="button" data-#=ns#name="#=view#" href="\\#" class="k-link k-scheduler-refresh">' + '<span class="k-icon k-i-reload"></span>' + '</a>' + '#}else{#' + '<ul class="k-reset k-header k-scheduler-views">' + '#for(var view in views){#' + '<li class="k-state-default k-view-#= view.toLowerCase() #" data-#=ns#name="#=view#"><a role="button" href="\\#" class="k-link">${views[view].title}</a></li>' + '#}#' + '</ul>' + '#}#' + '</div>'), MOBILETOOLBARTEMPLATE = kendo.template('<div class="k-floatwrap k-header k-scheduler-toolbar">' + '<ul class="k-reset k-header k-scheduler-navigation">' + '<li class="k-state-default k-nav-today"><a role="button" href="\\#" class="k-link">${messages.today}</a></li>' + '</ul>' + '#if(viewsCount === 1){#' + '<a role="button" data-#=ns#name="#=view#" href="\\#" class="k-link k-scheduler-refresh">' + '<span class="k-icon k-i-reload"></span>' + '</a>' + '#}else{#' + '<ul class="k-reset k-header k-scheduler-views">' + '#for(var view in views){#' + '<li class="k-state-default k-view-#= view.toLowerCase() #" data-#=ns#name="#=view#"><a role="button" href="\\#" class="k-link">${views[view].title}</a></li>' + '#}#' + '</ul>' + '#}#' + '</div>' + '<div class="k-floatwrap k-header k-scheduler-toolbar">' + '<ul class="k-reset k-header k-scheduler-navigation">' + '<li class="k-state-default k-nav-prev"><a role="button" href="\\#" class="k-link"><span class="k-icon k-i-arrow-60-left"></span></a></li>' + '<li class="k-state-default k-nav-current">' + '<span class="k-sm-date-format" data-#=ns#bind="text: formattedShortDate"></span>' + '<span class="k-lg-date-format" data-#=ns#bind="text: formattedDate"></span>' + '</li>' + '<li class="k-state-default k-nav-next"><a role="button" href="\\#" class="k-link"><span class="k-icon k-i-arrow-60-right"></span></a></li>' + '</ul>' + '</div>'), MOBILEDATERANGEEDITOR = function (container, options) {
                var attr = {
                    name: options.field,
                    title: options.title
                };
                var datepicker_role = !input_support.date ? kendo.attr('role') + '="datepicker" ' : '';
                var datetimepicker_role = kendo.attr('role') + '="datetimepicker" ';
                var isAllDay = options.model.isAllDay;
                var dateTimeValidate = kendo.attr('validate') + '=\'' + !isAllDay + '\'';
                var dateValidate = kendo.attr('validate') + '=\'' + isAllDay + '\'';
                appendTimezoneAttr(attr, options);
                appendDateCompareValidator(attr, options);
                $('<input type="datetime-local" required ' + kendo.attr('type') + '="date" ' + datetimepicker_role + kendo.attr('bind') + '="value:' + options.field + ',invisible:isAllDay" ' + dateTimeValidate + '/>').attr(attr).appendTo(container);
                $('<input type="date" required ' + kendo.attr('type') + '="date" ' + datepicker_role + kendo.attr('bind') + '="value:' + options.field + ',visible:isAllDay" ' + dateValidate + '/>').attr(attr).appendTo(container);
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            }, DATERANGEEDITOR = function (container, options) {
                var attr = {
                        name: options.field,
                        title: options.title
                    }, isAllDay = options.model.isAllDay, dateTimeValidate = kendo.attr('validate') + '=\'' + !isAllDay + '\' ', dateValidate = kendo.attr('validate') + '=\'' + isAllDay + '\' ';
                appendTimezoneAttr(attr, options);
                appendDateCompareValidator(attr, options);
                $('<input type="text" required ' + kendo.attr('type') + '="date"' + ' ' + kendo.attr('role') + '="datetimepicker" ' + kendo.attr('bind') + '="value:' + options.field + ',invisible:isAllDay" ' + dateTimeValidate + '/>').attr(attr).appendTo(container);
                $('<input type="text" required ' + kendo.attr('type') + '="date"' + ' ' + kendo.attr('role') + '="datepicker" ' + kendo.attr('bind') + '="value:' + options.field + ',visible:isAllDay" ' + dateValidate + '/>').attr(attr).appendTo(container);
                $('<span ' + kendo.attr('bind') + '="text: ' + options.field + 'Timezone"></span>').appendTo(container);
                if (options.field === 'end') {
                    $('<span ' + kendo.attr('bind') + '="text: startTimezone, invisible: endTimezone"></span>').appendTo(container);
                }
                $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
            }, RECURRENCEEDITOR = function (container, options) {
                $('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).appendTo(container).kendoRecurrenceEditor({
                    start: options.model.start,
                    timezone: options.timezone,
                    messages: options.messages
                });
            }, MOBILERECURRENCEEDITOR = function (container, options) {
                $('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).appendTo(container).kendoMobileRecurrenceEditor({
                    start: options.model.start,
                    timezone: options.timezone,
                    messages: options.messages,
                    pane: options.pane,
                    value: options.model[options.field]
                });
            }, MOBILETIMEZONEPOPUP = function (container, options) {
                var text = timezoneButtonText(options.model, options.messages.noTimezone);
                $('<a href="#" class="k-button k-timezone-button" data-bind="invisible:isAllDay">' + text + '</a>').click(options.click).appendTo(container);
            }, TIMEZONEPOPUP = function (container, options) {
                $('<a href="#" class="k-button" data-bind="invisible:isAllDay">' + options.messages.timezoneEditorButton + '</a>').click(options.click).appendTo(container);
            }, MOBILETIMEZONEEDITOR = function (container, options) {
                $('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).toggle(options.visible).appendTo(container).kendoMobileTimezoneEditor({ optionLabel: options.noTimezone });
            }, TIMEZONEEDITOR = function (container, options) {
                var visible = options.visible || options.visible === undefined;
                $('<div ' + kendo.attr('bind') + '="value:' + options.field + '" />').attr({ name: options.field }).toggle(visible).appendTo(container).kendoTimezoneEditor({
                    optionLabel: options.noTimezone,
                    title: options.title
                });
            };
        function timezoneButtonText(model, message) {
            message = message || '';
            if (model.startTimezone) {
                message = model.startTimezone;
                if (model.endTimezone) {
                    message += ' | ' + model.endTimezone;
                }
            }
            return message;
        }
        function appendTimezoneAttr(attrs, options) {
            var timezone = options.timezone;
            if (timezone) {
                attrs[kendo.attr('timezone')] = timezone;
            }
        }
        function appendDateCompareValidator(attrs, options) {
            var validationRules = options.model.fields[options.field].validation;
            if (validationRules) {
                var dateCompareRule = validationRules.dateCompare;
                if (dateCompareRule && isPlainObject(dateCompareRule) && dateCompareRule.message) {
                    attrs[kendo.attr('dateCompare-msg')] = dateCompareRule.message;
                }
            }
        }
        function wrapDataAccess(originalFunction, timezone) {
            return function (data) {
                data = originalFunction(data);
                convertData(data, 'apply', timezone);
                return data || [];
            };
        }
        function wrapDataSerialization(originalFunction, timezone) {
            return function (data) {
                if (data) {
                    if (toString.call(data) !== '[object Array]' && !(data instanceof kendo.data.ObservableArray)) {
                        data = [data];
                    }
                }
                convertData(data, 'remove', timezone, true);
                data = originalFunction(data);
                return data || [];
            };
        }
        function convertData(data, method, timezone, removeUid) {
            var event, idx, length;
            data = data || [];
            for (idx = 0, length = data.length; idx < length; idx++) {
                event = data[idx];
                if (removeUid) {
                    if (event.startTimezone || event.endTimezone) {
                        if (timezone) {
                            event.start = kendo.timezone.convert(event.start, event.startTimezone || event.endTimezone, timezone);
                            event.end = kendo.timezone.convert(event.end, event.endTimezone || event.startTimezone, timezone);
                            event.start = kendo.timezone[method](event.start, timezone);
                            event.end = kendo.timezone[method](event.end, timezone);
                        } else {
                            event.start = kendo.timezone[method](event.start, event.startTimezone || event.endTimezone);
                            event.end = kendo.timezone[method](event.end, event.endTimezone || event.startTimezone);
                        }
                    } else if (timezone) {
                        event.start = kendo.timezone[method](event.start, timezone);
                        event.end = kendo.timezone[method](event.end, timezone);
                    }
                } else {
                    if (event.startTimezone || event.endTimezone) {
                        event.start = kendo.timezone[method](event.start, event.startTimezone || event.endTimezone);
                        event.end = kendo.timezone[method](event.end, event.endTimezone || event.startTimezone);
                        if (timezone) {
                            event.start = kendo.timezone.convert(event.start, event.startTimezone || event.endTimezone, timezone);
                            event.end = kendo.timezone.convert(event.end, event.endTimezone || event.startTimezone, timezone);
                        }
                    } else if (timezone) {
                        event.start = kendo.timezone[method](event.start, timezone);
                        event.end = kendo.timezone[method](event.end, timezone);
                    }
                }
                if (removeUid) {
                    delete event.uid;
                }
            }
            return data;
        }
        function getOccurrenceByUid(data, uid) {
            var length = data.length, idx = 0, event;
            for (; idx < length; idx++) {
                event = data[idx];
                if (event.uid === uid) {
                    return event;
                }
            }
        }
        var SchedulerDataReader = kendo.Class.extend({
            init: function (schema, reader) {
                var timezone = schema.timezone;
                this.reader = reader;
                if (reader.model) {
                    this.model = reader.model;
                }
                this.timezone = timezone;
                this.data = wrapDataAccess($.proxy(this.data, this), timezone);
                this.serialize = wrapDataSerialization($.proxy(this.serialize, this), timezone);
            },
            errors: function (data) {
                return this.reader.errors(data);
            },
            parse: function (data) {
                return this.reader.parse(data);
            },
            data: function (data) {
                return this.reader.data(data);
            },
            total: function (data) {
                return this.reader.total(data);
            },
            groups: function (data) {
                return this.reader.groups(data);
            },
            aggregates: function (data) {
                return this.reader.aggregates(data);
            },
            serialize: function (data) {
                return this.reader.serialize(data);
            }
        });
        function applyZone(date, fromZone, toZone) {
            if (toZone) {
                date = kendo.timezone.convert(date, fromZone, toZone);
            } else {
                date = kendo.timezone.remove(date, fromZone);
            }
            return date;
        }
        function dateCompareValidator(input) {
            if (input.filter('[name=end]').length) {
                var container = input.closest('.k-scheduler-edit-form');
                var startInput = container.find('[name=start]:visible');
                var endInput = container.find('[name=end]:visible');
                if (endInput[0] && startInput[0]) {
                    var start, end;
                    var startPicker = kendo.widgetInstance(startInput, kendo.ui);
                    var endPicker = kendo.widgetInstance(endInput, kendo.ui);
                    var editable = container.data('kendoEditable');
                    var model = editable ? editable.options.model : null;
                    if (startPicker && endPicker) {
                        start = startPicker.value();
                        end = endPicker.value();
                    } else {
                        start = kendo.parseDate(startInput.val());
                        end = kendo.parseDate(endInput.val());
                    }
                    if (start && end) {
                        if (model) {
                            var timezone = startInput.attr(kendo.attr('timezone'));
                            var startTimezone = model.startTimezone;
                            var endTimezone = model.endTimezone;
                            startTimezone = startTimezone || endTimezone;
                            endTimezone = endTimezone || startTimezone;
                            if (startTimezone) {
                                start = applyZone(start, startTimezone, timezone);
                                end = applyZone(end, endTimezone, timezone);
                            }
                        }
                        return start <= end;
                    }
                }
            }
            return true;
        }
        var SchedulerEvent = kendo.data.Model.define({
            init: function (value) {
                var that = this;
                kendo.data.Model.fn.init.call(that, value);
                that._defaultId = that.defaults[that.idField];
            },
            _time: function (field) {
                var date = this[field];
                var fieldTime = '_' + field + 'Time';
                if (this[fieldTime]) {
                    return this[fieldTime] - kendo.date.toUtcTime(kendo.date.getDate(date));
                }
                return getMilliseconds(date);
            },
            _date: function (field) {
                var fieldTime = '_' + field + 'Time';
                if (this[fieldTime]) {
                    return this[fieldTime] - this._time(field);
                }
                return kendo.date.getDate(this[field]);
            },
            clone: function (options, updateUid) {
                var uid = this.uid, event = new this.constructor($.extend({}, this.toJSON(), options));
                if (!updateUid) {
                    event.uid = uid;
                }
                return event;
            },
            duration: function () {
                var end = this.end;
                var start = this.start;
                var offset = (end.getTimezoneOffset() - start.getTimezoneOffset()) * kendo.date.MS_PER_MINUTE;
                return end - start - offset;
            },
            expand: function (start, end, zone) {
                return recurrence ? recurrence.expand(this, start, end, zone) : [this];
            },
            update: function (eventInfo) {
                for (var field in eventInfo) {
                    this.set(field, eventInfo[field]);
                }
                if (this._startTime) {
                    this.set('_startTime', kendo.date.toUtcTime(this.start));
                }
                if (this._endTime) {
                    this.set('_endTime', kendo.date.toUtcTime(this.end));
                }
            },
            isMultiDay: function () {
                return this.isAllDay || this.duration() >= kendo.date.MS_PER_DAY;
            },
            isException: function () {
                return !this.isNew() && this.recurrenceId;
            },
            isOccurrence: function () {
                return this.isNew() && this.recurrenceId;
            },
            isRecurring: function () {
                return !!(this.recurrenceRule || this.recurrenceId);
            },
            isRecurrenceHead: function () {
                return !!(this.id && this.recurrenceRule);
            },
            toOccurrence: function (options) {
                options = $.extend(options, {
                    recurrenceException: null,
                    recurrenceRule: null,
                    recurrenceId: this.id || this.recurrenceId
                });
                options[this.idField] = this.defaults[this.idField];
                return this.clone(options, true);
            },
            toJSON: function () {
                var obj = kendo.data.Model.fn.toJSON.call(this);
                obj.uid = this.uid;
                delete obj._startTime;
                delete obj._endTime;
                return obj;
            },
            shouldSerialize: function (field) {
                return kendo.data.Model.fn.shouldSerialize.call(this, field) && field !== '_defaultId';
            },
            set: function (key, value) {
                var isAllDay = this.isAllDay || false;
                kendo.data.Model.fn.set.call(this, key, value);
                if (key == 'isAllDay' && value != isAllDay) {
                    var start = kendo.date.getDate(this.start);
                    var end = new Date(this.end);
                    var milliseconds = kendo.date.getMilliseconds(end);
                    if (milliseconds === 0 && value) {
                        milliseconds = MS_PER_DAY;
                    }
                    this.set('start', start);
                    if (value === true) {
                        kendo.date.setTime(end, -milliseconds);
                        if (end < start) {
                            end = start;
                        }
                    } else {
                        kendo.date.setTime(end, MS_PER_DAY - milliseconds);
                    }
                    this.set('end', end);
                }
            },
            id: 'id',
            fields: {
                id: { type: 'number' },
                title: {
                    defaultValue: '',
                    type: 'string'
                },
                start: {
                    type: 'date',
                    validation: { required: true }
                },
                startTimezone: { type: 'string' },
                end: {
                    type: 'date',
                    validation: {
                        required: true,
                        dateCompare: { value: dateCompareValidator }
                    }
                },
                endTimezone: { type: 'string' },
                recurrenceRule: {
                    defaultValue: '',
                    type: 'string'
                },
                recurrenceException: {
                    defaultValue: '',
                    type: 'string'
                },
                isAllDay: {
                    type: 'boolean',
                    defaultValue: false
                },
                description: { type: 'string' }
            }
        });
        var SchedulerDataSource = DataSource.extend({
            init: function (options) {
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: SchedulerEvent,
                        model: SchedulerEvent
                    }
                }, options));
                this.reader = new SchedulerDataReader(this.options.schema, this.reader);
            },
            expand: function (start, end) {
                var data = this.view(), filter = {};
                if (start && end) {
                    end = new Date(end.getTime() + MS_PER_DAY - 1);
                    filter = {
                        logic: 'or',
                        filters: [
                            {
                                logic: 'and',
                                filters: [
                                    {
                                        field: 'start',
                                        operator: 'gte',
                                        value: start
                                    },
                                    {
                                        field: 'end',
                                        operator: 'gte',
                                        value: start
                                    },
                                    {
                                        field: 'start',
                                        operator: 'lte',
                                        value: end
                                    }
                                ]
                            },
                            {
                                logic: 'and',
                                filters: [
                                    {
                                        field: 'start',
                                        operator: 'lte',
                                        value: new Date(start.getTime() + MS_PER_DAY - 1)
                                    },
                                    {
                                        field: 'end',
                                        operator: 'gte',
                                        value: start
                                    }
                                ]
                            }
                        ]
                    };
                    data = new kendo.data.Query(expandAll(data, start, end, this.reader.timezone)).filter(filter).toArray();
                }
                return data;
            },
            cancelChanges: function (model) {
                if (model && model.isOccurrence()) {
                    this._removeExceptionDate(model);
                }
                DataSource.fn.cancelChanges.call(this, model);
            },
            insert: function (index, model) {
                if (!model) {
                    return;
                }
                if (!(model instanceof SchedulerEvent)) {
                    var eventInfo = model;
                    model = this._createNewModel();
                    model.accept(eventInfo);
                }
                if (!this._pushCreated && model.isRecurrenceHead() || model.recurrenceId) {
                    model = model.recurrenceId ? model : model.toOccurrence();
                    this._addExceptionDate(model);
                }
                return DataSource.fn.insert.call(this, index, model);
            },
            pushCreate: function (items) {
                this._pushCreated = true;
                DataSource.fn.pushCreate.call(this, items);
                this._pushCreated = false;
            },
            remove: function (model) {
                if (model.isRecurrenceHead()) {
                    this._removeExceptions(model);
                } else if (model.isRecurring()) {
                    this._addExceptionDate(model);
                }
                return DataSource.fn.remove.call(this, model);
            },
            _removeExceptions: function (model) {
                var data = this.data().slice(0), item = data.shift(), id = model.id;
                while (item) {
                    if (item.recurrenceId === id) {
                        DataSource.fn.remove.call(this, item);
                    }
                    item = data.shift();
                }
                model.set(RECURRENCE_EXCEPTION, '');
            },
            _removeExceptionDate: function (model) {
                if (model.recurrenceId) {
                    var head = this.get(model.recurrenceId);
                    if (head) {
                        var start = model.start;
                        var replaceRegExp = new RegExp('(\\' + EXCEPTION_SEPARATOR + '?)' + recurrence.toExceptionString(start, this.reader.timezone));
                        var recurrenceException = (head.recurrenceException || '').replace(OLD_EXCEPTION_SEPARATOR_REGEXP, EXCEPTION_SEPARATOR).replace(/\,$/, '');
                        head.set(RECURRENCE_EXCEPTION, recurrenceException.replace(replaceRegExp, ''));
                    }
                }
            },
            _addExceptionDate: function (model) {
                var start = model.start;
                var zone = this.reader.timezone;
                var head = this.get(model.recurrenceId);
                var recurrenceException = (head.recurrenceException || '').replace(OLD_EXCEPTION_SEPARATOR_REGEXP, EXCEPTION_SEPARATOR).replace(/\,$/, '');
                if (!recurrence.isException(recurrenceException, start, zone)) {
                    var newException = recurrence.toExceptionString(start, zone);
                    head.set(RECURRENCE_EXCEPTION, recurrenceException + (recurrenceException && newException ? EXCEPTION_SEPARATOR : '') + newException);
                }
            }
        });
        function expandAll(events, start, end, zone) {
            var length = events.length, data = [], idx = 0;
            for (; idx < length; idx++) {
                data = data.concat(events[idx].expand(start, end, zone));
            }
            return data;
        }
        SchedulerDataSource.create = function (options) {
            if (isArray(options) || options instanceof kendo.data.ObservableArray) {
                options = { data: options };
            }
            var dataSource = options || {}, data = dataSource.data;
            dataSource.data = data;
            if (!(dataSource instanceof SchedulerDataSource) && dataSource instanceof kendo.data.DataSource) {
                throw new Error('Incorrect DataSource type. Only SchedulerDataSource instances are supported');
            }
            return dataSource instanceof SchedulerDataSource ? dataSource : new SchedulerDataSource(dataSource);
        };
        extend(true, kendo.data, {
            SchedulerDataSource: SchedulerDataSource,
            SchedulerDataReader: SchedulerDataReader,
            SchedulerEvent: SchedulerEvent
        });
        var defaultCommands = {
            update: {
                text: 'Save',
                className: 'k-primary k-scheduler-update'
            },
            canceledit: {
                text: 'Cancel',
                className: 'k-scheduler-cancel'
            },
            destroy: {
                text: 'Delete',
                imageClass: 'k-i-close',
                className: 'k-primary k-scheduler-delete',
                iconClass: 'k-icon'
            }
        };
        function trimOptions(options) {
            delete options.name;
            delete options.prefix;
            delete options.remove;
            delete options.edit;
            delete options.add;
            delete options.navigate;
            return options;
        }
        function createValidationAttributes(model, field) {
            var modelField = (model.fields || model)[field];
            var specialRules = [
                'url',
                'email',
                'number',
                'date',
                'boolean'
            ];
            var validation = modelField ? modelField.validation : {};
            var datatype = kendo.attr('type');
            var inArray = $.inArray;
            var ruleName;
            var rule;
            var attr = {};
            for (ruleName in validation) {
                rule = validation[ruleName];
                if (inArray(ruleName, specialRules) >= 0) {
                    attr[datatype] = ruleName;
                } else if (!kendo.isFunction(rule)) {
                    attr[ruleName] = isPlainObject(rule) ? rule.value || ruleName : rule;
                }
                attr[kendo.attr(ruleName + '-msg')] = rule.message;
            }
            return attr;
        }
        function dropDownResourceEditor(resource, model) {
            var attr = createValidationAttributes(model, resource.field);
            return function (container) {
                $(kendo.format('<select data-{0}bind="value:{1}" title="' + model.title + '">', kendo.ns, resource.field)).appendTo(container).attr(attr).kendoDropDownList({
                    dataTextField: resource.dataTextField,
                    dataValueField: resource.dataValueField,
                    dataSource: resource.dataSource,
                    valuePrimitive: resource.valuePrimitive,
                    optionLabel: 'None',
                    template: kendo.format('<span class="k-scheduler-mark" style="background-color:#= data.{0}?{0}:"none" #"></span>#={1}#', resource.dataColorField, resource.dataTextField)
                });
            };
        }
        function descriptionEditor(options) {
            var attr = createValidationAttributes(options.model, options.field);
            return function (container, model) {
                $('<textarea name="description" class="k-textbox" title="' + model.title + '"/>').attr(attr).appendTo(container);
            };
        }
        function multiSelectResourceEditor(resource, model) {
            var attr = createValidationAttributes(model, resource.field);
            return function (container) {
                $(kendo.format('<select data-{0}bind="value:{1}">', kendo.ns, resource.field)).appendTo(container).attr(attr).kendoMultiSelect({
                    dataTextField: resource.dataTextField,
                    dataValueField: resource.dataValueField,
                    dataSource: resource.dataSource,
                    valuePrimitive: resource.valuePrimitive,
                    itemTemplate: kendo.format('<span class="k-scheduler-mark" style="background-color:#= data.{0}?{0}:"none" #"></span>#={1}#', resource.dataColorField, resource.dataTextField),
                    tagTemplate: kendo.format('<span class="k-scheduler-mark" style="background-color:#= data.{0}?{0}:"none" #"></span>#={1}#', resource.dataColorField, resource.dataTextField)
                });
            };
        }
        function multiSelectResourceEditorMobile(resource, model) {
            var attr = createValidationAttributes(model, resource.field);
            return function (container) {
                var options = '';
                var view = resource.dataSource.view();
                for (var idx = 0, length = view.length; idx < length; idx++) {
                    options += kendo.format('<option value="{0}">{1}</option>', kendo.getter(resource.dataValueField)(view[idx]), kendo.getter(resource.dataTextField)(view[idx]));
                }
                $(kendo.format('<select data-{0}bind="value:{1}" multiple="multiple" data-{0}value-primitive="{3}">{2}</select>', kendo.ns, resource.field, options, resource.valuePrimitive)).appendTo(container).attr(attr);
            };
        }
        function moveEventRange(event, distance) {
            var duration = event.end.getTime() - event.start.getTime();
            var start = new Date(event.start.getTime());
            kendo.date.setTime(start, distance);
            var end = new Date(start.getTime());
            kendo.date.setTime(end, duration, true);
            return {
                start: start,
                end: end
            };
        }
        var editors = {
            mobile: {
                dateRange: MOBILEDATERANGEEDITOR,
                timezonePopUp: MOBILETIMEZONEPOPUP,
                timezone: MOBILETIMEZONEEDITOR,
                recurrence: MOBILERECURRENCEEDITOR,
                description: descriptionEditor,
                multipleResources: multiSelectResourceEditorMobile,
                resources: dropDownResourceEditor
            },
            desktop: {
                dateRange: DATERANGEEDITOR,
                timezonePopUp: TIMEZONEPOPUP,
                timezone: TIMEZONEEDITOR,
                recurrence: RECURRENCEEDITOR,
                description: descriptionEditor,
                multipleResources: multiSelectResourceEditor,
                resources: dropDownResourceEditor
            }
        };
        var Editor = kendo.Observable.extend({
            init: function (element, options) {
                kendo.Observable.fn.init.call(this);
                this.element = element;
                this.options = extend(true, {}, this.options, options);
                this.createButton = this.options.createButton;
                this.toggleDateValidationHandler = proxy(this._toggleDateValidation, this);
            },
            _toggleDateValidation: function (e) {
                if (e.field == 'isAllDay') {
                    var container = this.container, isAllDay = this.editable.options.model.isAllDay, bindAttribute = kendo.attr('bind'), element, isDateTimeInput, shouldValidate;
                    container.find('[' + bindAttribute + '*=end],[' + bindAttribute + '*=start]').each(function () {
                        element = $(this);
                        if (valueStartEndBoundRegex.test(element.attr(bindAttribute))) {
                            isDateTimeInput = element.is('[' + kendo.attr('role') + '=datetimepicker],[type*=datetime]');
                            shouldValidate = isAllDay !== isDateTimeInput;
                            element.attr(kendo.attr('validate'), shouldValidate);
                        }
                    });
                }
            },
            fields: function (editors, model) {
                var that = this;
                var messages = that.options.messages;
                var timezone = that.options.timezone;
                var click = function (e) {
                    e.preventDefault();
                    that._initTimezoneEditor(model, this);
                };
                var fields = [
                    {
                        field: 'title',
                        title: messages.editor.title
                    },
                    {
                        field: 'start',
                        title: messages.editor.start,
                        editor: editors.dateRange,
                        timezone: timezone
                    },
                    {
                        field: 'end',
                        title: messages.editor.end,
                        editor: editors.dateRange,
                        timezone: timezone
                    },
                    {
                        field: 'isAllDay',
                        title: messages.editor.allDayEvent
                    }
                ];
                if (kendo.timezone.windows_zones) {
                    fields.push({
                        field: 'timezone',
                        title: messages.editor.timezone,
                        editor: editors.timezonePopUp,
                        click: click,
                        messages: messages.editor,
                        model: model
                    });
                    fields.push({
                        field: 'startTimezone',
                        title: messages.editor.startTimezone,
                        editor: editors.timezone,
                        noTimezone: messages.editor.noTimezone
                    });
                    fields.push({
                        field: 'endTimezone',
                        title: messages.editor.endTimezone,
                        editor: editors.timezone,
                        noTimezone: messages.editor.noTimezone
                    });
                }
                if (!model.recurrenceId) {
                    fields.push({
                        field: 'recurrenceRule',
                        title: messages.editor.repeat,
                        editor: editors.recurrence,
                        timezone: timezone,
                        messages: messages.recurrenceEditor,
                        pane: this.pane
                    });
                }
                if ('description' in model) {
                    fields.push({
                        field: 'description',
                        title: messages.editor.description,
                        editor: editors.description({
                            model: model,
                            field: 'description'
                        })
                    });
                }
                for (var resourceIndex = 0; resourceIndex < this.options.resources.length; resourceIndex++) {
                    var resource = this.options.resources[resourceIndex];
                    fields.push({
                        field: resource.field,
                        title: resource.title,
                        editor: resource.multiple ? editors.multipleResources(resource, model) : editors.resources(resource, model)
                    });
                }
                return fields;
            },
            end: function () {
                return this.editable.end();
            },
            _buildEditTemplate: function (model, fields, editableFields) {
                var messages = this.options.messages;
                var settings = extend({}, kendo.Template, this.options.templateSettings);
                var paramName = settings.paramName;
                var template = this.options.editable.template;
                var html = '';
                if (template) {
                    if (typeof template === STRING) {
                        template = window.unescape(template);
                    }
                    html += kendo.template(template, settings)(model);
                } else {
                    for (var idx = 0, length = fields.length; idx < length; idx++) {
                        var field = fields[idx];
                        if (field.field === 'startTimezone') {
                            html += '<div class="k-popup-edit-form k-scheduler-edit-form k-scheduler-timezones" style="display:none">';
                            html += '<div class="k-edit-form-container">';
                            html += '<div class="k-edit-label"></div>';
                            html += '<div class="k-edit-field"><label class="k-check"><input class="k-timezone-toggle" type="checkbox" />' + messages.editor.separateTimezones + '</label></div>';
                        }
                        html += '<div class="k-edit-label"><label for="' + field.field + '">' + (field.title || field.field || '') + '</label></div>';
                        if (!model.editable || model.editable(field.field)) {
                            editableFields.push(field);
                            html += '<div ' + kendo.attr('container-for') + '="' + field.field + '" class="k-edit-field"></div>';
                        } else {
                            var tmpl = '#:';
                            if (field.field) {
                                field = kendo.expr(field.field, paramName);
                                tmpl += field + '==null?\'\':' + field;
                            } else {
                                tmpl += '\'\'';
                            }
                            tmpl += '#';
                            tmpl = kendo.template(tmpl, settings);
                            html += '<div class="k-edit-field">' + tmpl(model) + '</div>';
                        }
                        if (field.field === 'endTimezone') {
                            html += this._createEndTimezoneButton();
                        }
                    }
                }
                return html;
            },
            _createEndTimezoneButton: function () {
                return '</div></div>';
            },
            _revertTimezones: function (model) {
                model.set('startTimezone', this._startTimezone);
                model.set('endTimezone', this._endTimezone);
                delete this._startTimezone;
                delete this._endTimezone;
            }
        });
        var MobileEditor = Editor.extend({
            init: function () {
                Editor.fn.init.apply(this, arguments);
                this.pane = kendo.mobile.ui.Pane.wrap(this.element);
                this.pane.element.parent().css('height', this.options.height);
                this.view = this.pane.view();
                this._actionSheetButtonTemplate = kendo.template('<li><a #=attr# class="k-button #=className#" href="\\#">#:text#</a></li>');
                this._actionSheetPopupOptions = $(document.documentElement).hasClass('km-root') ? { modal: false } : {
                    align: 'bottom center',
                    position: 'bottom center',
                    effect: 'slideIn:up'
                };
            },
            options: {
                animations: {
                    left: 'slide',
                    right: 'slide:right'
                }
            },
            destroy: function () {
                this.close();
                this.unbind();
                this.pane.destroy();
            },
            _initTimezoneEditor: function (model) {
                var that = this;
                var pane = that.pane;
                var messages = that.options.messages;
                var timezoneView = that.timezoneView;
                var container = that.container.find('.k-scheduler-timezones');
                var checkbox = container.find('.k-timezone-toggle');
                var endTimezoneRow = container.find('.k-edit-label:last').add(container.find('.k-edit-field:last'));
                var startTimezoneChange = function (e) {
                    if (e.field === 'startTimezone') {
                        var value = model.startTimezone;
                        checkbox.prop('disabled', !value);
                        if (!value) {
                            endTimezoneRow.hide();
                            model.set('endTimezone', '');
                            checkbox.prop('checked', false);
                        }
                    }
                };
                that._startTimezone = model.startTimezone || '';
                that._endTimezone = model.endTimezone || '';
                if (!timezoneView) {
                    var html = '<div data-role="view" class="k-popup-edit-form k-scheduler-edit-form k-mobile-list">' + '<div data-role="header" class="k-header"><a href="#" class="k-button k-scheduler-cancel">' + messages.cancel + '</a>' + messages.editor.timezoneTitle + '<a href="#" class="k-button k-scheduler-update">' + messages.save + '</a></div></div>';
                    this.timezoneView = timezoneView = pane.append(html);
                    timezoneView.contentElement().append(container.show());
                    timezoneView.element.on(CLICK + NS, '.k-scheduler-cancel, .k-scheduler-update', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        if ($(this).hasClass('k-scheduler-cancel')) {
                            that._revertTimezones(model);
                        }
                        model.unbind('change', startTimezoneChange);
                        var editView = pane.element.find('#edit').data('kendoMobileView');
                        var text = timezoneButtonText(model, messages.editor.noTimezone);
                        editView.contentElement().find('.k-timezone-button').text(text);
                        pane.navigate(editView, that.options.animations.right);
                    });
                    checkbox.click(function () {
                        endTimezoneRow.toggle(checkbox.prop('checked'));
                        model.set('endTimezone', '');
                    });
                    model.bind('change', startTimezoneChange);
                }
                checkbox.prop('checked', model.endTimezone).prop('disabled', !model.startTimezone);
                if (model.endTimezone) {
                    endTimezoneRow.show();
                } else {
                    endTimezoneRow.hide();
                }
                pane.navigate(timezoneView, that.options.animations.left);
            },
            _createActionSheetButton: function (options) {
                options.template = this._actionSheetButtonTemplate;
                return this.createButton(options);
            },
            showDialog: function (options) {
                var type = '';
                var html = '<ul><li class="km-actionsheet-title">' + options.title + '</li>';
                var target = this.element.find('.k-event[' + kendo.attr('uid') + '=\'' + options.model.uid + '\']');
                if (this.container) {
                    target = this.container.find('.k-scheduler-delete');
                    if (target[0]) {
                        type = 'phone';
                    }
                }
                for (var buttonIndex = 0; buttonIndex < options.buttons.length; buttonIndex++) {
                    html += this._createActionSheetButton(options.buttons[buttonIndex]);
                }
                html += '</ul>';
                var actionSheet = $(html).appendTo(this.pane.view().element).kendoMobileActionSheet({
                    type: type,
                    cancel: this.options.messages.cancel,
                    cancelTemplate: '<li class="km-actionsheet-cancel"><a class="k-button" href="\\#">#:cancel#</a></li>',
                    close: function () {
                        this.destroy();
                    },
                    command: function (e) {
                        var buttonIndex = actionSheet.element.find('li:not(.km-actionsheet-cancel) > .k-button').index($(e.currentTarget));
                        if (buttonIndex > -1) {
                            actionSheet.close();
                            options.buttons[buttonIndex].click();
                        }
                    },
                    popup: this._actionSheetPopupOptions
                }).data('kendoMobileActionSheet');
                actionSheet.open(target);
            },
            editEvent: function (model) {
                var pane = this.pane;
                var html = '';
                var messages = this.options.messages;
                var updateText = messages.save;
                var removeText = messages.destroy;
                var cancelText = messages.cancel;
                var titleText = messages.editor.editorTitle;
                html += '<div data-role="view" class="k-popup-edit-form k-scheduler-edit-form k-mobile-list" id="edit" ' + kendo.attr('uid') + '="' + model.uid + '">' + '<div data-role="header" class="k-header"><a href="#" class="k-button k-scheduler-cancel">' + cancelText + '</a>' + titleText + '<a href="#" class="k-button k-scheduler-update">' + updateText + '</a></div>';
                var fields = this.fields(editors.mobile, model);
                var that = this;
                var editableFields = [];
                html += this._buildEditTemplate(model, fields, editableFields);
                if (!model.isNew() && this.options.editable && this.options.editable.destroy !== false) {
                    html += '<div class="k-edit-buttons"><a href="#" class="k-scheduler-delete k-button">' + removeText + '</a></div>';
                }
                html += '</div>';
                var view = pane.append(html);
                var container = this.container = view.element;
                this.editable = container.kendoEditable({
                    fields: editableFields,
                    model: model,
                    clearContainer: false,
                    target: that.options.target,
                    validateOnBlur: true
                }).data('kendoEditable');
                container.find('input[type=checkbox],input[type=radio]').parent('.k-edit-field').addClass('k-check').prev('.k-edit-label').addClass('k-check').click(function () {
                    $(this).next().children('input').click();
                });
                if (!this.trigger('edit', {
                        container: container,
                        model: model
                    })) {
                    container.on(CLICK + NS, 'a.k-scheduler-edit, a.k-scheduler-cancel, a.k-scheduler-update, a.k-scheduler-delete', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        var button = $(this);
                        if (!button.hasClass('k-scheduler-edit')) {
                            var name = 'cancel';
                            if (button.hasClass('k-scheduler-update')) {
                                name = 'save';
                            } else if (button.hasClass('k-scheduler-delete')) {
                                name = 'remove';
                            }
                            that.trigger(name, {
                                container: container,
                                model: model
                            });
                        } else {
                            pane.navigate('#edit', that.options.animations.right);
                        }
                    });
                    pane.navigate(view, that.options.animations.left);
                    model.bind('change', that.toggleDateValidationHandler);
                } else {
                    this.trigger('cancel', {
                        container: container,
                        model: model
                    });
                }
                return this.editable;
            },
            _views: function () {
                return this.pane.element.find(kendo.roleSelector('view')).not(this.view.element);
            },
            close: function () {
                if (this.container) {
                    this.pane.navigate('', this.options.animations.right);
                    var views = this._views();
                    var view;
                    for (var idx = 0, length = views.length; idx < length; idx++) {
                        view = views.eq(idx).data('kendoMobileView');
                        if (view) {
                            view.purge();
                        }
                    }
                    views.remove();
                    this.container = null;
                    if (this.editable) {
                        this.editable.options.model.unbind('change', this.toggleDateValidationHandler);
                        this.editable.destroy();
                        this.editable = null;
                    }
                    this.timezoneView = null;
                }
            }
        });
        var PopupEditor = Editor.extend({
            destroy: function () {
                this.close();
                this.unbind();
            },
            editEvent: function (model) {
                var that = this;
                var editable = that.options.editable;
                var html = '<div ' + kendo.attr('uid') + '="' + model.uid + '" class="k-popup-edit-form k-scheduler-edit-form"><div class="k-edit-form-container">';
                var messages = that.options.messages;
                var updateText = messages.save;
                var cancelText = messages.cancel;
                var deleteText = messages.destroy;
                var fields = this.fields(editors.desktop, model);
                var editableFields = [];
                html += this._buildEditTemplate(model, fields, editableFields);
                var attr;
                var options = isPlainObject(editable) ? editable.window : {};
                html += '<div class="k-edit-buttons k-state-default">';
                html += this.createButton({
                    name: 'update',
                    text: updateText,
                    attr: attr
                }) + this.createButton({
                    name: 'canceledit',
                    text: cancelText,
                    attr: attr
                });
                if (!model.isNew() && editable.destroy !== false) {
                    html += this.createButton({
                        name: 'delete',
                        text: deleteText,
                        attr: attr
                    });
                }
                html += '</div></div></div>';
                var container = this.container = $(html).appendTo(that.element).eq(0).kendoWindow(extend({
                    modal: true,
                    resizable: false,
                    draggable: true,
                    title: messages.editor.editorTitle,
                    visible: false,
                    close: function (e) {
                        if (e.userTriggered) {
                            if (that.trigger(CANCEL, {
                                    container: container,
                                    model: model
                                })) {
                                e.preventDefault();
                            }
                        }
                    }
                }, options));
                that.editable = container.kendoEditable({
                    fields: editableFields,
                    model: model,
                    clearContainer: false,
                    validateOnBlur: true,
                    target: that.options.target
                }).data('kendoEditable');
                if (!that.trigger(EDIT, {
                        container: container,
                        model: model
                    })) {
                    container.data('kendoWindow').center().open();
                    container.on(CLICK + NS, 'a.k-scheduler-cancel', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger(CANCEL, {
                            container: container,
                            model: model
                        });
                    });
                    container.on(CLICK + NS, 'a.k-scheduler-update', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger('save', {
                            container: container,
                            model: model
                        });
                    });
                    container.on(CLICK + NS, 'a.k-scheduler-delete', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger(REMOVE, {
                            container: container,
                            model: model
                        });
                    });
                    kendo.cycleForm(container);
                    model.bind('change', that.toggleDateValidationHandler);
                } else {
                    that.trigger(CANCEL, {
                        container: container,
                        model: model
                    });
                }
                return that.editable;
            },
            close: function () {
                var that = this;
                var destroy = function () {
                    if (that.editable) {
                        that.editable.options.model.unbind('change', that.toggleDateValidationHandler);
                        that.editable.destroy();
                        that.editable = null;
                        that.container = null;
                    }
                    if (that.popup) {
                        that.popup.destroy();
                        that.popup = null;
                    }
                };
                if (that.editable) {
                    if (that._timezonePopup && that._timezonePopup.data('kendoWindow')) {
                        that._timezonePopup.data('kendoWindow').destroy();
                        that._timezonePopup = null;
                    }
                    if (that.container.is(':visible')) {
                        that.container.data('kendoWindow').bind('deactivate', destroy).close();
                    } else {
                        destroy();
                    }
                } else {
                    destroy();
                }
            },
            _createEndTimezoneButton: function () {
                var messages = this.options.messages;
                var html = '';
                html += '<div class="k-edit-buttons k-state-default">';
                html += this.createButton({
                    name: 'savetimezone',
                    text: messages.save
                }) + this.createButton({
                    name: 'canceltimezone',
                    text: messages.cancel
                });
                html += '</div></div></div>';
                return html;
            },
            showDialog: function (options) {
                var html = kendo.format('<div class=\'k-popup-edit-form\'><div class=\'k-edit-form-container\'><p class=\'k-popup-message\'>{0}</p>', options.text);
                html += '<div class="k-edit-buttons k-state-default">';
                for (var buttonIndex = 0; buttonIndex < options.buttons.length; buttonIndex++) {
                    html += this.createButton(options.buttons[buttonIndex]);
                }
                html += '</div></div></div>';
                var wrapper = this.element;
                if (this.popup) {
                    this.popup.destroy();
                }
                var popup = this.popup = $(html).appendTo(wrapper).eq(0).on('click', '.k-button', function (e) {
                    e.preventDefault();
                    popup.close();
                    var buttonIndex = $(e.currentTarget).index();
                    options.buttons[buttonIndex].click();
                }).kendoWindow({
                    modal: true,
                    resizable: false,
                    draggable: false,
                    title: options.title,
                    visible: false,
                    close: function () {
                        this.destroy();
                        wrapper.focus();
                    }
                }).getKendoWindow();
                popup.center().open();
            },
            _initTimezoneEditor: function (model, activator) {
                var that = this;
                var container = that.container.find('.k-scheduler-timezones');
                var checkbox = container.find('.k-timezone-toggle');
                var endTimezoneRow = container.find('.k-edit-label:last').add(container.find('.k-edit-field:last'));
                var saveButton = container.find('.k-scheduler-savetimezone');
                var cancelButton = container.find('.k-scheduler-canceltimezone');
                var timezonePopup = that._timezonePopup;
                var startTimezoneChange = function (e) {
                    if (e.field === 'startTimezone') {
                        var value = model.startTimezone;
                        checkbox.prop('disabled', !value);
                        if (!value) {
                            endTimezoneRow.hide();
                            model.set('endTimezone', '');
                            checkbox.prop('checked', false);
                        }
                    }
                };
                var wnd;
                that._startTimezone = model.startTimezone;
                that._endTimezone = model.endTimezone;
                if (!timezonePopup) {
                    that._timezonePopup = timezonePopup = container.kendoWindow({
                        modal: true,
                        resizable: false,
                        draggable: true,
                        title: that.options.messages.editor.timezoneEditorTitle,
                        visible: false,
                        close: function (e) {
                            model.unbind('change', startTimezoneChange);
                            if (e.userTriggered) {
                                that._revertTimezones(model);
                            }
                            if (activator) {
                                activator.focus();
                            }
                        }
                    });
                    checkbox.click(function () {
                        endTimezoneRow.toggle(checkbox.prop('checked'));
                        model.set('endTimezone', '');
                    });
                    saveButton.click(function (e) {
                        e.preventDefault();
                        wnd.close();
                    });
                    cancelButton.click(function (e) {
                        e.preventDefault();
                        that._revertTimezones(model);
                        wnd.close();
                    });
                    model.bind('change', startTimezoneChange);
                }
                checkbox.prop('checked', model.endTimezone).prop('disabled', !model.startTimezone);
                if (model.endTimezone) {
                    endTimezoneRow.show();
                } else {
                    endTimezoneRow.hide();
                }
                wnd = timezonePopup.data('kendoWindow');
                wnd.center().open();
            }
        });
        var Scheduler = DataBoundWidget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                if (!that.options.views || !that.options.views.length) {
                    that.options.views = [
                        'day',
                        'week'
                    ];
                }
                that.resources = [];
                that._initModel();
                that._wrapper();
                that._views();
                that._toolbar();
                that._dataSource();
                that._resources();
                that._resizeHandler = function () {
                    that.resize();
                };
                that.wrapper.on('mousedown' + NS + ' selectstart' + NS, function (e) {
                    if (!$(e.target).is(':kendoFocusable')) {
                        e.preventDefault();
                    }
                });
                if (that.options.editable && that.options.editable.resize !== false) {
                    that._resizable();
                }
                that._movable();
                that._bindResize();
                if (that.options.messages && that.options.messages.recurrence) {
                    recurrence.options = that.options.messages.recurrence;
                }
                that._selectable();
                that._ariaId = kendo.guid();
                that._createEditor();
            },
            _bindResize: function () {
                $(window).on('resize' + NS, this._resizeHandler);
            },
            _unbindResize: function () {
                $(window).off('resize' + NS, this._resizeHandler);
            },
            dataItems: function () {
                var that = this;
                var items = that.items();
                var events = that._data;
                var eventsUids = $.map(items, function (item) {
                    return $(item).attr('data-uid');
                });
                var i;
                var key;
                var dict = {};
                var eventsUidsLength = eventsUids.length;
                for (i = 0; i < eventsUidsLength; i++) {
                    dict[eventsUids[i]] = null;
                }
                var eventsCount = events.length;
                for (i = 0; i < eventsCount; i++) {
                    var event = events[i];
                    if (dict[event.uid] !== undefined) {
                        dict[event.uid] = event;
                    }
                }
                var sortedData = [];
                for (key in dict) {
                    sortedData.push(dict[key]);
                }
                return sortedData;
            },
            _isMobile: function () {
                var options = this.options;
                return options.mobile === true && kendo.support.mobileOS || options.mobile === 'phone' || options.mobile === 'tablet';
            },
            _isMobilePhoneView: function () {
                var options = this.options;
                return options.mobile === true && kendo.support.mobileOS && !kendo.support.mobileOS.tablet || options.mobile === 'phone';
            },
            _groupsByResource: function (resources, groupIndex, groupsArray, parentFieldValue, parentField) {
                if (!groupsArray) {
                    groupsArray = [];
                }
                var resource = resources[0];
                if (resource) {
                    var group;
                    var data = resource.dataSource.view();
                    var prevIndex = 0;
                    for (var dataIndex = 0; dataIndex < data.length; dataIndex++) {
                        var fieldValue = kendo.getter(resource.dataValueField)(data[dataIndex]);
                        var currentGroupIndex = groupIndex + prevIndex + dataIndex;
                        group = this._groupsByResource(resources.slice(1), currentGroupIndex, groupsArray, fieldValue, resource.field);
                        group[resource.field] = fieldValue;
                        prevIndex = group.groupIndex;
                        if (parentField && parentFieldValue) {
                            group[parentField] = parentFieldValue;
                        }
                        if (resources.length === 1) {
                            group.groupIndex = groupIndex + dataIndex;
                            groupsArray.push(group);
                        }
                    }
                    return group;
                } else {
                    return {};
                }
            },
            data: function () {
                return this._data;
            },
            select: function (options) {
                var that = this;
                var view = that.view();
                var selection = that._selection;
                var groups = view.groups;
                var selectedGroups;
                if (options === undefined) {
                    var selectedEvents;
                    var slots = view._selectedSlots;
                    if (!selection) {
                        return [];
                    }
                    if (selection && selection.events) {
                        selectedEvents = that._selectedEvents();
                    }
                    return {
                        start: selection.start,
                        end: selection.end,
                        events: selectedEvents,
                        slots: slots,
                        resources: view._resourceBySlot(selection)
                    };
                }
                if (!options) {
                    that._selection = null;
                    that._old = null;
                    view.clearSelection();
                    return;
                }
                if ($.isArray(options)) {
                    options = { events: options.splice(0) };
                }
                if (options.resources) {
                    var fieldName;
                    var filters = [];
                    var groupsByResource = [];
                    if (view.groupedResources) {
                        that._groupsByResource(view.groupedResources, 0, groupsByResource);
                    }
                    for (fieldName in options.resources) {
                        filters.push({
                            field: fieldName,
                            operator: 'eq',
                            value: options.resources[fieldName]
                        });
                    }
                    selectedGroups = new kendo.data.Query(groupsByResource).filter(filters).toArray();
                }
                if (options.events && options.events.length) {
                    that._selectEvents(options.events, selectedGroups);
                    that._select();
                    return;
                }
                if (groups && (options.start && options.end)) {
                    var rangeStart = getDate(view._startDate);
                    var rangeEnd = kendo.date.addDays(getDate(view._endDate), 1);
                    var group;
                    var ranges;
                    if (options.start < rangeEnd && rangeStart <= options.end) {
                        if (selectedGroups && selectedGroups.length) {
                            group = groups[selectedGroups[0].groupIndex];
                        } else {
                            group = groups[0];
                        }
                        ranges = group.ranges(options.start, options.end, options.isAllDay, false);
                        if (ranges.length) {
                            that._selection = {
                                start: kendo.timezone.toLocalDate(ranges[0].start.start),
                                end: kendo.timezone.toLocalDate(ranges[ranges.length - 1].end.end),
                                groupIndex: ranges[0].start.groupIndex,
                                index: ranges[0].start.index,
                                isAllDay: ranges[0].start.isDaySlot,
                                events: []
                            };
                            that._select();
                        }
                    }
                }
            },
            _selectEvents: function (eventsUids, selectedGroups) {
                var that = this;
                var idx;
                var view = that.view();
                var groups = view.groups;
                var eventsLength = eventsUids.length;
                var isGrouped = selectedGroups && selectedGroups.length;
                for (idx = 0; idx < eventsLength; idx++) {
                    if (groups && isGrouped) {
                        var currentGroup = groups[selectedGroups[0].groupIndex];
                        var events = [];
                        var timeSlotCollectionCount = currentGroup.timeSlotCollectionCount();
                        var daySlotCollectionCount = currentGroup.daySlotCollectionCount();
                        for (var collIdx = 0; collIdx < timeSlotCollectionCount; collIdx++) {
                            events = events.concat(currentGroup.getTimeSlotCollection(collIdx).events());
                        }
                        for (var dayCollIdx = 0; dayCollIdx < daySlotCollectionCount; dayCollIdx++) {
                            events = events.concat(currentGroup.getDaySlotCollection(dayCollIdx).events());
                        }
                        events = new kendo.data.Query(events).filter({
                            field: 'element[0].getAttribute(\'data-uid\')',
                            operator: 'eq',
                            value: eventsUids[idx]
                        }).toArray();
                        if (events[0]) {
                            that._createSelection(events[0].element);
                        }
                    } else {
                        var element = view.element.find(kendo.format('.k-event[data-uid={0}], .k-task[data-uid={0}]', eventsUids[idx]));
                        if (element.length) {
                            that._createSelection(element[0]);
                        }
                    }
                }
            },
            _selectable: function () {
                var that = this, wrapper = that.wrapper, selectEvent = kendo.support.mobileOS ? 'touchend' : 'mousedown';
                if (!that.options.selectable) {
                    return;
                }
                that._tabindex();
                wrapper.on(selectEvent + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td, .k-event', function (e) {
                    var which = e.which;
                    var button = e.button;
                    var browser = kendo.support.browser;
                    var isRight = which && which === 3 || button && button == 2;
                    if (kendo.support.mobileOS && e.isDefaultPrevented()) {
                        return;
                    }
                    if (!isRight) {
                        that._createSelection(e.currentTarget);
                    }
                    wrapper.focus();
                    if (browser.msie && browser.version < 9) {
                        setTimeout(function () {
                            wrapper.focus();
                        });
                    }
                });
                var mouseMoveHandler = $.proxy(that._mouseMove, that);
                wrapper.on('mousedown' + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td', function (e) {
                    var which = e.which;
                    var button = e.button;
                    var isRight = which && which === 3 || button && button == 2;
                    if (!isRight) {
                        wrapper.on('mousemove' + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td', mouseMoveHandler);
                    }
                });
                wrapper.on('mouseup' + NS + ' mouseleave' + NS, function () {
                    wrapper.off('mousemove' + NS, '.k-scheduler-header-all-day td, .k-scheduler-content td', mouseMoveHandler);
                });
                wrapper.on('focus' + NS, function () {
                    if (!that._selection) {
                        that._selectFirstSlot();
                    }
                    that._select();
                });
                wrapper.on('focusout' + NS, function () {
                    that._ctrlKey = that._shiftKey = false;
                });
                wrapper.on('keydown' + NS, proxy(that._keydown, that));
                wrapper.on('keyup' + NS, function (e) {
                    that._ctrlKey = e.ctrlKey;
                    that._shiftKey = e.shiftKey;
                });
            },
            _selectFirstSlot: function () {
                this._createSelection(this.wrapper.find('.k-scheduler-content').find('td:first'));
            },
            _select: function () {
                var that = this;
                var view = that.view();
                var wrapper = that.wrapper;
                var current = view.current();
                var selection = that._selection;
                if (!selection) {
                    return;
                }
                if (current) {
                    current.removeAttribute('id');
                    current.removeAttribute('aria-label');
                    wrapper.removeAttr('aria-activedescendant');
                }
                view.select(selection);
                current = view.current();
                if (current && that._old !== current) {
                    var currentUid = $(current).data('uid');
                    if (that._old && currentUid && currentUid === $(that._old).data('uid')) {
                        return;
                    }
                    var labelFormat;
                    var data = selection;
                    var events = that._selectedEvents();
                    var slots = view._selectedSlots;
                    if (events[0]) {
                        data = events[0] || selection;
                        labelFormat = kendo.format(that.options.messages.ariaEventLabel, data.title, data.start, data.start);
                    } else {
                        labelFormat = kendo.format(that.options.messages.ariaSlotLabel, data.start, data.end);
                    }
                    current.setAttribute('id', that._ariaId);
                    current.setAttribute('aria-label', labelFormat);
                    wrapper.attr('aria-activedescendant', that._ariaId);
                    that._old = current;
                    that.trigger('change', {
                        start: selection.start,
                        end: selection.end,
                        events: events,
                        slots: slots,
                        resources: view._resourceBySlot(selection)
                    });
                }
            },
            _selectedEvents: function () {
                var uids = this._selection.events;
                var length = uids.length;
                var idx = 0;
                var event;
                var events = [];
                for (; idx < length; idx++) {
                    event = this.occurrenceByUid(uids[idx]);
                    if (event) {
                        events.push(event);
                    }
                }
                return events;
            },
            _mouseMove: function (e) {
                var that = this;
                clearTimeout(that._moveTimer);
                that._moveTimer = setTimeout(function () {
                    var view = that.view();
                    var selection = that._selection;
                    if (selection) {
                        var slot = view.selectionByElement($(e.currentTarget));
                        if (slot && selection.groupIndex === slot.groupIndex) {
                            var startDate = slot.startDate();
                            var endDate = slot.endDate();
                            if (startDate >= selection.end) {
                                selection.backward = false;
                            } else if (endDate <= selection.start) {
                                selection.backward = true;
                            }
                            if (selection.backward) {
                                selection.start = startDate;
                            } else {
                                selection.end = endDate;
                            }
                            that._select();
                        }
                    }
                }, 5);
            },
            _viewByIndex: function (index) {
                var view, views = this.views;
                for (view in views) {
                    if (!index) {
                        return view;
                    }
                    index--;
                }
            },
            _keydown: function (e) {
                var that = this, key = e.keyCode, view = that.view(), editable = view.options.editable, selection = that._selection, shiftKey = e.shiftKey;
                that._ctrlKey = e.ctrlKey;
                that._shiftKey = e.shiftKey;
                if (!selection) {
                    that._selectFirstSlot();
                    that._select();
                    return;
                }
                if (key === keys.TAB) {
                    if (view.moveToEvent(selection, shiftKey)) {
                        that._select();
                        e.preventDefault();
                    }
                } else if (editable && key === keys.ENTER) {
                    if (selection.events.length) {
                        if (editable.update !== false) {
                            that.editEvent(selection.events[0]);
                        }
                    } else if (editable.create !== false) {
                        if (selection.isAllDay) {
                            selection = $.extend({}, selection, { end: kendo.date.addDays(selection.end, -1) });
                        }
                        that.addEvent(extend({}, selection, view._resourceBySlot(selection)));
                    }
                } else if (key === keys.DELETE && editable !== false && editable.destroy !== false) {
                    that.removeEvent(selection.events[0]);
                } else if (key >= 49 && key <= 57) {
                    that.view(that._viewByIndex(key - 49));
                } else if (view.move(selection, key, shiftKey)) {
                    if (view.inRange(selection)) {
                        that._select();
                    } else {
                        that.date(selection.start);
                    }
                    e.preventDefault();
                }
                that._adjustSelectedDate();
            },
            _createSelection: function (item) {
                var uid, slot, selection;
                if (!this._selection || !this._ctrlKey && !this._shiftKey) {
                    this._selection = {
                        events: [],
                        groupIndex: 0
                    };
                }
                item = $(item);
                selection = this._selection;
                if (item.is('.k-event')) {
                    uid = item.attr(kendo.attr('uid'));
                }
                slot = this.view().selectionByElement(item);
                if (slot) {
                    selection.groupIndex = slot.groupIndex || 0;
                }
                if (uid) {
                    slot = getOccurrenceByUid(this._data, uid);
                }
                if (slot && slot.uid) {
                    uid = [slot.uid];
                }
                this._updateSelection(slot, uid);
                this._adjustSelectedDate();
            },
            _updateSelection: function (dataItem, events, groupIndex) {
                var selection = this._selection;
                if (dataItem && selection) {
                    var view = this.view();
                    if (dataItem.uid) {
                        dataItem = view._updateEventForSelection(dataItem);
                    }
                    if (this._shiftKey && selection.start && selection.end) {
                        var backward = dataItem.end < selection.end;
                        selection.end = dataItem.endDate ? dataItem.endDate() : dataItem.end;
                        if (backward && view._timeSlotInterval) {
                            kendo.date.setTime(selection.end, -view._timeSlotInterval());
                        }
                    } else {
                        selection.start = dataItem.startDate ? dataItem.startDate() : dataItem.start;
                        selection.end = dataItem.endDate ? dataItem.endDate() : dataItem.end;
                    }
                    if ('isDaySlot' in dataItem) {
                        selection.isAllDay = dataItem.isDaySlot;
                    } else {
                        selection.isAllDay = dataItem.isAllDay;
                    }
                    if (groupIndex !== null && groupIndex !== undefined) {
                        selection.groupIndex = groupIndex;
                    }
                    selection.index = dataItem.index;
                    if (this._ctrlKey) {
                        selection.events = selection.events.concat(events || []);
                    } else {
                        selection.events = events || [];
                    }
                }
            },
            options: {
                name: 'Scheduler',
                date: TODAY,
                editable: true,
                autoBind: true,
                snap: true,
                mobile: false,
                timezone: '',
                allDaySlot: true,
                min: new Date(1900, 0, 1),
                max: new Date(2099, 11, 31),
                toolbar: null,
                footer: {},
                messages: {
                    today: 'Today',
                    pdf: 'Export to PDF',
                    save: 'Save',
                    cancel: 'Cancel',
                    destroy: 'Delete',
                    deleteWindowTitle: 'Delete event',
                    next: 'Next',
                    previous: 'Previous',
                    ariaSlotLabel: 'Selected from {0:t} to {1:t}',
                    ariaEventLabel: '{0} on {1:D} at {2:t}',
                    views: {
                        day: 'Day',
                        week: 'Week',
                        workWeek: 'Work Week',
                        agenda: 'Agenda',
                        month: 'Month',
                        timeline: 'Timeline',
                        timelineWeek: 'Timeline Week',
                        timelineWorkWeek: 'Timeline Work Week',
                        timelineMonth: 'Timeline Month'
                    },
                    recurrenceMessages: {
                        deleteWindowTitle: 'Delete Recurring Item',
                        deleteWindowOccurrence: 'Delete current occurrence',
                        deleteWindowSeries: 'Delete the series',
                        editWindowTitle: 'Edit Recurring Item',
                        editWindowOccurrence: 'Edit current occurrence',
                        editWindowSeries: 'Edit the series'
                    },
                    editable: { confirmation: DELETECONFIRM },
                    editor: {
                        title: 'Title',
                        start: 'Start',
                        end: 'End',
                        allDayEvent: 'All day event',
                        description: 'Description',
                        repeat: 'Repeat',
                        timezone: 'Timezone',
                        startTimezone: 'Start timezone',
                        endTimezone: 'End timezone',
                        separateTimezones: 'Use separate start and end time zones',
                        timezoneEditorTitle: 'Timezones',
                        timezoneEditorButton: 'Time zone',
                        timezoneTitle: 'Time zones',
                        noTimezone: 'No timezone',
                        editorTitle: 'Event'
                    }
                },
                height: null,
                width: null,
                resources: [],
                group: {
                    resources: [],
                    orientation: 'horizontal'
                },
                views: [],
                selectable: false
            },
            events: [
                REMOVE,
                EDIT,
                CANCEL,
                SAVE,
                'add',
                'dataBinding',
                'dataBound',
                'moveStart',
                'move',
                'moveEnd',
                'resizeStart',
                'resize',
                'resizeEnd',
                'navigate',
                'change'
            ],
            destroy: function () {
                var that = this, element;
                Widget.fn.destroy.call(that);
                if (that.dataSource) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler);
                    that.dataSource.unbind('progress', that._progressHandler);
                    that.dataSource.unbind('error', that._errorHandler);
                }
                if (that.calendar) {
                    that.calendar.destroy();
                    that.popup.destroy();
                }
                if (that.view()) {
                    that.view().destroy();
                }
                if (that._editor) {
                    that._editor.destroy();
                }
                if (this._moveDraggable) {
                    this._moveDraggable.destroy();
                }
                if (this._resizeDraggable) {
                    this._resizeDraggable.destroy();
                }
                element = that.element.add(that.wrapper).add(that.toolbar).add(that.popup);
                element.off(NS);
                clearTimeout(that._moveTimer);
                that._model = null;
                that.toolbar = null;
                that.element = null;
                $(window).off('resize' + NS, that._resizeHandler);
                kendo.destroy(that.wrapper);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.options.autoBind) {
                    dataSource.fetch();
                }
            },
            items: function () {
                var content = this.wrapper.find('.k-scheduler-content');
                var view = this.view();
                if (view && view.options.name === 'agenda') {
                    return content.find('.k-task');
                } else {
                    return content.find('.k-event').add(this.wrapper.find('.k-scheduler-header-wrap').find('.k-scheduler-header-all-day').siblings());
                }
            },
            _movable: function () {
                var startSlot;
                var endSlot;
                var startTime;
                var endTime;
                var event;
                var clonedEvent;
                var that = this;
                var originSlot;
                var distance = 0;
                var isMobile = that._isMobile();
                var movable = that.options.editable && that.options.editable.move !== false;
                var resizable = that.options.editable && that.options.editable.resize !== false;
                if (movable || resizable && isMobile) {
                    if (isMobile && kendo.support.mobileOS.android) {
                        distance = 5;
                    }
                    that._moveDraggable = new kendo.ui.Draggable(that.element, {
                        distance: distance,
                        filter: '.k-event',
                        ignore: '.k-resize-handle',
                        holdToDrag: isMobile,
                        autoScroll: true
                    });
                    if (movable) {
                        that._moveDraggable.bind('dragstart', function (e) {
                            var view = that.view();
                            var eventElement = e.currentTarget;
                            if (!view.options.editable || view.options.editable.move === false) {
                                e.preventDefault();
                                return;
                            }
                            if (isMobile && !eventElement.hasClass('k-event-active')) {
                                that.element.find('.k-event-active').removeClass('k-event-active');
                                e.preventDefault();
                                return;
                            }
                            event = that.occurrenceByUid(eventElement.attr(kendo.attr('uid')));
                            clonedEvent = event.clone();
                            clonedEvent.update(view._eventOptionsForMove(clonedEvent));
                            startSlot = view._slotByPosition(e.x.startLocation, e.y.startLocation);
                            startTime = startSlot.startOffset(e.x.startLocation, e.y.startLocation, that.options.snap);
                            endSlot = startSlot;
                            originSlot = startSlot;
                            if (!startSlot || that.trigger('moveStart', { event: event })) {
                                e.preventDefault();
                            }
                        }).bind('drag', function (e) {
                            var view = that.view();
                            var slot = view._slotByPosition(e.x.location, e.y.location);
                            var distance;
                            var range;
                            if (!slot) {
                                return;
                            }
                            endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                            if (slot.isDaySlot !== startSlot.isDaySlot) {
                                startSlot = view._slotByPosition(e.x.location, e.y.location);
                                startTime = startSlot.startOffset(e.x.location, e.y.location, that.options.snap);
                                distance = endTime - startTime;
                                clonedEvent.isAllDay = slot.isDaySlot;
                                clonedEvent.start = kendo.timezone.toLocalDate(startTime);
                                clonedEvent.end = kendo.timezone.toLocalDate(endTime);
                                view._updateMoveHint(clonedEvent, slot.groupIndex, distance);
                                range = {
                                    start: clonedEvent.start,
                                    end: clonedEvent.end
                                };
                            } else {
                                distance = endTime - startTime;
                                view._updateMoveHint(clonedEvent, slot.groupIndex, distance);
                                range = moveEventRange(clonedEvent, distance);
                            }
                            if (!that.trigger('move', {
                                    event: event,
                                    slot: {
                                        element: slot.element,
                                        start: slot.startDate(),
                                        end: slot.endDate(),
                                        isDaySlot: slot.isDaySlot
                                    },
                                    resources: view._resourceBySlot(slot),
                                    start: range.start,
                                    end: range.end
                                })) {
                                endSlot = slot;
                            } else {
                                view._updateMoveHint(clonedEvent, slot.groupIndex, distance);
                            }
                        }).bind('dragend', function (e) {
                            that.view()._removeMoveHint();
                            var distance = endTime - startTime;
                            var range = moveEventRange(clonedEvent, distance);
                            var start = range.start;
                            var end = range.end;
                            var endResources = that.view()._resourceBySlot(endSlot);
                            var startResources = that.view()._resourceBySlot(startSlot);
                            var prevented = that.trigger('moveEnd', {
                                event: event,
                                slot: {
                                    element: endSlot.element,
                                    start: endSlot.startDate(),
                                    end: endSlot.endDate()
                                },
                                start: start,
                                end: end,
                                resources: endResources
                            });
                            if (!prevented && (event.start.getTime() !== start.getTime() || event.end.getTime() !== end.getTime() || originSlot.isDaySlot !== endSlot.isDaySlot || kendo.stringify(endResources) !== kendo.stringify(startResources))) {
                                var updatedEventOptions = that.view()._eventOptionsForMove(event);
                                var eventOptions;
                                if (originSlot.isDaySlot !== endSlot.isDaySlot) {
                                    if (endSlot.isDaySlot) {
                                        eventOptions = $.extend({
                                            start: endSlot.startDate(),
                                            end: endSlot.startDate(),
                                            isAllDay: endSlot.isDaySlot
                                        }, updatedEventOptions, endResources);
                                    } else {
                                        eventOptions = $.extend({
                                            isAllDay: endSlot.isDaySlot,
                                            start: start,
                                            end: end
                                        }, updatedEventOptions, endResources);
                                    }
                                } else {
                                    eventOptions = $.extend({
                                        isAllDay: event.isAllDay,
                                        start: start,
                                        end: end
                                    }, updatedEventOptions, endResources);
                                }
                                that._updateEvent(null, event, eventOptions, endSlot.groupIndex);
                            }
                            e.currentTarget.removeClass('k-event-active');
                            this.cancelHold();
                        }).bind('dragcancel', function () {
                            that.view()._removeMoveHint();
                            this.cancelHold();
                        });
                    }
                    if (isMobile) {
                        that._moveDraggable.bind('hold', function (e) {
                            if (that.element.find('.k-scheduler-monthview').length) {
                                e.preventDefault();
                            }
                            that.element.find('.k-event-active').removeClass('k-event-active');
                            e.currentTarget.addClass('k-event-active');
                        });
                        if (!kendo.support.mobileOS.android) {
                            that._moveDraggable.userEvents.bind('press', function (e) {
                                e.preventDefault();
                            });
                        }
                    }
                }
            },
            _resizable: function () {
                var startTime;
                var endTime;
                var event;
                var clonedEvent;
                var slot;
                var that = this;
                var distance = 0;
                function direction(handle) {
                    var directions = {
                        'k-resize-e': 'east',
                        'k-resize-w': 'west',
                        'k-resize-n': 'north',
                        'k-resize-s': 'south'
                    };
                    for (var key in directions) {
                        if (handle.hasClass(key)) {
                            return directions[key];
                        }
                    }
                }
                if (that._isMobile() && kendo.support.mobileOS.android) {
                    distance = 5;
                }
                that._resizeDraggable = new kendo.ui.Draggable(that.element, {
                    distance: distance,
                    filter: '.k-resize-handle',
                    autoScroll: true,
                    dragstart: function (e) {
                        var dragHandle = $(e.currentTarget);
                        var eventElement = dragHandle.closest('.k-event');
                        var uid = eventElement.attr(kendo.attr('uid'));
                        var view = that.view();
                        event = that.occurrenceByUid(uid);
                        clonedEvent = event.clone();
                        view._updateEventForResize(clonedEvent);
                        slot = view._slotByPosition(e.x.startLocation, e.y.startLocation);
                        if (that.trigger('resizeStart', { event: event })) {
                            e.preventDefault();
                        }
                        startTime = kendo.date.toUtcTime(clonedEvent.start);
                        endTime = kendo.date.toUtcTime(clonedEvent.end);
                    },
                    drag: function (e) {
                        if (!slot) {
                            return;
                        }
                        var dragHandle = $(e.currentTarget);
                        var dir = direction(dragHandle);
                        var view = that.view();
                        var currentSlot = view._slotByPosition(e.x.location, e.y.location);
                        if (!currentSlot || slot.groupIndex != currentSlot.groupIndex) {
                            return;
                        }
                        slot = currentSlot;
                        var originalStart = startTime;
                        var originalEnd = endTime;
                        if (dir == 'south') {
                            if (!slot.isDaySlot && slot.end - kendo.date.toUtcTime(clonedEvent.start) >= view._timeSlotInterval()) {
                                if (clonedEvent.isAllDay) {
                                    endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                                } else {
                                    endTime = slot.endOffset(e.x.location, e.y.location, that.options.snap);
                                }
                            }
                        } else if (dir == 'north') {
                            if (!slot.isDaySlot && kendo.date.toUtcTime(clonedEvent.end) - slot.start >= view._timeSlotInterval()) {
                                startTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                            }
                        } else if (dir == 'east') {
                            if (slot.isDaySlot && kendo.date.toUtcTime(kendo.date.getDate(slot.endDate())) >= kendo.date.toUtcTime(kendo.date.getDate(clonedEvent.start))) {
                                if (clonedEvent.isAllDay) {
                                    endTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                                } else {
                                    endTime = slot.endOffset(e.x.location, e.y.location, that.options.snap);
                                }
                            } else if (!slot.isDaySlot && slot.end - kendo.date.toUtcTime(clonedEvent.start) >= view._timeSlotInterval()) {
                                endTime = slot.endOffset(e.x.location, e.y.location, that.options.snap);
                            }
                        } else if (dir == 'west') {
                            if (slot.isDaySlot && kendo.date.toUtcTime(kendo.date.getDate(clonedEvent.end)) >= kendo.date.toUtcTime(kendo.date.getDate(slot.startDate()))) {
                                startTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                            } else if (!slot.isDaySlot && kendo.date.toUtcTime(clonedEvent.end) - slot.start >= view._timeSlotInterval()) {
                                startTime = slot.startOffset(e.x.location, e.y.location, that.options.snap);
                            }
                        }
                        if (!that.trigger('resize', {
                                event: event,
                                slot: {
                                    element: slot.element,
                                    start: slot.startDate(),
                                    end: slot.endDate()
                                },
                                start: kendo.timezone.toLocalDate(startTime),
                                end: kendo.timezone.toLocalDate(endTime),
                                resources: view._resourceBySlot(slot)
                            })) {
                            view._updateResizeHint(clonedEvent, slot.groupIndex, startTime, endTime);
                        } else {
                            startTime = originalStart;
                            endTime = originalEnd;
                        }
                    },
                    dragend: function (e) {
                        var dragHandle = $(e.currentTarget);
                        var start = new Date(clonedEvent.start.getTime());
                        var end = new Date(clonedEvent.end.getTime());
                        var dir = direction(dragHandle);
                        that.view()._removeResizeHint();
                        if (dir == 'south') {
                            end = kendo.timezone.toLocalDate(endTime);
                        } else if (dir == 'north') {
                            start = kendo.timezone.toLocalDate(startTime);
                        } else if (dir == 'east') {
                            if (slot.isDaySlot) {
                                end = kendo.date.getDate(kendo.timezone.toLocalDate(endTime));
                            } else {
                                end = kendo.timezone.toLocalDate(endTime);
                            }
                        } else if (dir == 'west') {
                            if (slot.isDaySlot) {
                                start = new Date(kendo.timezone.toLocalDate(startTime));
                                start.setHours(0);
                                start.setMinutes(0);
                            } else {
                                start = kendo.timezone.toLocalDate(startTime);
                            }
                        }
                        var prevented = that.trigger('resizeEnd', {
                            event: event,
                            slot: {
                                element: slot.element,
                                start: slot.startDate(),
                                end: slot.endDate()
                            },
                            start: start,
                            end: end,
                            resources: that.view()._resourceBySlot(slot)
                        });
                        if (!prevented && end.getTime() >= start.getTime()) {
                            if (clonedEvent.start.getTime() != start.getTime() || clonedEvent.end.getTime() != end.getTime()) {
                                that.view()._updateEventForResize(event);
                                that._updateEvent(dir, event, {
                                    start: start,
                                    end: end
                                });
                            }
                        }
                        slot = null;
                        event = null;
                    },
                    dragcancel: function () {
                        that.view()._removeResizeHint();
                        slot = null;
                        event = null;
                    }
                });
            },
            _updateEvent: function (dir, event, eventInfo, groupIndex) {
                var that = this;
                var updateEvent = function (event, callback) {
                    try {
                        that._preventRefresh = true;
                        event.update(eventInfo);
                        that._convertDates(event);
                    } finally {
                        that._preventRefresh = false;
                    }
                    if (!that.trigger(SAVE, { event: event })) {
                        if (callback) {
                            callback();
                        }
                        that._updateSelection(event, [event.uid], groupIndex);
                        that.dataSource.sync();
                    }
                };
                var recurrenceHead = function (event) {
                    if (event.recurrenceRule) {
                        return that.dataSource.getByUid(event.uid);
                    } else {
                        return that.dataSource.get(event.recurrenceId);
                    }
                };
                var updateSeries = function () {
                    var head = recurrenceHead(event);
                    if (dir == 'south' || dir == 'north') {
                        if (eventInfo.start) {
                            var start = kendo.date.getDate(head.start);
                            kendo.date.setTime(start, getMilliseconds(eventInfo.start));
                            eventInfo.start = start;
                        }
                        if (eventInfo.end) {
                            var end = kendo.date.getDate(head.end);
                            kendo.date.setTime(end, getMilliseconds(eventInfo.end));
                            eventInfo.end = end;
                        }
                    }
                    that.dataSource._removeExceptions(head);
                    updateEvent(head);
                };
                var updateOccurrence = function () {
                    var head = recurrenceHead(event);
                    var callback = function () {
                        that._convertDates(head);
                    };
                    var exception = head.toOccurrence({
                        start: event.start,
                        end: event.end
                    });
                    updateEvent(that.dataSource.add(exception), callback);
                };
                if (event.recurrenceRule || event.isOccurrence()) {
                    var recurrenceMessages = that.options.messages.recurrenceMessages;
                    that._showRecurringDialog(event, updateOccurrence, updateSeries, {
                        title: recurrenceMessages.editWindowTitle,
                        text: recurrenceMessages.editRecurring ? recurrenceMessages.editRecurring : EDITRECURRING,
                        occurrenceText: recurrenceMessages.editWindowOccurrence,
                        seriesText: recurrenceMessages.editWindowSeries
                    });
                } else {
                    updateEvent(that.dataSource.getByUid(event.uid));
                }
            },
            _modelForContainer: function (container) {
                container = $(container).closest('[' + kendo.attr('uid') + ']');
                return this.dataSource.getByUid(container.attr(kendo.attr('uid')));
            },
            showDialog: function (options) {
                this._editor.showDialog(options);
            },
            focus: function () {
                this.wrapper.focus();
            },
            _confirmation: function (callback, model) {
                var editable = this.options.editable;
                if (editable === true || editable.confirmation !== false) {
                    var messages = this.options.messages;
                    var title = messages.deleteWindowTitle;
                    var text = typeof editable.confirmation === STRING ? editable.confirmation : messages.editable.confirmation;
                    if (this._isEditorOpened() && model.isRecurring()) {
                        var recurrenceMessages = this.options.messages.recurrenceMessages;
                        title = recurrenceMessages.deleteWindowTitle;
                        if (model.isException()) {
                            text = recurrenceMessages.deleteRecurringConfirmation ? recurrenceMessages.deleteRecurringConfirmation : DELETERECURRINGCONFIRM;
                        } else {
                            text = recurrenceMessages.deleteSeriesConfirmation ? recurrenceMessages.deleteSeriesConfirmation : DELETESERIESCONFIRM;
                        }
                    }
                    var buttons = [{
                            name: 'destroy',
                            text: messages.destroy,
                            click: function () {
                                callback();
                            }
                        }];
                    if (!(this._isMobile() && kendo.mobile.ui.Pane)) {
                        buttons.push({
                            name: 'canceledit',
                            text: messages.cancel,
                            click: function () {
                                callback(true);
                            }
                        });
                    }
                    this._unbindResize();
                    this.showDialog({
                        model: model,
                        text: text,
                        title: title,
                        buttons: buttons
                    });
                    this._bindResize();
                } else {
                    callback();
                }
            },
            addEvent: function (eventInfo) {
                var editable = this._editor.editable;
                var dataSource = this.dataSource;
                var event;
                eventInfo = eventInfo || {};
                var prevented = this.trigger('add', { event: eventInfo });
                if (!prevented && (editable && editable.end() || !editable)) {
                    this.cancelEvent();
                    if (eventInfo && eventInfo.toJSON) {
                        eventInfo = eventInfo.toJSON();
                    }
                    event = dataSource.add(eventInfo);
                    if (event) {
                        this.cancelEvent();
                        this._editEvent(event);
                    }
                }
            },
            saveEvent: function () {
                var editor = this._editor;
                if (!editor) {
                    return;
                }
                var editable = editor.editable;
                var container = editor.container;
                var model = this._modelForContainer(container);
                if (container && editable && editable.end() && !this.trigger(SAVE, {
                        container: container,
                        event: model
                    })) {
                    if (model.isRecurrenceHead()) {
                        this.dataSource._removeExceptions(model);
                    }
                    if (!model.dirty && !model.isOccurrence()) {
                        this._convertDates(model, 'remove');
                    }
                    this.dataSource.sync();
                }
            },
            cancelEvent: function () {
                var editor = this._editor;
                var container = editor.container;
                var model;
                if (container) {
                    model = this._modelForContainer(container);
                    if (model && model.isOccurrence()) {
                        this._convertDates(model, 'remove');
                        this._convertDates(this.dataSource.get(model.recurrenceId), 'remove');
                    }
                    this.dataSource.cancelChanges(model);
                    editor.close();
                }
            },
            editEvent: function (uid) {
                var model = typeof uid == 'string' ? this.occurrenceByUid(uid) : uid;
                if (!model) {
                    return;
                }
                this.cancelEvent();
                if (model.isRecurring()) {
                    this._editRecurringDialog(model);
                } else {
                    this._editEvent(model);
                }
            },
            _editEvent: function (model) {
                this._unbindResize();
                this._createPopupEditor(model);
                this._bindResize();
            },
            _editRecurringDialog: function (model) {
                var that = this;
                var editOccurrence = function () {
                    if (model.isException()) {
                        that._editEvent(model);
                    } else {
                        that.addEvent(model);
                    }
                };
                var editSeries = function () {
                    if (model.recurrenceId) {
                        model = that.dataSource.get(model.recurrenceId);
                    }
                    that._editEvent(model);
                };
                var recurrenceMessages = that.options.messages.recurrenceMessages;
                that._showRecurringDialog(model, editOccurrence, editSeries, {
                    title: recurrenceMessages.editWindowTitle,
                    text: recurrenceMessages.editRecurring ? recurrenceMessages.editRecurring : EDITRECURRING,
                    occurrenceText: recurrenceMessages.editWindowOccurrence,
                    seriesText: recurrenceMessages.editWindowSeries
                });
            },
            _showRecurringDialog: function (model, editOccurrence, editSeries, messages) {
                var that = this;
                var editable = that.options.editable;
                var editRecurringMode = isPlainObject(editable) ? editable.editRecurringMode : 'dialog';
                if (editRecurringMode === 'series') {
                    editSeries();
                } else if (editRecurringMode === 'occurrence') {
                    editOccurrence();
                } else {
                    this._unbindResize();
                    that.showDialog({
                        model: model,
                        title: messages.title,
                        text: messages.text,
                        buttons: [
                            {
                                text: messages.occurrenceText,
                                click: editOccurrence
                            },
                            {
                                text: messages.seriesText,
                                click: editSeries
                            }
                        ]
                    });
                    this._bindResize();
                }
            },
            _createButton: function (command) {
                var template = command.template || COMMANDBUTTONTMPL, commandName = typeof command === STRING ? command : command.name || command.text, options = {
                        className: 'k-scheduler-' + (commandName || '').replace(/\s/g, ''),
                        text: commandName,
                        attr: ''
                    };
                if (!commandName && !(isPlainObject(command) && command.template)) {
                    throw new Error('Custom commands should have name specified');
                }
                if (isPlainObject(command)) {
                    if (command.className) {
                        command.className += ' ' + options.className;
                    }
                    if (commandName === 'edit' && isPlainObject(command.text)) {
                        command = extend(true, {}, command);
                        command.text = command.text.edit;
                    }
                    options = extend(true, options, defaultCommands[commandName], command);
                } else {
                    options = extend(true, options, defaultCommands[commandName]);
                }
                return kendo.template(template)(options);
            },
            _convertDates: function (model, method) {
                var timezone = this.dataSource.reader.timezone;
                var startTimezone = model.startTimezone;
                var endTimezone = model.endTimezone;
                var start = model.start;
                var end = model.start;
                method = method || 'apply';
                startTimezone = startTimezone || endTimezone;
                endTimezone = endTimezone || startTimezone;
                if (startTimezone) {
                    if (timezone) {
                        if (method === 'apply') {
                            start = kendo.timezone.convert(model.start, timezone, startTimezone);
                            end = kendo.timezone.convert(model.end, timezone, endTimezone);
                        } else {
                            start = kendo.timezone.convert(model.start, startTimezone, timezone);
                            end = kendo.timezone.convert(model.end, endTimezone, timezone);
                        }
                    } else {
                        start = kendo.timezone[method](model.start, startTimezone);
                        end = kendo.timezone[method](model.end, endTimezone);
                    }
                    model._set('start', start);
                    model._set('end', end);
                }
            },
            _createEditor: function () {
                var that = this;
                var editor;
                if (this._isMobile() && kendo.mobile.ui.Pane) {
                    editor = that._editor = new MobileEditor(this.wrapper, extend({}, this.options, {
                        target: this,
                        timezone: that.dataSource.reader.timezone,
                        resources: that.resources,
                        createButton: proxy(this._createButton, this)
                    }));
                } else {
                    editor = that._editor = new PopupEditor(this.wrapper, extend({}, this.options, {
                        target: this,
                        createButton: proxy(this._createButton, this),
                        timezone: that.dataSource.reader.timezone,
                        resources: that.resources
                    }));
                }
                editor.bind('cancel', function (e) {
                    if (that.trigger('cancel', {
                            container: e.container,
                            event: e.model
                        })) {
                        e.preventDefault();
                        return;
                    }
                    that.cancelEvent();
                    that.focus();
                });
                editor.bind('edit', function (e) {
                    if (that.trigger(EDIT, {
                            container: e.container,
                            event: e.model
                        })) {
                        e.preventDefault();
                    }
                });
                editor.bind('save', function () {
                    that.saveEvent();
                });
                editor.bind('remove', function (e) {
                    that.removeEvent(e.model);
                });
            },
            _createPopupEditor: function (model) {
                var editor = this._editor;
                if (!model.isNew() || model.isOccurrence()) {
                    if (model.isOccurrence()) {
                        this._convertDates(model.recurrenceId ? this.dataSource.get(model.recurrenceId) : model);
                    }
                    this._convertDates(model);
                }
                this.editable = editor.editEvent(model);
            },
            removeEvent: function (uid) {
                var that = this, model = typeof uid == 'string' ? that.occurrenceByUid(uid) : uid;
                if (!model) {
                    return;
                }
                if (model.isRecurring()) {
                    that._deleteRecurringDialog(model);
                } else {
                    that._confirmation(function (cancel) {
                        if (!cancel) {
                            that._removeEvent(model);
                        }
                    }, model);
                }
            },
            occurrenceByUid: function (uid) {
                var occurrence = this.dataSource.getByUid(uid);
                if (!occurrence) {
                    occurrence = getOccurrenceByUid(this._data, uid);
                }
                return occurrence;
            },
            occurrencesInRange: function (start, end) {
                return new kendo.data.Query(this._data).filter({
                    logic: 'or',
                    filters: [
                        {
                            logic: 'and',
                            filters: [
                                {
                                    field: 'start',
                                    operator: 'gte',
                                    value: start
                                },
                                {
                                    field: 'end',
                                    operator: 'gte',
                                    value: start
                                },
                                {
                                    field: 'start',
                                    operator: 'lt',
                                    value: end
                                }
                            ]
                        },
                        {
                            logic: 'and',
                            filters: [
                                {
                                    field: 'start',
                                    operator: 'lte',
                                    value: start
                                },
                                {
                                    field: 'end',
                                    operator: 'gt',
                                    value: start
                                }
                            ]
                        }
                    ]
                }).toArray();
            },
            _removeEvent: function (model) {
                if (!this.trigger(REMOVE, { event: model })) {
                    if (this.dataSource.remove(model)) {
                        this.dataSource.sync();
                    }
                }
            },
            _deleteRecurringDialog: function (model) {
                var that = this;
                var currentModel = model;
                var editable = that.options.editable;
                var deleteOccurrence;
                var deleteSeries;
                var deleteOccurrenceConfirmation;
                var deleteSeriesConfirmation;
                var editRecurringMode = isPlainObject(editable) ? editable.editRecurringMode : 'dialog';
                deleteOccurrence = function () {
                    var occurrence = currentModel.recurrenceId ? currentModel : currentModel.toOccurrence();
                    var head = that.dataSource.get(occurrence.recurrenceId);
                    that._convertDates(head);
                    that._removeEvent(occurrence);
                };
                deleteSeries = function () {
                    if (currentModel.recurrenceId) {
                        currentModel = that.dataSource.get(currentModel.recurrenceId);
                    }
                    that._removeEvent(currentModel);
                };
                if (editRecurringMode != 'dialog' || that._isEditorOpened()) {
                    deleteOccurrenceConfirmation = function () {
                        that._confirmation(function (cancel) {
                            if (!cancel) {
                                deleteOccurrence();
                            }
                        }, currentModel);
                    };
                    deleteSeriesConfirmation = function () {
                        that._confirmation(function (cancel) {
                            if (!cancel) {
                                deleteSeries();
                            }
                        }, currentModel);
                    };
                }
                var seriesCallback = deleteSeriesConfirmation || deleteSeries;
                var occurrenceCallback = deleteOccurrenceConfirmation || deleteOccurrence;
                if (that._isEditorOpened()) {
                    if (model.isException()) {
                        occurrenceCallback();
                    } else {
                        seriesCallback();
                    }
                } else {
                    var recurrenceMessages = that.options.messages.recurrenceMessages;
                    that._showRecurringDialog(model, occurrenceCallback, seriesCallback, {
                        title: recurrenceMessages.deleteWindowTitle,
                        text: recurrenceMessages.deleteRecurring ? recurrenceMessages.deleteRecurring : DELETERECURRING,
                        occurrenceText: recurrenceMessages.deleteWindowOccurrence,
                        seriesText: recurrenceMessages.deleteWindowSeries
                    });
                }
            },
            _isEditorOpened: function () {
                return !!this._editor.container;
            },
            _unbindView: function (view) {
                var that = this;
                that.angular('cleanup', function () {
                    return { elements: that.items() };
                });
                view.destroy();
            },
            _bindView: function (view) {
                var that = this;
                if (that.options.editable) {
                    if (that._viewRemoveHandler) {
                        view.unbind(REMOVE, that._viewRemoveHandler);
                    }
                    that._viewRemoveHandler = function (e) {
                        that.removeEvent(e.uid);
                    };
                    view.bind(REMOVE, that._viewRemoveHandler);
                    if (that._viewAddHandler) {
                        view.unbind(ADD, that._viewAddHandler);
                    }
                    that._viewAddHandler = function (e) {
                        that.addEvent(e.eventInfo);
                    };
                    view.bind(ADD, this._viewAddHandler);
                    if (that._viewEditHandler) {
                        view.unbind(EDIT, that._viewEditHandler);
                    }
                    that._viewEditHandler = function (e) {
                        that.editEvent(e.uid);
                    };
                    view.bind(EDIT, this._viewEditHandler);
                }
                if (that._viewNavigateHandler) {
                    view.unbind('navigate', that._viewNavigateHandler);
                }
                that._viewNavigateHandler = function (e) {
                    if (e.view) {
                        var switchWorkDay = 'isWorkDay' in e;
                        var action = switchWorkDay ? 'changeWorkDay' : 'changeView';
                        if (!that.trigger('navigate', {
                                view: e.view,
                                isWorkDay: e.isWorkDay,
                                action: action,
                                date: e.date
                            })) {
                            if (switchWorkDay) {
                                that._workDayMode = e.isWorkDay;
                            }
                            that._selectView(e.view);
                            that.date(e.date);
                        }
                    }
                };
                view.bind('navigate', that._viewNavigateHandler);
                if (that._viewActivateHandler) {
                    view.unbind('activate', that._viewActivateHandler);
                }
                that._viewActivateHandler = function () {
                    var view = this;
                    if (that._selection) {
                        view.constrainSelection(that._selection);
                        that._select();
                        that._adjustSelectedDate();
                    }
                };
                view.bind('activate', that._viewActivateHandler);
            },
            _selectView: function (name) {
                var that = this;
                if (name && that.views[name]) {
                    if (that._selectedView) {
                        that._unbindView(that._selectedView);
                    }
                    that._selectedView = that._renderView(name);
                    that._selectedViewName = name;
                    if (that._viewsCount > 1) {
                        var viewButton = VIEWBUTTONTEMPLATE({
                            views: that.views,
                            view: name,
                            ns: kendo.ns
                        });
                        var firstButton = that.toolbar.find('.k-scheduler-views li:first-child');
                        if (firstButton.is('.k-current-view')) {
                            firstButton.replaceWith(viewButton);
                        } else {
                            that.toolbar.find('.k-scheduler-views').prepend(viewButton);
                        }
                        var viewButtons = that.toolbar.find('.k-scheduler-views li').removeClass('k-state-selected');
                        viewButtons.end().find('.k-view-' + name.replace(/\./g, '\\.').toLowerCase()).addClass('k-state-selected');
                    }
                }
            },
            view: function (name) {
                var that = this;
                if (name) {
                    that._selectView(name);
                    that.rebind();
                    return;
                }
                return that._selectedView;
            },
            viewName: function () {
                return this.view().name;
            },
            _renderView: function (name) {
                var view = this._initializeView(name);
                this._bindView(view);
                this._model.set('formattedDate', view.dateForTitle());
                this._model.set('formattedShortDate', view.shortDateForTitle());
                return view;
            },
            resize: function (force) {
                var size = this.getSize();
                var currentSize = this._size;
                var view = this.view();
                if (!view || !view.groups) {
                    return;
                }
                if (force || !currentSize || size.width !== currentSize.width || size.height !== currentSize.height) {
                    this.refresh({ action: 'resize' });
                    this._size = size;
                }
            },
            _adjustSelectedDate: function () {
                var date = this._model.selectedDate, selection = this._selection, start = selection.start;
                if (start && !kendo.date.isInDateRange(date, getDate(start), getDate(selection.end))) {
                    date.setFullYear(start.getFullYear(), start.getMonth(), start.getDate());
                }
            },
            _initializeView: function (name) {
                var view = this.views[name];
                if (view) {
                    var isSettings = isPlainObject(view), type = view.type;
                    if (typeof type === STRING) {
                        type = kendo.getter(view.type)(window);
                    }
                    if (type) {
                        view = new type(this.wrapper, trimOptions(extend(true, {}, this.options, isSettings ? view : {}, {
                            resources: this.resources,
                            date: this.date(),
                            showWorkHours: this._workDayMode
                        })));
                    } else {
                        throw new Error('There is no such view');
                    }
                }
                return view;
            },
            _views: function () {
                var views = this.options.views;
                var view;
                var defaultView;
                var selected;
                var isSettings;
                var name;
                var type;
                var idx;
                var length;
                this.views = {};
                this._viewsCount = 0;
                for (idx = 0, length = views.length; idx < length; idx++) {
                    var hasType = false;
                    view = views[idx];
                    isSettings = isPlainObject(view);
                    if (isSettings) {
                        type = name = view.type ? view.type : view;
                        if (typeof type !== STRING) {
                            name = view.name || view.title;
                            hasType = true;
                        }
                    } else {
                        type = name = view;
                    }
                    defaultView = defaultViews[name];
                    if (defaultView && !hasType) {
                        view.type = defaultView.type;
                        defaultView.title = this.options.messages.views[name];
                        if (defaultView.type === 'day') {
                            defaultView.messages = { allDay: this.options.messages.allDay };
                        } else if (defaultView.type === 'agenda') {
                            defaultView.messages = {
                                event: this.options.messages.event,
                                date: this.options.messages.date,
                                time: this.options.messages.time
                            };
                        }
                    }
                    view = extend({ title: name }, defaultView, isSettings ? view : {});
                    if (name) {
                        this.views[name] = view;
                        this._viewsCount++;
                        if (!selected || view.selected) {
                            selected = name;
                        }
                    }
                }
                if (selected) {
                    this._selectedViewName = selected;
                }
            },
            rebind: function () {
                this.dataSource.fetch();
            },
            _dataSource: function () {
                var that = this, options = that.options, dataSource = options.dataSource;
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                if (options.timezone && !(dataSource instanceof SchedulerDataSource)) {
                    dataSource = extend(true, dataSource, { schema: { timezone: options.timezone } });
                } else if (dataSource instanceof SchedulerDataSource) {
                    options.timezone = dataSource.options.schema ? dataSource.options.schema.timezone : '';
                }
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler).unbind('progress', that._progressHandler).unbind('error', that._errorHandler);
                } else {
                    that._refreshHandler = proxy(that.refresh, that);
                    that._progressHandler = proxy(that._requestStart, that);
                    that._errorHandler = proxy(that._error, that);
                }
                that.dataSource = kendo.data.SchedulerDataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind('progress', that._progressHandler).bind('error', that._errorHandler);
                that.options.dataSource = that.dataSource;
            },
            _error: function () {
                this._progress(false);
            },
            _requestStart: function () {
                this._progress(true);
            },
            _progress: function (toggle) {
                var element = this.element.find('.k-scheduler-content');
                kendo.ui.progress(element, toggle);
            },
            _resources: function () {
                var that = this;
                var resources = that.options.resources;
                for (var idx = 0; idx < resources.length; idx++) {
                    var resource = resources[idx];
                    var field = resource.field;
                    var dataSource = resource.dataSource;
                    if (!field || !dataSource) {
                        throw new Error('The "field" and "dataSource" options of the scheduler resource are mandatory.');
                    }
                    that.resources.push({
                        field: field,
                        name: resource.name || field,
                        title: resource.title || field,
                        dataTextField: resource.dataTextField || 'text',
                        dataValueField: resource.dataValueField || 'value',
                        dataColorField: resource.dataColorField || 'color',
                        valuePrimitive: resource.valuePrimitive != null ? resource.valuePrimitive : true,
                        multiple: resource.multiple || false,
                        dataSource: kendo.data.DataSource.create(dataSource)
                    });
                }
                var promises = $.map(that.resources, function (resource) {
                    return resource.dataSource.fetch();
                });
                $.when.apply(null, promises).then(function () {
                    if (that.options.autoBind) {
                        that.view(that._selectedViewName);
                    } else {
                        that._selectView(that._selectedViewName);
                    }
                });
            },
            _initModel: function () {
                var that = this;
                that._model = kendo.observable({
                    selectedDate: new Date(this.options.date),
                    formattedDate: '',
                    formattedShortDate: ''
                });
                that._model.bind('change', function (e) {
                    if (e.field === 'selectedDate') {
                        that.view(that._selectedViewName);
                    }
                });
            },
            _wrapper: function () {
                var that = this;
                var options = that.options;
                var height = options.height;
                var width = options.width;
                that.wrapper = that.element.addClass('k-widget k-scheduler k-floatwrap').attr('role', 'grid').attr('aria-multiselectable', true);
                if (that._isMobile()) {
                    that.wrapper.addClass('k-scheduler-mobile');
                }
                if (that._isMobilePhoneView()) {
                    that.wrapper.addClass('k-scheduler-phone');
                }
                if (height) {
                    that.wrapper.height(height);
                }
                if (width) {
                    that.wrapper.width(width);
                }
            },
            date: function (value) {
                if (value != null && getDate(value) >= getDate(this.options.min) && getDate(value) <= getDate(this.options.max)) {
                    this._model.set('selectedDate', value);
                }
                return getDate(this._model.get('selectedDate'));
            },
            _toolbar: function () {
                var that = this;
                var options = that.options;
                var commands = [];
                if (options.toolbar) {
                    commands = $.isArray(options.toolbar) ? options.toolbar : [options.toolbar];
                }
                var template = this._isMobilePhoneView() ? MOBILETOOLBARTEMPLATE : TOOLBARTEMPLATE;
                var toolbar = $(template({
                    messages: options.messages,
                    pdf: $.grep(commands, function (item) {
                        return item == 'pdf' || item.name == 'pdf';
                    }).length > 0,
                    ns: kendo.ns,
                    views: that.views,
                    viewsCount: that._viewsCount
                }));
                that.wrapper.append(toolbar);
                that.toolbar = toolbar;
                kendo.bind(that.toolbar, that._model);
                toolbar.on(CLICK + NS, '.k-pdf', function (e) {
                    e.preventDefault();
                    that.saveAsPDF();
                });
                toolbar.on(CLICK + NS, '.k-scheduler-navigation li', function (e) {
                    var li = $(this);
                    var date = new Date(that.date());
                    var action = '';
                    e.preventDefault();
                    if (li.hasClass('k-nav-today')) {
                        action = 'today';
                        date = new Date();
                    } else if (li.hasClass('k-nav-next')) {
                        action = 'next';
                        date = that.view().nextDate();
                    } else if (li.hasClass('k-nav-prev')) {
                        action = 'previous';
                        date = that.view().previousDate();
                    } else if (li.hasClass('k-nav-current') && !that._isMobilePhoneView()) {
                        that._showCalendar();
                        return;
                    }
                    if (!that.trigger('navigate', {
                            view: that._selectedViewName,
                            action: action,
                            date: date
                        })) {
                        that.date(date);
                    }
                });
                toolbar.on(CLICK + NS, '.k-scheduler-views li:not(.k-current-view), .k-scheduler-refresh', function (e) {
                    e.preventDefault();
                    var name = $(this).attr(kendo.attr('name'));
                    if (!that.trigger('navigate', {
                            view: name,
                            action: 'changeView',
                            date: that.date()
                        })) {
                        that.view(name);
                        that.element.find('.k-state-expanded').removeClass('k-state-expanded');
                    }
                });
                toolbar.on(CLICK + NS, '.k-scheduler-views li.k-current-view', function () {
                    that.element.find('.k-scheduler-views').toggleClass('k-state-expanded');
                    $(document).on(MOUSEDOWN + NS, function (e) {
                        if ($(e.target).closest('.k-scheduler-views').length === 0) {
                            that.element.find('.k-state-expanded').removeClass('k-state-expanded');
                            $(document).off(CLICK + NS);
                        }
                    });
                });
                toolbar.find('li').hover(function () {
                    $(this).addClass('k-state-hover');
                }, function () {
                    $(this).removeClass('k-state-hover');
                });
            },
            _showCalendar: function () {
                var that = this, target = that.toolbar.find('.k-nav-current'), html = $('<div class="k-calendar-container"><div class="k-scheduler-calendar"/></div>');
                if (!that.popup) {
                    that.popup = new Popup(html, {
                        anchor: target,
                        open: function () {
                            if (!that.calendar) {
                                that.calendar = new Calendar(this.element.find('.k-scheduler-calendar'), {
                                    change: function () {
                                        var date = this.value();
                                        if (!that.trigger('navigate', {
                                                view: that._selectedViewName,
                                                action: 'changeDate',
                                                date: date
                                            })) {
                                            that.date(date);
                                            that.popup.close();
                                        }
                                    },
                                    min: that.options.min,
                                    max: that.options.max
                                });
                            }
                            that.calendar.value(that.date());
                        },
                        copyAnchorStyles: false
                    });
                }
                that.popup.open();
            },
            refresh: function (e) {
                var that = this;
                var view = this.view();
                this._progress(false);
                this.angular('cleanup', function () {
                    return { elements: that.items() };
                });
                e = e || {};
                if (!view) {
                    return;
                }
                if (e && e.action === 'itemchange' && (this._editor.editable || this._preventRefresh)) {
                    return;
                }
                if (this.trigger('dataBinding', {
                        action: e.action || 'rebind',
                        index: e.index,
                        items: e.items
                    })) {
                    return;
                }
                if (!(e && e.action === 'resize') && this._editor) {
                    this._editor.close();
                }
                this._data = this.dataSource.expand(view.startDate(), view.endDate());
                view.refreshLayout();
                view.render(this._data);
                this.trigger('dataBound');
            },
            slotByPosition: function (x, y) {
                var view = this.view();
                if (!view._slotByPosition) {
                    return null;
                }
                var slot = view._slotByPosition(x, y);
                if (!slot) {
                    return null;
                }
                return {
                    startDate: slot.startDate(),
                    endDate: slot.endDate(),
                    groupIndex: slot.groupIndex,
                    element: slot.element,
                    isDaySlot: slot.isDaySlot
                };
            },
            slotByElement: function (element) {
                var offset = $(element).offset();
                return this.slotByPosition(offset.left, offset.top);
            },
            resourcesBySlot: function (slot) {
                return this.view()._resourceBySlot(slot);
            }
        });
        var defaultViews = {
            day: { type: 'kendo.ui.DayView' },
            week: { type: 'kendo.ui.WeekView' },
            workWeek: { type: 'kendo.ui.WorkWeekView' },
            agenda: { type: 'kendo.ui.AgendaView' },
            month: { type: 'kendo.ui.MonthView' },
            timeline: { type: 'kendo.ui.TimelineView' },
            timelineWeek: { type: 'kendo.ui.TimelineWeekView' },
            timelineWorkWeek: { type: 'kendo.ui.TimelineWorkWeekView' },
            timelineMonth: { type: 'kendo.ui.TimelineMonthView' }
        };
        ui.plugin(Scheduler);
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Scheduler.prototype);
            var SCHEDULER_EXPORT = 'k-scheduler-pdf-export';
            Scheduler.fn._drawPDF = function (progress) {
                var wrapper = this.wrapper;
                var styles = wrapper[0].style.cssText;
                wrapper.css({
                    width: wrapper.width(),
                    height: wrapper.height()
                });
                wrapper.addClass(SCHEDULER_EXPORT);
                var scheduler = this;
                var promise = new $.Deferred();
                var table = wrapper.find('.k-scheduler-content').find('table').css('table-layout', 'auto');
                setTimeout(function () {
                    table.css('table-layout', 'fixed');
                    scheduler.resize(true);
                    scheduler._drawPDFShadow({}, { avoidLinks: scheduler.options.pdf.avoidLinks }).done(function (group) {
                        var args = {
                            page: group,
                            pageNumber: 1,
                            progress: 1,
                            totalPages: 1
                        };
                        progress.notify(args);
                        promise.resolve(args.page);
                    }).fail(function (err) {
                        promise.reject(err);
                    }).always(function () {
                        wrapper[0].style.cssText = styles;
                        wrapper.removeClass(SCHEDULER_EXPORT);
                        scheduler.resize(true);
                        scheduler.resize(true);
                    });
                });
                return promise;
            };
        }
        var TimezoneEditor = Widget.extend({
            init: function (element, options) {
                var that = this, zones = kendo.timezone.windows_zones;
                if (!zones || !kendo.timezone.zones_titles) {
                    throw new Error('kendo.timezones.min.js is not included.');
                }
                Widget.fn.init.call(that, element, options);
                that.wrapper = that.element;
                that._zonesQuery = new kendo.data.Query(zones);
                that._zoneTitleId = kendo.guid();
                that._zoneTitlePicker();
                that._zonePicker();
                that._zoneTitle.bind('cascade', function () {
                    if (!this.value()) {
                        that._zone.wrapper.hide();
                    }
                });
                that._zone.bind('cascade', function () {
                    that._value = this.value();
                    that.trigger('change');
                });
                that.value(that.options.value);
            },
            options: {
                name: 'TimezoneEditor',
                value: '',
                optionLabel: 'No timezone'
            },
            events: ['change'],
            _zoneTitlePicker: function () {
                var that = this, zoneTitle = $('<input id="' + that._zoneTitleId + '" aria-label="' + that.options.title + '"/>').appendTo(that.wrapper);
                that._zoneTitle = new kendo.ui.DropDownList(zoneTitle, {
                    dataSource: kendo.timezone.zones_titles,
                    dataValueField: 'other_zone',
                    dataTextField: 'name',
                    optionLabel: that.options.optionLabel
                });
            },
            _zonePicker: function () {
                var that = this, zone = $('<input aria-label="' + that.options.title + '"/>').appendTo(this.wrapper);
                that._zone = new kendo.ui.DropDownList(zone, {
                    dataValueField: 'zone',
                    dataTextField: 'territory',
                    dataSource: that._zonesQuery.data,
                    cascadeFrom: that._zoneTitleId,
                    dataBound: function () {
                        that._value = this.value();
                        this.wrapper.toggle(this.dataSource.view().length > 1);
                    }
                });
                that._zone.wrapper.hide();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                kendo.destroy(this.wrapper);
            },
            value: function (value) {
                var that = this, zone;
                if (value === undefined) {
                    return that._value;
                }
                zone = that._zonesQuery.filter({
                    field: 'zone',
                    operator: 'eq',
                    value: value
                }).data[0];
                if (zone) {
                    that._zoneTitle.value(zone.other_zone);
                    that._zone.value(zone.zone);
                } else {
                    that._zoneTitle.select(0);
                }
            }
        });
        ui.plugin(TimezoneEditor);
        var ZONETITLEOPTIONTEMPLATE = kendo.template('<option value="#=other_zone#">#=name#</option>');
        var ZONEOPTIONTEMPLATE = kendo.template('<option value="#=zone#">#=territory#</option>');
        var MobileTimezoneEditor = Widget.extend({
            init: function (element, options) {
                var that = this, zones = kendo.timezone.windows_zones;
                if (!zones || !kendo.timezone.zones_titles) {
                    throw new Error('kendo.timezones.min.js is not included.');
                }
                Widget.fn.init.call(that, element, options);
                that.wrapper = that.element;
                that._zonesQuery = new kendo.data.Query(zones);
                that._zoneTitlePicker();
                that._zonePicker();
                that.value(that.options.value);
            },
            options: {
                name: 'MobileTimezoneEditor',
                optionLabel: 'No timezone',
                value: ''
            },
            events: ['change'],
            _bindZones: function (value) {
                var data = value ? this._filter(value) : [];
                this._zone.html(this._options(data, ZONEOPTIONTEMPLATE));
            },
            _filter: function (value) {
                return this._zonesQuery.filter({
                    field: 'other_zone',
                    operator: 'eq',
                    value: value
                }).data;
            },
            _options: function (data, template, optionLabel) {
                var idx = 0;
                var html = '';
                var length = data.length;
                if (optionLabel) {
                    html += template({
                        other_zone: '',
                        name: optionLabel
                    });
                }
                for (; idx < length; idx++) {
                    html += template(data[idx]);
                }
                return html;
            },
            _zoneTitlePicker: function () {
                var that = this;
                var options = that._options(kendo.timezone.zones_titles, ZONETITLEOPTIONTEMPLATE, that.options.optionLabel);
                that._zoneTitle = $('<select>' + options + '</select>').appendTo(that.wrapper).change(function () {
                    var value = this.value;
                    var zone = that._zone;
                    that._bindZones(value);
                    if (value && zone[0].children.length > 1) {
                        zone.show();
                    } else {
                        zone.hide();
                    }
                    that._value = zone[0].value;
                    that.trigger('change');
                });
            },
            _zonePicker: function () {
                var that = this;
                that._zone = $('<select style="display:none"></select>').appendTo(this.wrapper).change(function () {
                    that._value = this.value;
                    that.trigger('change');
                });
                that._bindZones(that._zoneTitle.val());
                that._value = that._zone[0].value;
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                kendo.destroy(this.wrapper);
            },
            value: function (value) {
                var that = this;
                var zonePicker = that._zone;
                var other_zone = '';
                var zone_value = '';
                var zone;
                if (value === undefined) {
                    return that._value;
                }
                zone = that._zonesQuery.filter({
                    field: 'zone',
                    operator: 'eq',
                    value: value
                }).data[0];
                if (zone) {
                    zone_value = zone.zone;
                    other_zone = zone.other_zone;
                }
                that._zoneTitle.val(other_zone);
                that._bindZones(other_zone);
                zonePicker.val(zone_value);
                zone_value = zonePicker[0].value;
                if (zone_value && zonePicker[0].children.length > 1) {
                    zonePicker.show();
                } else {
                    zonePicker.hide();
                }
                that._value = zone_value;
            }
        });
        ui.plugin(MobileTimezoneEditor);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.touch', [
        'kendo.core',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'touch',
        name: 'Touch',
        category: 'mobile',
        description: 'The kendo Touch widget provides a cross-platform compatible API for handling user-initiated touch events, multi-touch gestures and event sequences (drag, swipe, etc.). ',
        depends: [
            'core',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, proxy = $.proxy, abs = Math.abs, MAX_DOUBLE_TAP_DISTANCE = 20;
        var Touch = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element;
                that.wrapper = element;
                function eventProxy(name) {
                    return function (e) {
                        that._triggerTouch(name, e);
                    };
                }
                function gestureEventProxy(name) {
                    return function (e) {
                        that.trigger(name, {
                            touches: e.touches,
                            distance: e.distance,
                            center: e.center,
                            event: e.event
                        });
                    };
                }
                that.events = new kendo.UserEvents(element, {
                    filter: options.filter,
                    surface: options.surface,
                    minHold: options.minHold,
                    multiTouch: options.multiTouch,
                    allowSelection: true,
                    fastTap: options.fastTap,
                    press: eventProxy('touchstart'),
                    hold: eventProxy('hold'),
                    tap: proxy(that, '_tap'),
                    gesturestart: gestureEventProxy('gesturestart'),
                    gesturechange: gestureEventProxy('gesturechange'),
                    gestureend: gestureEventProxy('gestureend')
                });
                if (options.enableSwipe) {
                    that.events.bind('start', proxy(that, '_swipestart'));
                    that.events.bind('move', proxy(that, '_swipemove'));
                } else {
                    that.events.bind('start', proxy(that, '_dragstart'));
                    that.events.bind('move', eventProxy('drag'));
                    that.events.bind('end', eventProxy('dragend'));
                }
                kendo.notify(that);
            },
            events: [
                'touchstart',
                'dragstart',
                'drag',
                'dragend',
                'tap',
                'doubletap',
                'hold',
                'swipe',
                'gesturestart',
                'gesturechange',
                'gestureend'
            ],
            options: {
                name: 'Touch',
                surface: null,
                global: false,
                fastTap: false,
                filter: null,
                multiTouch: false,
                enableSwipe: false,
                minXDelta: 30,
                maxYDelta: 20,
                maxDuration: 1000,
                minHold: 800,
                doubleTapTimeout: 800
            },
            cancel: function () {
                this.events.cancel();
            },
            destroy: function () {
                this.events.destroy();
            },
            _triggerTouch: function (type, e) {
                if (this.trigger(type, {
                        touch: e.touch,
                        event: e.event
                    })) {
                    e.preventDefault();
                }
            },
            _tap: function (e) {
                var that = this, lastTap = that.lastTap, touch = e.touch;
                if (lastTap && touch.endTime - lastTap.endTime < that.options.doubleTapTimeout && kendo.touchDelta(touch, lastTap).distance < MAX_DOUBLE_TAP_DISTANCE) {
                    that._triggerTouch('doubletap', e);
                    that.lastTap = null;
                } else {
                    that._triggerTouch('tap', e);
                    that.lastTap = touch;
                }
            },
            _dragstart: function (e) {
                this._triggerTouch('dragstart', e);
            },
            _swipestart: function (e) {
                if (abs(e.x.velocity) * 2 >= abs(e.y.velocity)) {
                    e.sender.capture();
                }
            },
            _swipemove: function (e) {
                var that = this, options = that.options, touch = e.touch, duration = e.event.timeStamp - touch.startTime, direction = touch.x.initialDelta > 0 ? 'right' : 'left';
                if (abs(touch.x.initialDelta) >= options.minXDelta && abs(touch.y.initialDelta) < options.maxYDelta && duration < options.maxDuration) {
                    that.trigger('swipe', {
                        direction: direction,
                        touch: e.touch
                    });
                    touch.cancel();
                }
            }
        });
        kendo.ui.plugin(Touch);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.gantt.list', [
        'kendo.dom',
        'kendo.touch',
        'kendo.draganddrop',
        'kendo.columnsorter',
        'kendo.datetimepicker',
        'kendo.editable'
    ], f);
}(function () {
    var __meta__ = {
        id: 'gantt.list',
        name: 'Gantt List',
        category: 'web',
        description: 'The Gantt List',
        depends: [
            'dom',
            'touch',
            'draganddrop',
            'columnsorter',
            'datetimepicker',
            'editable'
        ],
        hidden: true
    };
    (function ($) {
        var kendo = window.kendo;
        var kendoDom = kendo.dom;
        var kendoDomElement = kendoDom.element;
        var kendoTextElement = kendoDom.text;
        var browser = kendo.support.browser;
        var mobileOS = kendo.support.mobileOS;
        var ui = kendo.ui;
        var Widget = ui.Widget;
        var extend = $.extend;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var map = $.map;
        var isFunction = $.isFunction;
        var oldIE = browser.msie && browser.version < 9;
        var keys = kendo.keys;
        var titleFromField = {
            'title': 'Title',
            'start': 'Start Time',
            'end': 'End Time',
            'percentComplete': '% Done',
            'parentId': 'Predecessor ID',
            'id': 'ID',
            'orderId': 'Order ID'
        };
        var STRING = 'string';
        var NS = '.kendoGanttList';
        var CLICK = 'click';
        var DOT = '.';
        var SIZE_CALCULATION_TEMPLATE = '<table style=\'visibility: hidden;\'>' + '<tbody>' + '<tr style=\'height:{0}\'>' + '<td>&nbsp;</td>' + '</tr>' + '</tbody>' + '</table>';
        var listStyles = {
            wrapper: 'k-treelist k-grid k-widget',
            header: 'k-header',
            alt: 'k-alt',
            rtl: 'k-rtl',
            editCell: 'k-edit-cell',
            group: 'k-treelist-group',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            gridContentWrap: 'k-grid-content',
            selected: 'k-state-selected',
            icon: 'k-icon',
            iconCollapse: 'k-i-collapse',
            iconExpand: 'k-i-expand',
            iconHidden: 'k-i-none',
            iconPlaceHolder: 'k-icon k-i-none',
            input: 'k-input',
            link: 'k-link',
            resizeHandle: 'k-resize-handle',
            resizeHandleInner: 'k-resize-handle-inner',
            dropPositions: 'k-i-insert-up k-i-insert-down k-i-plus k-i-insert-middle',
            dropTop: 'k-i-insert-up',
            dropBottom: 'k-i-insert-down',
            dropAdd: 'k-i-plus',
            dropMiddle: 'k-i-insert-middle',
            dropDenied: 'k-i-cancel',
            dragStatus: 'k-drag-status',
            dragClue: 'k-drag-clue',
            dragClueText: 'k-clue-text'
        };
        function createPlaceholders(options) {
            var spans = [];
            var className = options.className;
            for (var i = 0, level = options.level; i < level; i++) {
                spans.push(kendoDomElement('span', { className: className }));
            }
            return spans;
        }
        function blurActiveElement() {
            var activeElement = kendo._activeElement();
            if (activeElement && activeElement.nodeName.toLowerCase() !== 'body') {
                $(activeElement).blur();
            }
        }
        var GanttList = ui.GanttList = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                if (this.options.columns.length === 0) {
                    this.options.columns.push('title');
                }
                this.dataSource = this.options.dataSource;
                this._columns();
                this._layout();
                this._domTrees();
                this._header();
                this._sortable();
                this._editable();
                this._selectable();
                this._draggable();
                this._resizable();
                this._attachEvents();
                this._adjustHeight();
                this.bind('render', function () {
                    var headerCols;
                    var tableCols;
                    if (this.options.resizable) {
                        headerCols = this.header.find('col');
                        tableCols = this.content.find('col');
                        this.header.find('th').not(':last').each(function (index) {
                            var width = outerWidth($(this));
                            headerCols.eq(index).width(width);
                            tableCols.eq(index).width(width);
                        });
                        headerCols.last().css('width', 'auto');
                        tableCols.last().css('width', 'auto');
                    }
                }, true);
            },
            _adjustHeight: function () {
                if (this.content) {
                    this.content.height(this.element.height() - outerHeight(this.header.parent()));
                }
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this._reorderDraggable) {
                    this._reorderDraggable.destroy();
                }
                if (this._tableDropArea) {
                    this._tableDropArea.destroy();
                }
                if (this._contentDropArea) {
                    this._contentDropArea.destroy();
                }
                if (this._columnResizable) {
                    this._columnResizable.destroy();
                }
                if (this.touch) {
                    this.touch.destroy();
                }
                if (this.timer) {
                    clearTimeout(this.timer);
                }
                this.content.off(NS);
                this.header.find('thead').off(NS);
                this.header.find(DOT + GanttList.link).off(NS);
                this.header = null;
                this.content = null;
                this.levels = null;
                kendo.destroy(this.element);
            },
            options: {
                name: 'GanttList',
                selectable: true,
                editable: true,
                resizable: false
            },
            _attachEvents: function () {
                var that = this;
                var listStyles = GanttList.styles;
                that.content.on(CLICK + NS, 'td > span.' + listStyles.icon + ':not(.' + listStyles.iconHidden + ')', function (e) {
                    var element = $(this);
                    var model = that._modelFromElement(element);
                    model.set('expanded', !model.get('expanded'));
                    e.stopPropagation();
                });
            },
            _domTrees: function () {
                this.headerTree = new kendoDom.Tree(this.header[0]);
                this.contentTree = new kendoDom.Tree(this.content[0]);
            },
            _columns: function () {
                var columns = this.options.columns;
                var model = function () {
                    this.field = '';
                    this.title = '';
                    this.editable = false;
                    this.sortable = false;
                };
                this.columns = map(columns, function (column) {
                    column = typeof column === STRING ? {
                        field: column,
                        title: titleFromField[column]
                    } : column;
                    return extend(new model(), column);
                });
            },
            _layout: function () {
                var that = this;
                var options = this.options;
                var element = this.element;
                var listStyles = GanttList.styles;
                var calculateRowHeight = function () {
                    var rowHeight = typeof options.rowHeight === STRING ? options.rowHeight : options.rowHeight + 'px';
                    var table = $(kendo.format(SIZE_CALCULATION_TEMPLATE, rowHeight));
                    var height;
                    that.content.append(table);
                    height = outerHeight(table.find('tr'));
                    table.remove();
                    return height;
                };
                element.addClass(listStyles.wrapper).append('<div class=\'' + listStyles.gridHeader + '\'><div class=\'' + listStyles.gridHeaderWrap + '\'></div></div>').append('<div class=\'' + listStyles.gridContentWrap + '\'></div>');
                this.header = element.find(DOT + listStyles.gridHeaderWrap);
                this.content = element.find(DOT + listStyles.gridContent);
                if (options.rowHeight) {
                    this._rowHeight = calculateRowHeight();
                }
            },
            _header: function () {
                var domTree = this.headerTree;
                var colgroup;
                var thead;
                var table;
                colgroup = kendoDomElement('colgroup', null, this._cols());
                thead = kendoDomElement('thead', { 'role': 'rowgroup' }, [kendoDomElement('tr', { 'role': 'row' }, this._ths())]);
                table = kendoDomElement('table', {
                    'style': { 'minWidth': this.options.listWidth + 'px' },
                    'role': 'grid'
                }, [
                    colgroup,
                    thead
                ]);
                domTree.render([table]);
            },
            _render: function (tasks) {
                var colgroup;
                var tbody;
                var table;
                var tableAttr = {
                    'style': { 'minWidth': this.options.listWidth + 'px' },
                    'tabIndex': 0,
                    'role': 'treegrid'
                };
                if (this._rowHeight) {
                    tableAttr.style.height = tasks.length * this._rowHeight + 'px';
                }
                this.levels = [{
                        field: null,
                        value: 0
                    }];
                colgroup = kendoDomElement('colgroup', null, this._cols());
                tbody = kendoDomElement('tbody', { 'role': 'rowgroup' }, this._trs(tasks));
                table = kendoDomElement('table', tableAttr, [
                    colgroup,
                    tbody
                ]);
                this.contentTree.render([table]);
                this.trigger('render');
            },
            _ths: function () {
                var columns = this.columns;
                var column;
                var attr;
                var ths = [];
                for (var i = 0, length = columns.length; i < length; i++) {
                    column = columns[i];
                    attr = {
                        'data-field': column.field,
                        'data-title': column.title,
                        className: GanttList.styles.header,
                        'role': 'columnheader'
                    };
                    ths.push(kendoDomElement('th', attr, [kendoTextElement(column.title)]));
                }
                if (this.options.resizable) {
                    ths.push(kendoDomElement('th', {
                        className: GanttList.styles.header,
                        'role': 'columnheader'
                    }));
                }
                return ths;
            },
            _cols: function () {
                var columns = this.columns;
                var column;
                var style;
                var width;
                var cols = [];
                for (var i = 0, length = columns.length; i < length; i++) {
                    column = columns[i];
                    width = column.width;
                    if (width && parseInt(width, 10) !== 0) {
                        style = { style: { width: typeof width === STRING ? width : width + 'px' } };
                    } else {
                        style = null;
                    }
                    cols.push(kendoDomElement('col', style, []));
                }
                if (this.options.resizable) {
                    cols.push(kendoDomElement('col', { style: { width: '1px' } }));
                }
                return cols;
            },
            _trs: function (tasks) {
                var task;
                var rows = [];
                var attr;
                var className = [];
                var level;
                var listStyles = GanttList.styles;
                for (var i = 0, length = tasks.length; i < length; i++) {
                    task = tasks[i];
                    level = this._levels({
                        idx: task.parentId,
                        id: task.id,
                        summary: task.summary
                    });
                    attr = {
                        'data-uid': task.uid,
                        'data-level': level,
                        'role': 'row'
                    };
                    if (task.summary) {
                        attr['aria-expanded'] = task.expanded;
                    }
                    if (i % 2 !== 0) {
                        className.push(listStyles.alt);
                    }
                    if (task.summary) {
                        className.push(listStyles.group);
                    }
                    if (className.length) {
                        attr.className = className.join(' ');
                    }
                    rows.push(this._tds({
                        task: task,
                        attr: attr,
                        level: level
                    }));
                    className = [];
                }
                return rows;
            },
            _tds: function (options) {
                var children = [];
                var columns = this.columns;
                var column;
                for (var i = 0, l = columns.length; i < l; i++) {
                    column = columns[i];
                    children.push(this._td({
                        task: options.task,
                        column: column,
                        level: options.level
                    }));
                }
                if (this.options.resizable) {
                    children.push(kendoDomElement('td', { 'role': 'gridcell' }));
                }
                return kendoDomElement('tr', options.attr, children);
            },
            _td: function (options) {
                var children = [];
                var resourcesField = this.options.resourcesField;
                var listStyles = GanttList.styles;
                var task = options.task;
                var column = options.column;
                var value = task.get(column.field);
                var formatedValue;
                var label;
                if (column.field == resourcesField) {
                    value = value || [];
                    formatedValue = [];
                    for (var i = 0; i < value.length; i++) {
                        formatedValue.push(kendo.format('{0} [{1}]', value[i].get('name'), value[i].get('formatedValue')));
                    }
                    formatedValue = formatedValue.join(', ');
                } else {
                    formatedValue = column.format ? kendo.format(column.format, value) : value;
                }
                if (column.field === 'title') {
                    children = createPlaceholders({
                        level: options.level,
                        className: listStyles.iconPlaceHolder
                    });
                    children.push(kendoDomElement('span', { className: listStyles.icon + ' ' + (task.summary ? task.expanded ? listStyles.iconCollapse : listStyles.iconExpand : listStyles.iconHidden) }));
                    label = kendo.format('{0}, {1:P0}', formatedValue, task.percentComplete);
                }
                children.push(kendoDomElement('span', { 'aria-label': label }, [kendoTextElement(formatedValue)]));
                return kendoDomElement('td', { 'role': 'gridcell' }, children);
            },
            _levels: function (options) {
                var levels = this.levels;
                var level;
                var summary = options.summary;
                var idx = options.idx;
                var id = options.id;
                for (var i = 0, length = levels.length; i < length; i++) {
                    level = levels[i];
                    if (level.field == idx) {
                        if (summary) {
                            levels.push({
                                field: id,
                                value: level.value + 1
                            });
                        }
                        return level.value;
                    }
                }
            },
            _sortable: function () {
                var that = this;
                var resourcesField = this.options.resourcesField;
                var columns = this.columns;
                var column;
                var sortableInstance;
                var cells = this.header.find('th[' + kendo.attr('field') + ']');
                var cell;
                var changeHandler = function (e) {
                    if (that.dataSource.total() === 0 || that.editable && that.editable.trigger('validate')) {
                        e.preventDefault();
                    }
                };
                for (var idx = 0, length = cells.length; idx < length; idx++) {
                    column = columns[idx];
                    if (column.sortable && column.field !== resourcesField) {
                        cell = cells.eq(idx);
                        sortableInstance = cell.data('kendoColumnSorter');
                        if (sortableInstance) {
                            sortableInstance.destroy();
                        }
                        cell.attr('data-' + kendo.ns + 'field', column.field).kendoColumnSorter({
                            dataSource: this.dataSource,
                            change: changeHandler
                        });
                    }
                }
                cells = null;
            },
            _selectable: function () {
                var that = this;
                var selectable = this.options.selectable;
                if (selectable) {
                    this.content.on(CLICK + NS, 'tr', function (e) {
                        var element = $(this);
                        if (that.editable) {
                            that.editable.trigger('validate');
                        }
                        if (!e.ctrlKey) {
                            that.select(element);
                        } else {
                            that.clearSelection();
                        }
                    });
                }
            },
            select: function (value) {
                var element = this.content.find(value);
                var selectedClassName = GanttList.styles.selected;
                if (element.length) {
                    element.siblings(DOT + selectedClassName).removeClass(selectedClassName).attr('aria-selected', false).end().addClass(selectedClassName).attr('aria-selected', true);
                    this.trigger('change');
                    return;
                }
                return this.content.find(DOT + selectedClassName);
            },
            clearSelection: function () {
                var selected = this.select();
                if (selected.length) {
                    selected.removeClass(GanttList.styles.selected);
                    this.trigger('change');
                }
            },
            _setDataSource: function (dataSource) {
                this.dataSource = dataSource;
                this._sortable();
            },
            _editable: function () {
                var that = this;
                var editable = this.options.editable;
                var listStyles = GanttList.styles;
                var iconSelector = 'span.' + listStyles.icon + ':not(' + listStyles.iconHidden + ')';
                var finishEdit = function () {
                    var editable = that.editable;
                    if (editable) {
                        if (editable.end()) {
                            that._closeCell();
                        } else {
                            editable.trigger('validate');
                        }
                    }
                };
                var mousedown = function (e) {
                    var currentTarget = $(e.currentTarget);
                    if (!currentTarget.hasClass(listStyles.editCell)) {
                        blurActiveElement();
                    }
                };
                if (!editable || editable.update === false) {
                    return;
                }
                this._startEditHandler = function (e) {
                    var td = e.currentTarget ? $(e.currentTarget) : e;
                    var column = that._columnFromElement(td);
                    if (that.editable) {
                        return;
                    }
                    if (column && column.editable) {
                        that._editCell({
                            cell: td,
                            column: column
                        });
                    }
                };
                that.content.on('focusin' + NS, function () {
                    clearTimeout(that.timer);
                    that.timer = null;
                }).on('focusout' + NS, function () {
                    that.timer = setTimeout(finishEdit, 1);
                }).on('keydown' + NS, function (e) {
                    if (e.keyCode === keys.ENTER) {
                        e.preventDefault();
                    }
                }).on('keyup' + NS, function (e) {
                    var key = e.keyCode;
                    var cell;
                    var model;
                    switch (key) {
                    case keys.ENTER:
                        blurActiveElement();
                        finishEdit();
                        break;
                    case keys.ESC:
                        if (that.editable) {
                            cell = that._editableContainer;
                            model = that._modelFromElement(cell);
                            if (!that.trigger('cancel', {
                                    model: model,
                                    cell: cell
                                })) {
                                that._closeCell(true);
                            }
                        }
                        break;
                    }
                });
                if (!mobileOS) {
                    that.content.on('mousedown' + NS, 'td', function (e) {
                        mousedown(e);
                    }).on('dblclick' + NS, 'td', function (e) {
                        if (!$(e.target).is(iconSelector)) {
                            that._startEditHandler(e);
                        }
                    });
                } else {
                    that.touch = that.content.kendoTouch({
                        filter: 'td',
                        touchstart: function (e) {
                            mousedown(e.touch);
                        },
                        doubletap: function (e) {
                            if (!$(e.touch.initialTouch).is(iconSelector)) {
                                that._startEditHandler(e.touch);
                            }
                        }
                    }).data('kendoTouch');
                }
            },
            _editCell: function (options) {
                var resourcesField = this.options.resourcesField;
                var listStyles = GanttList.styles;
                var cell = options.cell;
                var column = options.column;
                var model = this._modelFromElement(cell);
                var modelCopy = this.dataSource._createNewModel(model.toJSON());
                var field = modelCopy.fields[column.field] || modelCopy[column.field];
                var validation = field.validation;
                var DATATYPE = kendo.attr('type');
                var BINDING = kendo.attr('bind');
                var FORMAT = kendo.attr('format');
                var attr = {
                    'name': column.field,
                    'required': field.validation ? field.validation.required === true : false
                };
                var editor;
                if (column.field === resourcesField) {
                    column.editor(cell, modelCopy);
                    return;
                }
                this._editableContent = cell.children().detach();
                this._editableContainer = cell;
                cell.data('modelCopy', modelCopy);
                if ((field.type === 'date' || $.type(field) === 'date') && (!column.format || /H|m|s|F|g|u/.test(column.format))) {
                    attr[BINDING] = 'value:' + column.field;
                    attr[DATATYPE] = 'date';
                    if (column.format) {
                        attr[FORMAT] = kendo._extractFormat(column.format);
                    }
                    editor = function (container, options) {
                        $('<input type="text"/>').attr(attr).appendTo(container).kendoDateTimePicker({ format: options.format });
                    };
                }
                this.editable = cell.addClass(listStyles.editCell).kendoEditable({
                    fields: {
                        field: column.field,
                        format: column.format,
                        editor: column.editor || editor
                    },
                    model: modelCopy,
                    clearContainer: false
                }).data('kendoEditable');
                if (validation && validation.dateCompare && isFunction(validation.dateCompare) && validation.message) {
                    $('<span ' + kendo.attr('for') + '="' + column.field + '" class="k-invalid-msg"/>').hide().appendTo(cell);
                    cell.find('[name=' + column.field + ']').attr(kendo.attr('dateCompare-msg'), validation.message);
                }
                this.editable.bind('validate', function (e) {
                    var focusable = this.element.find(':kendoFocusable:first').focus();
                    if (oldIE) {
                        focusable.focus();
                    }
                    e.preventDefault();
                });
                if (this.trigger('edit', {
                        model: model,
                        cell: cell
                    })) {
                    this._closeCell(true);
                }
            },
            _closeCell: function (cancelUpdate) {
                var listStyles = GanttList.styles;
                var cell = this._editableContainer;
                var model = this._modelFromElement(cell);
                var column = this._columnFromElement(cell);
                var field = column.field;
                var copy = cell.data('modelCopy');
                var taskInfo = {};
                taskInfo[field] = copy.get(field);
                cell.empty().removeData('modelCopy').removeClass(listStyles.editCell).append(this._editableContent);
                this.editable.unbind();
                this.editable.destroy();
                this.editable = null;
                this._editableContainer = null;
                this._editableContent = null;
                if (!cancelUpdate) {
                    if (field === 'start') {
                        taskInfo.end = new Date(taskInfo.start.getTime() + model.duration());
                    }
                    this.trigger('update', {
                        task: model,
                        updateInfo: taskInfo
                    });
                }
            },
            _draggable: function () {
                var that = this;
                var draggedTask = null;
                var dropAllowed = true;
                var dropTarget;
                var listStyles = GanttList.styles;
                var isRtl = kendo.support.isRtl(this.element);
                var selector = 'tr[' + kendo.attr('level') + ' = 0]:last';
                var action = {};
                var editable = this.options.editable;
                var clear = function () {
                    draggedTask = null;
                    dropTarget = null;
                    dropAllowed = true;
                    action = {};
                };
                var allowDrop = function (task) {
                    var parent = task;
                    while (parent) {
                        if (draggedTask.get('id') === parent.get('id')) {
                            dropAllowed = false;
                            break;
                        }
                        parent = that.dataSource.taskParent(parent);
                    }
                };
                var defineLimits = function () {
                    var height = $(dropTarget).height();
                    var offsetTop = kendo.getOffset(dropTarget).top;
                    extend(dropTarget, {
                        beforeLimit: offsetTop + height * 0.25,
                        afterLimit: offsetTop + height * 0.75
                    });
                };
                var defineAction = function (coordinate) {
                    if (!dropTarget) {
                        return;
                    }
                    var location = coordinate.location;
                    var className = listStyles.dropAdd;
                    var command = 'add';
                    var level = parseInt(dropTarget.attr(kendo.attr('level')), 10);
                    var sibling;
                    if (location <= dropTarget.beforeLimit) {
                        sibling = dropTarget.prev();
                        className = listStyles.dropTop;
                        command = 'insert-before';
                    } else if (location >= dropTarget.afterLimit) {
                        sibling = dropTarget.next();
                        className = listStyles.dropBottom;
                        command = 'insert-after';
                    }
                    if (sibling && parseInt(sibling.attr(kendo.attr('level')), 10) === level) {
                        className = listStyles.dropMiddle;
                    }
                    action.className = className;
                    action.command = command;
                };
                var status = function () {
                    return that._reorderDraggable.hint.children(DOT + listStyles.dragStatus).removeClass(listStyles.dropPositions);
                };
                if (!editable || editable.reorder === false || editable.update === false) {
                    return;
                }
                this._reorderDraggable = this.content.kendoDraggable({
                    distance: 10,
                    holdToDrag: mobileOS,
                    group: 'listGroup',
                    filter: 'tr[data-uid]',
                    ignore: DOT + listStyles.input,
                    hint: function (target) {
                        return $('<div class="' + listStyles.header + ' ' + listStyles.dragClue + '"/>').css({
                            width: 300,
                            paddingLeft: target.css('paddingLeft'),
                            paddingRight: target.css('paddingRight'),
                            lineHeight: target.height() + 'px',
                            paddingTop: target.css('paddingTop'),
                            paddingBottom: target.css('paddingBottom')
                        }).append('<span class="' + listStyles.icon + ' ' + listStyles.dragStatus + '" /><span class="' + listStyles.dragClueText + '"/>');
                    },
                    cursorOffset: {
                        top: -20,
                        left: 0
                    },
                    container: this.content,
                    'dragstart': function (e) {
                        var editable = that.editable;
                        if (editable && editable.reorder !== false && editable.trigger('validate')) {
                            e.preventDefault();
                            return;
                        }
                        draggedTask = that._modelFromElement(e.currentTarget);
                        this.hint.children(DOT + listStyles.dragClueText).text(draggedTask.get('title'));
                        if (isRtl) {
                            this.hint.addClass(listStyles.rtl);
                        }
                    },
                    'drag': function (e) {
                        if (dropAllowed) {
                            defineAction(e.y);
                            status().addClass(action.className);
                        }
                    },
                    'dragend': function () {
                        clear();
                    },
                    'dragcancel': function () {
                        clear();
                    }
                }).data('kendoDraggable');
                this._tableDropArea = this.content.kendoDropTargetArea({
                    distance: 0,
                    group: 'listGroup',
                    filter: 'tr[data-uid]',
                    'dragenter': function (e) {
                        dropTarget = e.dropTarget;
                        allowDrop(that._modelFromElement(dropTarget));
                        defineLimits();
                        status().toggleClass(listStyles.dropDenied, !dropAllowed);
                    },
                    'dragleave': function () {
                        dropAllowed = true;
                        status();
                    },
                    'drop': function () {
                        var target = that._modelFromElement(dropTarget);
                        var orderId = target.orderId;
                        var taskInfo = { parentId: target.parentId };
                        if (dropAllowed) {
                            switch (action.command) {
                            case 'add':
                                taskInfo.parentId = target.id;
                                break;
                            case 'insert-before':
                                if (target.parentId === draggedTask.parentId && target.orderId > draggedTask.orderId) {
                                    taskInfo.orderId = orderId - 1;
                                } else {
                                    taskInfo.orderId = orderId;
                                }
                                break;
                            case 'insert-after':
                                if (target.parentId === draggedTask.parentId && target.orderId > draggedTask.orderId) {
                                    taskInfo.orderId = orderId;
                                } else {
                                    taskInfo.orderId = orderId + 1;
                                }
                                break;
                            }
                            that.trigger('update', {
                                task: draggedTask,
                                updateInfo: taskInfo
                            });
                        }
                    }
                }).data('kendoDropTargetArea');
                this._contentDropArea = this.element.kendoDropTargetArea({
                    distance: 0,
                    group: 'listGroup',
                    filter: DOT + listStyles.gridContent,
                    'drop': function () {
                        var target = that._modelFromElement(that.content.find(selector));
                        var orderId = target.orderId;
                        var taskInfo = {
                            parentId: null,
                            orderId: draggedTask.parentId !== null ? orderId + 1 : orderId
                        };
                        that.trigger('update', {
                            task: draggedTask,
                            updateInfo: taskInfo
                        });
                    }
                }).data('kendoDropTargetArea');
            },
            _resizable: function () {
                var that = this;
                var listStyles = GanttList.styles;
                var positionResizeHandle = function (e) {
                    var th = $(e.currentTarget);
                    var resizeHandle = that.resizeHandle;
                    var position = th.position();
                    var left = position.left;
                    var cellWidth = outerWidth(th);
                    var container = th.closest('div');
                    var clientX = e.clientX + $(window).scrollLeft();
                    var indicatorWidth = that.options.columnResizeHandleWidth;
                    left += container.scrollLeft();
                    if (!resizeHandle) {
                        resizeHandle = that.resizeHandle = $('<div class="' + listStyles.resizeHandle + '"><div class="' + listStyles.resizeHandleInner + '" /></div>');
                    }
                    var cellOffset = th.offset().left + cellWidth;
                    var show = clientX > cellOffset - indicatorWidth && clientX < cellOffset + indicatorWidth;
                    if (!show) {
                        resizeHandle.hide();
                        return;
                    }
                    container.append(resizeHandle);
                    resizeHandle.show().css({
                        top: position.top,
                        left: left + cellWidth - indicatorWidth - 1,
                        height: outerHeight(th),
                        width: indicatorWidth * 3
                    }).data('th', th);
                };
                if (!this.options.resizable) {
                    return;
                }
                if (this._columnResizable) {
                    this._columnResizable.destroy();
                }
                this.header.find('thead').on('mousemove' + NS, 'th', positionResizeHandle);
                this._columnResizable = this.header.kendoResizable({
                    handle: DOT + listStyles.resizeHandle,
                    start: function (e) {
                        var th = $(e.currentTarget).data('th');
                        var colSelector = 'col:eq(' + th.index() + ')';
                        var header = that.header.find('table');
                        var contentTable = that.content.find('table');
                        that.element.addClass('k-grid-column-resizing');
                        this.col = contentTable.children('colgroup').find(colSelector).add(header.find(colSelector));
                        this.th = th;
                        this.startLocation = e.x.location;
                        this.columnWidth = outerWidth(th);
                        this.table = header.add(contentTable);
                        this.totalWidth = this.table.width() - outerWidth(header.find('th:last'));
                    },
                    resize: function (e) {
                        var minColumnWidth = 11;
                        var delta = e.x.location - this.startLocation;
                        if (this.columnWidth + delta < minColumnWidth) {
                            delta = minColumnWidth - this.columnWidth;
                        }
                        this.table.css({ 'minWidth': this.totalWidth + delta });
                        this.col.width(this.columnWidth + delta);
                    },
                    resizeend: function () {
                        that.element.removeClass('k-grid-column-resizing');
                        var oldWidth = Math.floor(this.columnWidth);
                        var newWidth = Math.floor(outerWidth(this.th));
                        var column = that.columns[this.th.index()];
                        that.trigger('columnResize', {
                            column: column,
                            oldWidth: oldWidth,
                            newWidth: newWidth
                        });
                        this.table = this.col = this.th = null;
                    }
                }).data('kendoResizable');
            },
            _modelFromElement: function (element) {
                var row = element.closest('tr');
                var model = this.dataSource.getByUid(row.attr(kendo.attr('uid')));
                return model;
            },
            _columnFromElement: function (element) {
                var td = element.closest('td');
                var tr = td.parent();
                var idx = tr.children().index(td);
                return this.columns[idx];
            }
        });
        extend(true, ui.GanttList, { styles: listStyles });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.gantt.timeline', [
        'kendo.dom',
        'kendo.touch',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'gantt.timeline',
        name: 'Gantt Timeline',
        category: 'web',
        description: 'The Gantt Timeline',
        depends: [
            'dom',
            'touch',
            'draganddrop'
        ],
        hidden: true
    };
    (function ($) {
        var Widget = kendo.ui.Widget;
        var kendoDomElement = kendo.dom.element;
        var kendoTextElement = kendo.dom.text;
        var kendoHtmlElement = kendo.dom.html;
        var isPlainObject = $.isPlainObject;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var extend = $.extend;
        var proxy = $.proxy;
        var browser = kendo.support.browser;
        var isRtl = false;
        var keys = kendo.keys;
        var Query = kendo.data.Query;
        var STRING = 'string';
        var NS = '.kendoGanttTimeline';
        var CLICK = 'click';
        var DBLCLICK = 'dblclick';
        var MOUSEMOVE = 'mousemove';
        var MOUSEENTER = 'mouseenter';
        var MOUSELEAVE = 'mouseleave';
        var KEYDOWN = 'keydown';
        var DOT = '.';
        var TIME_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'t\')#');
        var DAY_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'ddd M/dd\')#');
        var WEEK_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'ddd M/dd\')# - #=kendo.toString(kendo.date.addDays(end, -1), \'ddd M/dd\')#');
        var MONTH_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'MMM\')#');
        var YEAR_HEADER_TEMPLATE = kendo.template('#=kendo.toString(start, \'yyyy\')#');
        var RESIZE_HINT = kendo.template('<div class="#=styles.marquee#">' + '<div class="#=styles.marqueeColor#"></div>' + '</div>');
        var RESIZE_TOOLTIP_TEMPLATE = kendo.template('<div style="z-index: 100002;" class="#=styles.tooltipWrapper#">' + '<div class="#=styles.tooltipContent#">' + '<div>#=messages.start#: #=kendo.toString(start, format)#</div>' + '<div>#=messages.end#: #=kendo.toString(end, format)#</div>' + '</div>' + '</div>');
        var PERCENT_RESIZE_TOOLTIP_TEMPLATE = kendo.template('<div style="z-index: 100002;" class="#=styles.tooltipWrapper#" >' + '<div class="#=styles.tooltipContent#">#=text#%</div>' + '<div class="#=styles.tooltipCallout#" style="left:13px;"></div>' + '</div>');
        var TASK_TOOLTIP_TEMPLATE = kendo.template('<div class="#=kendo.htmlEncode(styles.taskDetails)#">' + '<strong>#=kendo.htmlEncode(task.title)#</strong>' + '<div class="#=styles.taskDetailsPercent#">#=kendo.toString(task.percentComplete, "p0")#</div>' + '<ul class="#=styles.reset#">' + '<li>#=messages.start#: #=kendo.toString(task.start, "h:mm tt ddd, MMM d")#</li>' + '<li>#=messages.end#: #=kendo.toString(task.end, "h:mm tt ddd, MMM d")#</li>' + '</ul>' + '</div>');
        var SIZE_CALCULATION_TEMPLATE = '<table style=\'visibility: hidden;\'>' + '<tbody>' + '<tr style=\'height:{0}\'>' + '<td>&nbsp;</td>' + '</tr>' + '</tbody>' + '</table>';
        var defaultViews = {
            day: { type: 'kendo.ui.GanttDayView' },
            week: { type: 'kendo.ui.GanttWeekView' },
            month: { type: 'kendo.ui.GanttMonthView' },
            year: { type: 'kendo.ui.GanttYearView' }
        };
        function trimOptions(options) {
            delete options.name;
            delete options.prefix;
            delete options.views;
            return options;
        }
        function getWorkDays(options) {
            var workDays = [];
            var dayIndex = options.workWeekStart;
            workDays.push(dayIndex);
            while (options.workWeekEnd != dayIndex) {
                if (dayIndex > 6) {
                    dayIndex -= 7;
                } else {
                    dayIndex++;
                }
                workDays.push(dayIndex);
            }
            return workDays;
        }
        function blurActiveElement() {
            var activeElement = kendo._activeElement();
            if (activeElement && activeElement.nodeName.toLowerCase() !== 'body') {
                $(activeElement).blur();
            }
        }
        var viewStyles = {
            alt: 'k-alt',
            reset: 'k-reset',
            nonWorking: 'k-nonwork-hour',
            header: 'k-header',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            tasksWrapper: 'k-gantt-tables',
            rowsTable: 'k-gantt-rows',
            columnsTable: 'k-gantt-columns',
            tasksTable: 'k-gantt-tasks',
            dependenciesWrapper: 'k-gantt-dependencies',
            resource: 'k-resource',
            resourceAlt: 'k-resource k-alt',
            task: 'k-task',
            taskSingle: 'k-task-single',
            taskMilestone: 'k-task-milestone',
            taskSummary: 'k-task-summary',
            taskWrap: 'k-task-wrap',
            taskMilestoneWrap: 'k-milestone-wrap',
            resourcesWrap: 'k-resources-wrap',
            taskDot: 'k-task-dot',
            taskDotStart: 'k-task-start',
            taskDotEnd: 'k-task-end',
            taskDragHandle: 'k-task-draghandle',
            taskContent: 'k-task-content',
            taskTemplate: 'k-task-template',
            taskActions: 'k-task-actions',
            taskDelete: 'k-task-delete',
            taskComplete: 'k-task-complete',
            taskDetails: 'k-task-details',
            taskDetailsPercent: 'k-task-pct',
            link: 'k-link',
            icon: 'k-icon',
            iconDelete: 'k-i-close',
            taskResizeHandle: 'k-resize-handle',
            taskResizeHandleWest: 'k-resize-w',
            taskResizeHandleEast: 'k-resize-e',
            taskSummaryProgress: 'k-task-summary-progress',
            taskSummaryComplete: 'k-task-summary-complete',
            line: 'k-line',
            lineHorizontal: 'k-line-h',
            lineVertical: 'k-line-v',
            arrowWest: 'k-arrow-w',
            arrowEast: 'k-arrow-e',
            dragHint: 'k-drag-hint',
            dependencyHint: 'k-dependency-hint',
            tooltipWrapper: 'k-widget k-tooltip k-popup k-group k-reset',
            tooltipContent: 'k-tooltip-content',
            tooltipCallout: 'k-callout k-callout-s',
            callout: 'k-callout',
            marquee: 'k-marquee k-gantt-marquee',
            marqueeColor: 'k-marquee-color'
        };
        var GanttView = kendo.ui.GanttView = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.title = this.options.title || this.options.name;
                this.header = this.element.find(DOT + GanttView.styles.gridHeader);
                this.content = this.element.find(DOT + GanttView.styles.gridContent);
                this.contentWidth = this.content.width();
                this._workDays = getWorkDays(this.options);
                this._headerTree = options.headerTree;
                this._taskTree = options.taskTree;
                this._taskTemplate = options.taskTemplate ? kendo.template(options.taskTemplate, extend({}, kendo.Template, options.templateSettings)) : null;
                this._dependencyTree = options.dependencyTree;
                this._taskCoordinates = {};
                this._currentTime();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                clearTimeout(this._tooltipTimeout);
                this.headerRow = null;
                this.header = null;
                this.content = null;
                this._dragHint = null;
                this._resizeHint = null;
                this._resizeTooltip = null;
                this._taskTooltip = null;
                this._percentCompleteResizeTooltip = null;
                this._headerTree = null;
                this._taskTree = null;
                this._dependencyTree = null;
            },
            options: {
                showWorkHours: false,
                showWorkDays: false,
                workDayStart: new Date(1980, 1, 1, 8, 0, 0),
                workDayEnd: new Date(1980, 1, 1, 17, 0, 0),
                workWeekStart: 1,
                workWeekEnd: 5,
                hourSpan: 1,
                slotSize: 100,
                currentTimeMarker: { updateInterval: 10000 }
            },
            renderLayout: function () {
                this._slots = this._createSlots();
                this._tableWidth = this._calculateTableWidth();
                this.createLayout(this._layout());
                this._slotDimensions();
                this._adjustHeight();
                this.content.find(DOT + GanttView.styles.dependenciesWrapper).width(this._tableWidth);
            },
            _adjustHeight: function () {
                if (this.content) {
                    this.content.height(this.element.height() - outerHeight(this.header));
                }
            },
            createLayout: function (rows) {
                var headers = this._headers(rows);
                var colgroup = this._colgroup();
                var tree = this._headerTree;
                var header = kendoDomElement('thead', null, headers);
                var table = kendoDomElement('table', { style: { width: this._tableWidth + 'px' } }, [
                    colgroup,
                    header
                ]);
                tree.render([table]);
                this.headerRow = this.header.find('table:first tr').last();
            },
            _slotDimensions: function () {
                var headers = this.headerRow[0].children;
                var slots = this._timeSlots();
                var slot;
                var header;
                for (var i = 0, length = headers.length; i < length; i++) {
                    header = headers[i];
                    slot = slots[i];
                    slot.offsetLeft = header.offsetLeft;
                    slot.offsetWidth = header.offsetWidth;
                }
            },
            render: function (tasks) {
                var taskCount = tasks.length;
                var styles = GanttView.styles;
                var contentTable;
                var rowsTable = this._rowsTable(taskCount);
                var columnsTable = this._columnsTable(taskCount);
                var tasksTable = this._tasksTable(tasks);
                var currentTimeMarker = this.options.currentTimeMarker;
                var calculatedSize = this.options.calculatedSize;
                var totalHeight;
                this._taskTree.render([
                    rowsTable,
                    columnsTable,
                    tasksTable
                ]);
                contentTable = this.content.find(DOT + styles.rowsTable);
                if (calculatedSize) {
                    totalHeight = calculatedSize.row * tasks.length;
                    this.content.find(DOT + styles.tasksTable).height(totalHeight);
                    contentTable.height(totalHeight);
                }
                this._contentHeight = contentTable.height();
                this._rowHeight = calculatedSize ? calculatedSize.row : this._contentHeight / contentTable.find('tr').length;
                this.content.find(DOT + styles.columnsTable).height(this._contentHeight);
                if (currentTimeMarker !== false && currentTimeMarker.updateInterval !== undefined) {
                    this._renderCurrentTime();
                }
            },
            _rowsTable: function (rowCount) {
                var rows = [];
                var row;
                var styles = GanttView.styles;
                var attributes = [
                    null,
                    { className: styles.alt }
                ];
                for (var i = 0; i < rowCount; i++) {
                    row = kendoDomElement('tr', attributes[i % 2], [kendoDomElement('td', null, [kendoTextElement('\xA0')])]);
                    rows.push(row);
                }
                return this._createTable(1, rows, { className: styles.rowsTable });
            },
            _columnsTable: function () {
                var cells = [];
                var row;
                var styles = GanttView.styles;
                var slots = this._timeSlots();
                var slotsCount = slots.length;
                var slot;
                var slotSpan;
                var totalSpan = 0;
                var attributes;
                for (var i = 0; i < slotsCount; i++) {
                    slot = slots[i];
                    attributes = {};
                    slotSpan = slot.span;
                    totalSpan += slotSpan;
                    if (slotSpan !== 1) {
                        attributes.colspan = slotSpan;
                    }
                    if (slot.isNonWorking) {
                        attributes.className = styles.nonWorking;
                    }
                    cells.push(kendoDomElement('td', attributes, [kendoTextElement('\xA0')]));
                }
                row = kendoDomElement('tr', null, cells);
                return this._createTable(totalSpan, [row], { className: styles.columnsTable });
            },
            _tasksTable: function (tasks) {
                var rows = [];
                var row;
                var cell;
                var position;
                var task;
                var styles = GanttView.styles;
                var coordinates = this._taskCoordinates = {};
                var size = this._calculateMilestoneWidth();
                var milestoneWidth = Math.round(size.width);
                var resourcesField = this.options.resourcesField;
                var className = [
                    styles.resource,
                    styles.resourceAlt
                ];
                var calculatedSize = this.options.calculatedSize;
                var resourcesPosition;
                var resourcesMargin = this._calculateResourcesMargin();
                var taskBorderWidth = this._calculateTaskBorderWidth();
                var resourceStyle;
                var addCoordinates = function (rowIndex) {
                    var taskLeft;
                    var taskRight;
                    taskLeft = position.left;
                    taskRight = taskLeft + position.width;
                    if (task.isMilestone()) {
                        taskLeft -= milestoneWidth / 2;
                        taskRight = taskLeft + milestoneWidth;
                    }
                    coordinates[task.id] = {
                        start: taskLeft,
                        end: taskRight,
                        rowIndex: rowIndex
                    };
                };
                for (var i = 0, l = tasks.length; i < l; i++) {
                    task = tasks[i];
                    position = this._taskPosition(task);
                    position.borderWidth = taskBorderWidth;
                    row = kendoDomElement('tr', null);
                    cell = kendoDomElement('td');
                    if (task.start <= this.end && task.end >= this.start) {
                        cell.children.push(this._renderTask(tasks[i], position));
                        if (task[resourcesField] && task[resourcesField].length) {
                            if (isRtl) {
                                resourcesPosition = this._tableWidth - position.left;
                            } else {
                                resourcesPosition = Math.max(position.width || size.clientWidth, 0) + position.left;
                            }
                            resourceStyle = { width: this._tableWidth - (resourcesPosition + resourcesMargin) + 'px' };
                            resourceStyle[isRtl ? 'right' : 'left'] = resourcesPosition + 'px';
                            if (calculatedSize) {
                                resourceStyle.height = calculatedSize.cell + 'px';
                            }
                            cell.children.push(kendoDomElement('div', {
                                className: styles.resourcesWrap,
                                style: resourceStyle
                            }, this._renderResources(task[resourcesField], className[i % 2])));
                        }
                        addCoordinates(i);
                    }
                    row.children.push(cell);
                    rows.push(row);
                }
                return this._createTable(1, rows, { className: GanttView.styles.tasksTable });
            },
            _createTable: function (colspan, rows, styles) {
                var cols = [];
                var colgroup;
                var tbody;
                for (var i = 0; i < colspan; i++) {
                    cols.push(kendoDomElement('col'));
                }
                colgroup = kendoDomElement('colgroup', null, cols);
                tbody = kendoDomElement('tbody', null, rows);
                if (!styles.style) {
                    styles.style = {};
                }
                styles.style.width = this._tableWidth + 'px';
                return kendoDomElement('table', styles, [
                    colgroup,
                    tbody
                ]);
            },
            _calculateTableWidth: function () {
                var slots = this._timeSlots();
                var maxSpan = 0;
                var totalSpan = 0;
                var currentSpan;
                var tableWidth;
                for (var i = 0, length = slots.length; i < length; i++) {
                    currentSpan = slots[i].span;
                    totalSpan += currentSpan;
                    if (currentSpan > maxSpan) {
                        maxSpan = currentSpan;
                    }
                }
                tableWidth = Math.round(totalSpan * this.options.slotSize / maxSpan);
                return tableWidth;
            },
            _calculateMilestoneWidth: function () {
                var size;
                var className = GanttView.styles.task + ' ' + GanttView.styles.taskMilestone;
                var milestone = $('<div class=\'' + className + '\' style=\'visibility: hidden; position: absolute\'>');
                var boundingClientRect;
                this.content.append(milestone);
                boundingClientRect = milestone[0].getBoundingClientRect();
                size = {
                    'width': boundingClientRect.right - boundingClientRect.left,
                    'clientWidth': milestone[0].clientWidth
                };
                milestone.remove();
                return size;
            },
            _calculateResourcesMargin: function () {
                var margin;
                var wrapper = $('<div class=\'' + GanttView.styles.resourcesWrap + '\' style=\'visibility: hidden; position: absolute\'>');
                this.content.append(wrapper);
                margin = parseInt(wrapper.css(isRtl ? 'margin-right' : 'margin-left'), 10);
                wrapper.remove();
                return margin;
            },
            _calculateTaskBorderWidth: function () {
                var width;
                var className = GanttView.styles.task + ' ' + GanttView.styles.taskSingle;
                var task = $('<div class=\'' + className + '\' style=\'visibility: hidden; position: absolute\'>');
                var computedStyle;
                this.content.append(task);
                computedStyle = kendo.getComputedStyles(task[0], ['border-left-width']);
                width = parseFloat(computedStyle['border-left-width'], 10);
                task.remove();
                return width;
            },
            _renderTask: function (task, position) {
                var taskWrapper;
                var taskElement;
                var editable = this.options.editable;
                var progressHandleOffset;
                var taskLeft = position.left;
                var styles = GanttView.styles;
                var wrapClassName = styles.taskWrap;
                var calculatedSize = this.options.calculatedSize;
                var dragHandleStyle = {};
                var taskWrapAttr = {
                    className: wrapClassName,
                    style: { left: taskLeft + 'px' }
                };
                if (calculatedSize) {
                    taskWrapAttr.style.height = calculatedSize.cell + 'px';
                }
                if (task.summary) {
                    taskElement = this._renderSummary(task, position);
                } else if (task.isMilestone()) {
                    taskElement = this._renderMilestone(task, position);
                    taskWrapAttr.className += ' ' + styles.taskMilestoneWrap;
                } else {
                    taskElement = this._renderSingleTask(task, position);
                }
                taskWrapper = kendoDomElement('div', taskWrapAttr, [taskElement]);
                if (editable && editable.dependencyCreate !== false) {
                    taskWrapper.children.push(kendoDomElement('div', { className: styles.taskDot + ' ' + styles.taskDotStart }));
                    taskWrapper.children.push(kendoDomElement('div', { className: styles.taskDot + ' ' + styles.taskDotEnd }));
                }
                if (!task.summary && !task.isMilestone() && editable && editable.dragPercentComplete !== false && editable.update !== false && this._taskTemplate === null) {
                    progressHandleOffset = Math.round(position.width * task.percentComplete);
                    dragHandleStyle[isRtl ? 'right' : 'left'] = progressHandleOffset + 'px';
                    taskWrapper.children.push(kendoDomElement('div', {
                        className: styles.taskDragHandle,
                        style: dragHandleStyle
                    }));
                }
                return taskWrapper;
            },
            _renderSingleTask: function (task, position) {
                var styles = GanttView.styles;
                var progressWidth = Math.round(position.width * task.percentComplete);
                var taskChildren = [];
                var taskContent;
                var editable = this.options.editable;
                if (this._taskTemplate !== null) {
                    taskContent = kendoHtmlElement(this._taskTemplate(task));
                } else {
                    taskContent = kendoTextElement(task.title);
                    taskChildren.push(kendoDomElement('div', {
                        className: styles.taskComplete,
                        style: { width: progressWidth + 'px' }
                    }));
                }
                var content = kendoDomElement('div', { className: styles.taskContent }, [kendoDomElement('div', { className: styles.taskTemplate }, [taskContent])]);
                taskChildren.push(content);
                if (editable) {
                    if (editable.destroy !== false) {
                        content.children.push(kendoDomElement('span', { className: styles.taskActions }, [kendoDomElement('a', {
                                className: styles.link + ' ' + styles.taskDelete,
                                href: '#',
                                'aria-label': 'Delete'
                            }, [kendoDomElement('span', { className: styles.icon + ' ' + styles.iconDelete })])]));
                    }
                    if (editable.resize !== false && editable.update !== false) {
                        content.children.push(kendoDomElement('span', { className: styles.taskResizeHandle + ' ' + styles.taskResizeHandleWest }));
                        content.children.push(kendoDomElement('span', { className: styles.taskResizeHandle + ' ' + styles.taskResizeHandleEast }));
                    }
                }
                var element = kendoDomElement('div', {
                    className: styles.task + ' ' + styles.taskSingle,
                    'data-uid': task.uid,
                    style: { width: Math.max(position.width - position.borderWidth * 2, 0) + 'px' }
                }, taskChildren);
                return element;
            },
            _renderMilestone: function (task) {
                var styles = GanttView.styles;
                var element = kendoDomElement('div', {
                    className: styles.task + ' ' + styles.taskMilestone,
                    'data-uid': task.uid
                });
                return element;
            },
            _renderSummary: function (task, position) {
                var styles = GanttView.styles;
                var progressWidth = Math.round(position.width * task.percentComplete);
                var element = kendoDomElement('div', {
                    className: styles.task + ' ' + styles.taskSummary,
                    'data-uid': task.uid,
                    style: { width: position.width + 'px' }
                }, [kendoDomElement('div', {
                        className: styles.taskSummaryProgress,
                        style: { width: progressWidth + 'px' }
                    }, [kendoDomElement('div', {
                            className: styles.taskSummaryComplete,
                            style: { width: position.width + 'px' }
                        })])]);
                return element;
            },
            _renderResources: function (resources, className) {
                var children = [];
                var resource;
                for (var i = 0, length = resources.length; i < length; i++) {
                    resource = resources[i];
                    children.push(kendoDomElement('span', {
                        className: className,
                        style: { 'color': resource.get('color') }
                    }, [kendoTextElement(resource.get('name'))]));
                }
                if (isRtl) {
                    children.reverse();
                }
                return children;
            },
            _taskPosition: function (task) {
                var round = Math.round;
                var startLeft = round(this._offset(isRtl ? task.end : task.start));
                var endLeft = round(this._offset(isRtl ? task.start : task.end));
                return {
                    left: startLeft,
                    width: endLeft - startLeft
                };
            },
            _offset: function (date) {
                var slots = this._timeSlots();
                var slot;
                var startOffset;
                var slotDuration;
                var slotOffset = 0;
                var startIndex;
                if (!slots.length) {
                    return 0;
                }
                startIndex = this._slotIndex('start', date);
                slot = slots[startIndex];
                if (slot.end < date) {
                    slotOffset = slot.offsetWidth;
                } else if (slot.start <= date) {
                    startOffset = date - slot.start;
                    slotDuration = slot.end - slot.start;
                    slotOffset = startOffset / slotDuration * slot.offsetWidth;
                }
                if (isRtl) {
                    slotOffset = slot.offsetWidth + 1 - slotOffset;
                }
                return slot.offsetLeft + slotOffset;
            },
            _slotIndex: function (field, value, reverse) {
                var slots = this._timeSlots();
                var startIdx = 0;
                var endIdx = slots.length - 1;
                var middle;
                if (reverse) {
                    slots = [].slice.call(slots).reverse();
                }
                do {
                    middle = Math.ceil((endIdx + startIdx) / 2);
                    if (slots[middle][field] < value) {
                        startIdx = middle;
                    } else {
                        if (middle === endIdx) {
                            middle--;
                        }
                        endIdx = middle;
                    }
                } while (startIdx !== endIdx);
                if (reverse) {
                    startIdx = slots.length - 1 - startIdx;
                }
                return startIdx;
            },
            _timeByPosition: function (x, snap, snapToEnd) {
                var slot = this._slotByPosition(x);
                if (snap) {
                    return snapToEnd ? slot.end : slot.start;
                }
                var offsetLeft = x - $(DOT + GanttView.styles.tasksTable).offset().left;
                var duration = slot.end - slot.start;
                var slotOffset = offsetLeft - slot.offsetLeft;
                if (isRtl) {
                    slotOffset = slot.offsetWidth - slotOffset;
                }
                return new Date(slot.start.getTime() + duration * (slotOffset / slot.offsetWidth));
            },
            _slotByPosition: function (x) {
                var offsetLeft = x - $(DOT + GanttView.styles.tasksTable).offset().left;
                var slotIndex = this._slotIndex('offsetLeft', offsetLeft, isRtl);
                return this._timeSlots()[slotIndex];
            },
            _renderDependencies: function (dependencies) {
                var elements = [];
                var tree = this._dependencyTree;
                for (var i = 0, l = dependencies.length; i < l; i++) {
                    elements.push.apply(elements, this._renderDependency(dependencies[i]));
                }
                tree.render(elements);
            },
            _renderDependency: function (dependency) {
                var predecessor = this._taskCoordinates[dependency.predecessorId];
                var successor = this._taskCoordinates[dependency.successorId];
                var elements;
                var method;
                if (!predecessor || !successor) {
                    return [];
                }
                method = '_render' + [
                    'FF',
                    'FS',
                    'SF',
                    'SS'
                ][isRtl ? 3 - dependency.type : dependency.type];
                elements = this[method](predecessor, successor);
                for (var i = 0, length = elements.length; i < length; i++) {
                    elements[i].attr['data-uid'] = dependency.uid;
                }
                return elements;
            },
            _renderFF: function (from, to) {
                var lines = this._dependencyFF(from, to, false);
                lines[lines.length - 1].children[0] = this._arrow(true);
                return lines;
            },
            _renderSS: function (from, to) {
                var lines = this._dependencyFF(to, from, true);
                lines[0].children[0] = this._arrow(false);
                return lines.reverse();
            },
            _renderFS: function (from, to) {
                var lines = this._dependencyFS(from, to, false);
                lines[lines.length - 1].children[0] = this._arrow(false);
                return lines;
            },
            _renderSF: function (from, to) {
                var lines = this._dependencyFS(to, from, true);
                lines[0].children[0] = this._arrow(true);
                return lines.reverse();
            },
            _dependencyFF: function (from, to, reverse) {
                var that = this;
                var lines = [];
                var left = 0;
                var top = 0;
                var width = 0;
                var height = 0;
                var dir = reverse ? 'start' : 'end';
                var delta;
                var overlap = 2;
                var arrowOverlap = 1;
                var rowHeight = this._rowHeight;
                var minLineWidth = 10;
                var fromTop = from.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
                var toTop = to.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
                var styles = GanttView.styles;
                var addHorizontal = function () {
                    lines.push(that._line(styles.line + ' ' + styles.lineHorizontal, {
                        left: left + 'px',
                        top: top + 'px',
                        width: width + 'px'
                    }));
                };
                var addVertical = function () {
                    lines.push(that._line(styles.line + ' ' + styles.lineVertical, {
                        left: left + 'px',
                        top: top + 'px',
                        height: height + 'px'
                    }));
                };
                left = from[dir];
                top = fromTop;
                width = minLineWidth;
                delta = to[dir] - from[dir];
                if (delta > 0 !== reverse) {
                    width = Math.abs(delta) + minLineWidth;
                }
                if (reverse) {
                    left -= width;
                    width -= arrowOverlap;
                    addHorizontal();
                } else {
                    addHorizontal();
                    left += width - overlap;
                }
                if (toTop < top) {
                    height = top - toTop;
                    height += overlap;
                    top = toTop;
                    addVertical();
                } else {
                    height = toTop - top;
                    height += overlap;
                    addVertical();
                    top += height - overlap;
                }
                width = Math.abs(left - to[dir]);
                if (!reverse) {
                    width -= arrowOverlap;
                    left -= width;
                }
                addHorizontal();
                return lines;
            },
            _dependencyFS: function (from, to, reverse) {
                var that = this;
                var lines = [];
                var left = 0;
                var top = 0;
                var width = 0;
                var height = 0;
                var rowHeight = this._rowHeight;
                var minLineHeight = Math.floor(rowHeight / 2);
                var minLineWidth = 10;
                var minDistance = 2 * minLineWidth;
                var delta = to.start - from.end;
                var overlap = 2;
                var arrowOverlap = 1;
                var fromTop = from.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
                var toTop = to.rowIndex * rowHeight + Math.floor(rowHeight / 2) - 1;
                var styles = GanttView.styles;
                var addHorizontal = function () {
                    lines.push(that._line(styles.line + ' ' + styles.lineHorizontal, {
                        left: left + 'px',
                        top: top + 'px',
                        width: width + 'px'
                    }));
                };
                var addVertical = function () {
                    lines.push(that._line(styles.line + ' ' + styles.lineVertical, {
                        left: left + 'px',
                        top: top + 'px',
                        height: height + 'px'
                    }));
                };
                left = from.end;
                top = fromTop;
                width = minLineWidth;
                if (reverse) {
                    left += arrowOverlap;
                    if (delta > minDistance) {
                        width = delta - (minLineWidth - overlap);
                    }
                    width -= arrowOverlap;
                }
                addHorizontal();
                left += width - overlap;
                if (delta <= minDistance) {
                    height = reverse ? Math.abs(toTop - fromTop) - minLineHeight : minLineHeight;
                    if (toTop < fromTop) {
                        top -= height;
                        height += overlap;
                        addVertical();
                    } else {
                        addVertical();
                        top += height;
                    }
                    width = from.end - to.start + minDistance;
                    if (width < minLineWidth) {
                        width = minLineWidth;
                    }
                    left -= width - overlap;
                    addHorizontal();
                }
                if (toTop < fromTop) {
                    height = top - toTop;
                    top = toTop;
                    height += overlap;
                    addVertical();
                } else {
                    height = toTop - top;
                    addVertical();
                    top += height;
                }
                width = to.start - left;
                if (!reverse) {
                    width -= arrowOverlap;
                }
                addHorizontal();
                return lines;
            },
            _line: function (className, styles) {
                return kendoDomElement('div', {
                    className: className,
                    style: styles
                });
            },
            _arrow: function (direction) {
                return kendoDomElement('span', { className: direction ? GanttView.styles.arrowWest : GanttView.styles.arrowEast });
            },
            _colgroup: function () {
                var slots = this._timeSlots();
                var count = slots.length;
                var cols = [];
                for (var i = 0; i < count; i++) {
                    for (var j = 0, length = slots[i].span; j < length; j++) {
                        cols.push(kendoDomElement('col'));
                    }
                }
                return kendoDomElement('colgroup', null, cols);
            },
            _createDragHint: function (element) {
                this._dragHint = element.clone().addClass(GanttView.styles.dragHint).css('cursor', 'move');
                element.parent().append(this._dragHint);
            },
            _updateDragHint: function (start) {
                var left = this._offset(start);
                this._dragHint.css({ 'left': left });
            },
            _removeDragHint: function () {
                this._dragHint.remove();
                this._dragHint = null;
            },
            _createResizeHint: function (task) {
                var styles = GanttView.styles;
                var taskTop = this._taskCoordinates[task.id].rowIndex * this._rowHeight;
                var tooltipHeight;
                var tooltipTop;
                var options = this.options;
                var messages = options.messages;
                this._resizeHint = $(RESIZE_HINT({ styles: styles })).css({
                    'top': 0,
                    'height': this._contentHeight
                });
                this.content.append(this._resizeHint);
                this._resizeTooltip = $(RESIZE_TOOLTIP_TEMPLATE({
                    styles: styles,
                    start: task.start,
                    end: task.end,
                    messages: messages.views,
                    format: options.resizeTooltipFormat
                })).css({
                    'top': 0,
                    'left': 0
                });
                this.content.append(this._resizeTooltip);
                this._resizeTooltipWidth = outerWidth(this._resizeTooltip);
                tooltipHeight = outerHeight(this._resizeTooltip);
                tooltipTop = taskTop - tooltipHeight;
                if (tooltipTop < 0) {
                    tooltipTop = taskTop + this._rowHeight;
                }
                this._resizeTooltipTop = tooltipTop;
            },
            _updateResizeHint: function (start, end, resizeStart) {
                var left = this._offset(isRtl ? end : start);
                var right = this._offset(isRtl ? start : end);
                var width = right - left;
                var tooltipLeft = resizeStart !== isRtl ? left : right;
                var tablesWidth = this._tableWidth - kendo.support.scrollbar();
                var tooltipWidth = this._resizeTooltipWidth;
                var options = this.options;
                var messages = options.messages;
                var tableOffset = $(DOT + GanttView.styles.tasksTable).offset().left - $(DOT + GanttView.styles.tasksWrapper).offset().left;
                if (isRtl) {
                    left += tableOffset;
                }
                this._resizeHint.css({
                    'left': left,
                    'width': width
                });
                if (this._resizeTooltip) {
                    this._resizeTooltip.remove();
                }
                tooltipLeft -= Math.round(tooltipWidth / 2);
                if (tooltipLeft < 0) {
                    tooltipLeft = 0;
                } else if (tooltipLeft + tooltipWidth > tablesWidth) {
                    tooltipLeft = tablesWidth - tooltipWidth;
                }
                if (isRtl) {
                    tooltipLeft += tableOffset;
                }
                this._resizeTooltip = $(RESIZE_TOOLTIP_TEMPLATE({
                    styles: GanttView.styles,
                    start: start,
                    end: end,
                    messages: messages.views,
                    format: options.resizeTooltipFormat
                })).css({
                    'top': this._resizeTooltipTop,
                    'left': tooltipLeft,
                    'min-width': tooltipWidth
                }).appendTo(this.content);
            },
            _removeResizeHint: function () {
                this._resizeHint.remove();
                this._resizeHint = null;
                this._resizeTooltip.remove();
                this._resizeTooltip = null;
            },
            _updatePercentCompleteTooltip: function (top, left, text) {
                this._removePercentCompleteTooltip();
                var tooltip = this._percentCompleteResizeTooltip = $(PERCENT_RESIZE_TOOLTIP_TEMPLATE({
                    styles: GanttView.styles,
                    text: text
                })).appendTo(this.element);
                var tooltipMiddle = Math.round(outerWidth(tooltip) / 2);
                var arrow = tooltip.find(DOT + GanttView.styles.callout);
                var arrowHeight = Math.round(outerWidth(arrow) / 2);
                tooltip.css({
                    'top': top - (outerHeight(tooltip) + arrowHeight),
                    'left': left - tooltipMiddle
                });
                arrow.css('left', tooltipMiddle - arrowHeight);
            },
            _removePercentCompleteTooltip: function () {
                if (this._percentCompleteResizeTooltip) {
                    this._percentCompleteResizeTooltip.remove();
                }
                this._percentCompleteResizeTooltip = null;
            },
            _updateDependencyDragHint: function (from, to, useVML) {
                this._removeDependencyDragHint();
                if (useVML) {
                    this._creteVmlDependencyDragHint(from, to);
                } else {
                    this._creteDependencyDragHint(from, to);
                }
            },
            _creteDependencyDragHint: function (from, to) {
                var styles = GanttView.styles;
                var deltaX = to.x - from.x;
                var deltaY = to.y - from.y;
                var width = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
                var angle = Math.atan(deltaY / deltaX);
                if (deltaX < 0) {
                    angle += Math.PI;
                }
                $('<div class=\'' + styles.line + ' ' + styles.lineHorizontal + ' ' + styles.dependencyHint + '\'></div>').css({
                    'top': from.y,
                    'left': from.x,
                    'width': width,
                    'transform-origin': '0% 0',
                    '-ms-transform-origin': '0% 0',
                    '-webkit-transform-origin': '0% 0',
                    'transform': 'rotate(' + angle + 'rad)',
                    '-ms-transform': 'rotate(' + angle + 'rad)',
                    '-webkit-transform': 'rotate(' + angle + 'rad)'
                }).appendTo(this.content);
            },
            _creteVmlDependencyDragHint: function (from, to) {
                var hint = $('<kvml:line class=\'' + GanttView.styles.dependencyHint + '\' style=\'position:absolute; top: 0px; left: 0px;\' strokecolor=\'black\' strokeweight=\'2px\' from=\'' + from.x + 'px,' + from.y + 'px\' to=\'' + to.x + 'px,' + to.y + 'px\'' + '></kvml:line>').appendTo(this.content);
                hint[0].outerHTML = hint[0].outerHTML;
            },
            _removeDependencyDragHint: function () {
                this.content.find(DOT + GanttView.styles.dependencyHint).remove();
            },
            _createTaskTooltip: function (task, element, mouseLeft) {
                var styles = GanttView.styles;
                var options = this.options;
                var content = this.content;
                var contentOffset = content.offset();
                var contentWidth = content.width();
                var contentScrollLeft = kendo.scrollLeft(content);
                var row = $(element).parents('tr').first();
                var rowOffset = row.offset();
                var template = options.tooltip && options.tooltip.template ? kendo.template(options.tooltip.template) : TASK_TOOLTIP_TEMPLATE;
                var left = isRtl ? mouseLeft - (contentOffset.left + contentScrollLeft + kendo.support.scrollbar()) : mouseLeft - (contentOffset.left - contentScrollLeft);
                var top = rowOffset.top + outerHeight(row) - contentOffset.top + content.scrollTop();
                var tooltip = this._taskTooltip = $('<div style="z-index: 100002;" class="' + styles.tooltipWrapper + '" >' + '<div class="' + styles.taskContent + '"></div></div>');
                var tooltipWidth;
                tooltip.css({
                    'left': left,
                    'top': top
                }).appendTo(content).find(DOT + styles.taskContent).append(template({
                    styles: styles,
                    task: task,
                    messages: options.messages.views
                }));
                if (outerHeight(tooltip) < rowOffset.top - contentOffset.top) {
                    tooltip.css('top', rowOffset.top - contentOffset.top - outerHeight(tooltip) + content.scrollTop());
                }
                tooltipWidth = outerWidth(tooltip);
                if (tooltipWidth + left - contentScrollLeft > contentWidth) {
                    left -= tooltipWidth;
                    if (left < contentScrollLeft) {
                        left = contentScrollLeft + contentWidth - (tooltipWidth + 17);
                    }
                    tooltip.css('left', left);
                }
            },
            _removeTaskTooltip: function () {
                if (this._taskTooltip) {
                    this._taskTooltip.remove();
                }
                this._taskTooltip = null;
            },
            _scrollTo: function (element) {
                var elementLeft = element.offset().left;
                var elementWidth = element.width();
                var elementRight = elementLeft + elementWidth;
                var row = element.closest('tr');
                var rowTop = row.offset().top;
                var rowHeight = row.height();
                var rowBottom = rowTop + rowHeight;
                var content = this.content;
                var contentOffset = content.offset();
                var contentTop = contentOffset.top;
                var contentHeight = content.height();
                var contentBottom = contentTop + contentHeight;
                var contentLeft = contentOffset.left;
                var contentWidth = content.width();
                var contentRight = contentLeft + contentWidth;
                var scrollbarWidth = kendo.support.scrollbar();
                if (rowTop < contentTop) {
                    content.scrollTop(content.scrollTop() + (rowTop - contentTop));
                } else if (rowBottom > contentBottom) {
                    content.scrollTop(content.scrollTop() + (rowBottom + scrollbarWidth - contentBottom));
                }
                if (elementLeft < contentLeft && elementWidth > contentWidth && elementRight < contentRight || elementRight > contentRight && elementWidth < contentWidth) {
                    content.scrollLeft(content.scrollLeft() + (elementRight + scrollbarWidth - contentRight));
                } else if (elementRight > contentRight && elementWidth > contentWidth && elementLeft > contentLeft || elementLeft < contentLeft && elementWidth < contentWidth) {
                    content.scrollLeft(content.scrollLeft() + (elementLeft - contentLeft));
                }
            },
            _scrollToDate: function (date) {
                var viewStart = this.start;
                var viewEnd = this.end;
                var offset;
                if (date >= viewStart && date < viewEnd) {
                    offset = this._offset(date);
                    if (kendo.support.isRtl(this.element)) {
                        offset = this._tableWidth - offset;
                    }
                    kendo.scrollLeft(this.content, offset);
                }
            },
            _timeSlots: function () {
                if (!this._slots || !this._slots.length) {
                    return [];
                }
                return this._slots[this._slots.length - 1];
            },
            _headers: function (columnLevels) {
                var rows = [];
                var level;
                var headers;
                var column;
                var headerText;
                var styles = GanttView.styles;
                for (var levelIndex = 0, levelCount = columnLevels.length; levelIndex < levelCount; levelIndex++) {
                    level = columnLevels[levelIndex];
                    headers = [];
                    for (var columnIndex = 0, columnCount = level.length; columnIndex < columnCount; columnIndex++) {
                        column = level[columnIndex];
                        headerText = kendoTextElement(column.text);
                        headers.push(kendoDomElement('th', {
                            colspan: column.span,
                            className: styles.header + (column.isNonWorking ? ' ' + styles.nonWorking : '')
                        }, [headerText]));
                    }
                    rows.push(kendoDomElement('tr', null, headers));
                }
                return rows;
            },
            _hours: function (start, end) {
                var slotEnd;
                var slots = [];
                var options = this.options;
                var workDayStart = options.workDayStart.getHours();
                var workDayEnd = options.workDayEnd.getHours();
                var isWorkHour;
                var hours;
                var hourSpan = options.hourSpan;
                start = new Date(start);
                end = new Date(end);
                while (start < end) {
                    slotEnd = new Date(start);
                    hours = slotEnd.getHours();
                    isWorkHour = hours >= workDayStart && hours < workDayEnd;
                    slotEnd.setHours(slotEnd.getHours() + hourSpan);
                    if (hours == slotEnd.getHours()) {
                        slotEnd.setHours(slotEnd.getHours() + 2 * hourSpan);
                    }
                    if (!options.showWorkHours || isWorkHour) {
                        slots.push({
                            start: start,
                            end: slotEnd,
                            isNonWorking: !isWorkHour,
                            span: 1
                        });
                    }
                    start = slotEnd;
                }
                return slots;
            },
            _days: function (start, end) {
                var slotEnd;
                var slots = [];
                var isWorkDay;
                start = new Date(start);
                end = new Date(end);
                while (start < end) {
                    slotEnd = end < kendo.date.nextDay(start) ? end : kendo.date.nextDay(start);
                    isWorkDay = this._isWorkDay(start);
                    if (!this.options.showWorkDays || isWorkDay) {
                        slots.push({
                            start: start,
                            end: slotEnd,
                            isNonWorking: !isWorkDay,
                            span: 1
                        });
                    }
                    start = slotEnd;
                }
                return slots;
            },
            _weeks: function (start, end) {
                var slotEnd;
                var slots = [];
                var firstDay = this.calendarInfo().firstDay;
                var daySlots;
                var span;
                start = new Date(start);
                end = new Date(end);
                while (start < end) {
                    slotEnd = kendo.date.dayOfWeek(kendo.date.addDays(start, 1), firstDay, 1);
                    if (slotEnd > end) {
                        slotEnd = end;
                    }
                    daySlots = this._days(start, slotEnd);
                    span = daySlots.length;
                    if (span > 0) {
                        slots.push({
                            start: daySlots[0].start,
                            end: daySlots[span - 1].end,
                            span: span
                        });
                    }
                    start = slotEnd;
                }
                return slots;
            },
            _months: function (start, end) {
                var slotEnd;
                var endMonth;
                var slots = [];
                var daySlots;
                var span;
                start = new Date(start);
                end = new Date(end);
                while (start < end) {
                    slotEnd = new Date(start);
                    endMonth = kendo.date.firstDayOfMonth(new Date(slotEnd.setMonth(slotEnd.getMonth() + 1)));
                    slotEnd = end < endMonth ? end : endMonth;
                    daySlots = this._days(start, slotEnd);
                    span = daySlots.length;
                    if (span > 0) {
                        slots.push({
                            start: daySlots[0].start,
                            end: daySlots[span - 1].end,
                            span: span
                        });
                    }
                    start = slotEnd;
                }
                return slots;
            },
            _years: function (start, end) {
                var slotEnd;
                var monthSpan;
                var endMonth;
                var slots = [];
                start = new Date(start);
                end = new Date(end);
                while (start < end) {
                    slotEnd = new Date(start);
                    slotEnd = kendo.date.firstDayOfMonth(new Date(slotEnd.setMonth(12)));
                    if (slotEnd >= end) {
                        slotEnd = end;
                    }
                    endMonth = slotEnd.getMonth() || 12;
                    monthSpan = endMonth - start.getMonth();
                    slots.push({
                        start: start,
                        end: slotEnd,
                        span: monthSpan
                    });
                    start = slotEnd;
                }
                return slots;
            },
            _slotHeaders: function (slots, template) {
                var columns = [];
                var slot;
                for (var i = 0, l = slots.length; i < l; i++) {
                    slot = slots[i];
                    columns.push({
                        text: template(slot),
                        isNonWorking: !!slot.isNonWorking,
                        span: slot.span
                    });
                }
                return columns;
            },
            _isWorkDay: function (date) {
                var day = date.getDay();
                var workDays = this._workDays;
                for (var i = 0, l = workDays.length; i < l; i++) {
                    if (workDays[i] === day) {
                        return true;
                    }
                }
                return false;
            },
            calendarInfo: function () {
                return kendo.getCulture().calendars.standard;
            },
            _renderCurrentTime: function () {
                var currentTime = this._getCurrentTime();
                var timeOffset = this._offset(currentTime);
                var element = $('<div class=\'k-current-time\'></div>');
                var viewStyles = GanttView.styles;
                var tablesWrap = $(DOT + viewStyles.tasksWrapper);
                var tasksTable = $(DOT + viewStyles.tasksTable);
                var slot;
                if (!this.content || !this._timeSlots().length) {
                    return;
                }
                this.content.find('.k-current-time').remove();
                slot = this._timeSlots()[this._slotIndex('start', currentTime)];
                if (currentTime < slot.start || currentTime > slot.end) {
                    return;
                }
                if (tablesWrap.length && tasksTable.length) {
                    timeOffset += tasksTable.offset().left - tablesWrap.offset().left;
                }
                element.css({
                    left: timeOffset + 'px',
                    top: '0px',
                    width: '1px',
                    height: this._contentHeight + 'px'
                }).appendTo(this.content);
            },
            _getCurrentTime: function () {
                return new Date();
            },
            _currentTime: function () {
                var markerOptions = this.options.currentTimeMarker;
                if (markerOptions !== false && markerOptions.updateInterval !== undefined) {
                    this._renderCurrentTime();
                    this._currentTimeUpdateTimer = setInterval(proxy(this._renderCurrentTime, this), markerOptions.updateInterval);
                }
            }
        });
        extend(true, GanttView, { styles: viewStyles });
        kendo.ui.GanttDayView = GanttView.extend({
            name: 'day',
            options: {
                timeHeaderTemplate: TIME_HEADER_TEMPLATE,
                dayHeaderTemplate: DAY_HEADER_TEMPLATE,
                resizeTooltipFormat: 'h:mm tt ddd, MMM d'
            },
            range: function (range) {
                var optionsRange = this.options.range;
                this.start = kendo.date.getDate(range.start);
                this.end = kendo.date.getDate(range.end);
                if (kendo.date.getMilliseconds(range.end) > 0 || this.end.getTime() === this.start.getTime()) {
                    this.end = kendo.date.addDays(this.end, 1);
                }
                if (optionsRange && optionsRange.start) {
                    this.start = kendo.date.getDate(optionsRange.start);
                    this.start.setHours(optionsRange.start.getHours());
                }
                if (optionsRange && optionsRange.end) {
                    this.end = kendo.date.getDate(optionsRange.end);
                    this.end.setHours(optionsRange.end.getHours());
                }
            },
            _createSlots: function () {
                var daySlots;
                var daySlot;
                var hourSlots;
                var hours;
                var slots = [];
                daySlots = this._days(this.start, this.end);
                hourSlots = [];
                for (var i = 0, l = daySlots.length; i < l; i++) {
                    daySlot = daySlots[i];
                    hours = this._hours(daySlot.start, daySlot.end);
                    daySlot.span = hours.length;
                    hourSlots.push.apply(hourSlots, hours);
                }
                slots.push(daySlots);
                slots.push(hourSlots);
                return slots;
            },
            _layout: function () {
                var rows = [];
                var options = this.options;
                rows.push(this._slotHeaders(this._slots[0], kendo.template(options.dayHeaderTemplate)));
                rows.push(this._slotHeaders(this._slots[1], kendo.template(options.timeHeaderTemplate)));
                return rows;
            }
        });
        kendo.ui.GanttWeekView = GanttView.extend({
            name: 'week',
            options: {
                dayHeaderTemplate: DAY_HEADER_TEMPLATE,
                weekHeaderTemplate: WEEK_HEADER_TEMPLATE,
                resizeTooltipFormat: 'h:mm tt ddd, MMM d'
            },
            range: function (range) {
                var optionsRange = this.options.range;
                var calendarInfo = this.calendarInfo();
                var firstDay = calendarInfo.firstDay;
                var rangeEnd = range.end;
                var endDay;
                if (firstDay === rangeEnd.getDay()) {
                    rangeEnd.setDate(rangeEnd.getDate() + 7);
                }
                this.start = kendo.date.getDate(kendo.date.dayOfWeek(range.start, firstDay, -1));
                this.end = kendo.date.getDate(kendo.date.dayOfWeek(rangeEnd, firstDay, 1));
                if (optionsRange && optionsRange.start) {
                    this.start = kendo.date.getDate(optionsRange.start);
                }
                if (optionsRange && optionsRange.end) {
                    endDay = new Date(optionsRange.end);
                    if (kendo.date.getDate(endDay) < optionsRange.end) {
                        this.end = kendo.date.getDate(new Date(endDay.setDate(endDay.getDate() + 1)));
                    } else {
                        this.end = kendo.date.getDate(endDay);
                    }
                }
            },
            _createSlots: function () {
                var slots = [];
                slots.push(this._weeks(this.start, this.end));
                slots.push(this._days(this.start, this.end));
                return slots;
            },
            _layout: function () {
                var rows = [];
                var options = this.options;
                rows.push(this._slotHeaders(this._slots[0], kendo.template(options.weekHeaderTemplate)));
                rows.push(this._slotHeaders(this._slots[1], kendo.template(options.dayHeaderTemplate)));
                return rows;
            }
        });
        kendo.ui.GanttMonthView = GanttView.extend({
            name: 'month',
            options: {
                weekHeaderTemplate: WEEK_HEADER_TEMPLATE,
                monthHeaderTemplate: MONTH_HEADER_TEMPLATE,
                resizeTooltipFormat: 'dddd, MMM d, yyyy'
            },
            range: function (range) {
                var optionsRange = this.options.range;
                var endDay;
                this.start = kendo.date.firstDayOfMonth(range.start);
                this.end = kendo.date.addDays(kendo.date.getDate(kendo.date.lastDayOfMonth(range.end)), 1);
                if (optionsRange && optionsRange.start) {
                    this.start = kendo.date.getDate(optionsRange.start);
                }
                if (optionsRange && optionsRange.end) {
                    endDay = new Date(optionsRange.end);
                    if (kendo.date.getDate(endDay) < optionsRange.end) {
                        this.end = kendo.date.getDate(new Date(endDay.setDate(endDay.getDate() + 1)));
                    } else {
                        this.end = kendo.date.getDate(endDay);
                    }
                }
            },
            _createSlots: function () {
                var slots = [];
                slots.push(this._months(this.start, this.end));
                slots.push(this._weeks(this.start, this.end));
                return slots;
            },
            _layout: function () {
                var rows = [];
                var options = this.options;
                rows.push(this._slotHeaders(this._slots[0], kendo.template(options.monthHeaderTemplate)));
                rows.push(this._slotHeaders(this._slots[1], kendo.template(options.weekHeaderTemplate)));
                return rows;
            }
        });
        kendo.ui.GanttYearView = GanttView.extend({
            name: 'year',
            options: {
                yearHeaderTemplate: YEAR_HEADER_TEMPLATE,
                monthHeaderTemplate: MONTH_HEADER_TEMPLATE,
                resizeTooltipFormat: 'dddd, MMM d, yyyy'
            },
            range: function (range) {
                var optionsRange = this.options.range;
                var firstDayOfMonth;
                this.start = kendo.date.firstDayOfMonth(new Date(range.start.setMonth(0)));
                this.end = kendo.date.firstDayOfMonth(new Date(range.end.setMonth(12)));
                if (optionsRange && optionsRange.start) {
                    this.start = kendo.date.firstDayOfMonth(optionsRange.start);
                }
                if (optionsRange && optionsRange.end) {
                    firstDayOfMonth = kendo.date.firstDayOfMonth(optionsRange.end);
                    this.end = kendo.date.getDate(new Date(firstDayOfMonth.setMonth(firstDayOfMonth.getMonth() + 1)));
                }
            },
            _createSlots: function () {
                var slots = [];
                var monthSlots = this._months(this.start, this.end);
                $(monthSlots).each(function (index, slot) {
                    slot.span = 1;
                });
                slots.push(this._years(this.start, this.end));
                slots.push(monthSlots);
                return slots;
            },
            _layout: function () {
                var rows = [];
                var options = this.options;
                rows.push(this._slotHeaders(this._slots[0], kendo.template(options.yearHeaderTemplate)));
                rows.push(this._slotHeaders(this._slots[1], kendo.template(options.monthHeaderTemplate)));
                return rows;
            }
        });
        var timelineStyles = {
            wrapper: 'k-timeline k-grid k-widget',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            gridContentWrap: 'k-grid-content',
            tasksWrapper: 'k-gantt-tables',
            dependenciesWrapper: 'k-gantt-dependencies',
            task: 'k-task',
            line: 'k-line',
            taskResizeHandle: 'k-resize-handle',
            taskResizeHandleWest: 'k-resize-w',
            taskDragHandle: 'k-task-draghandle',
            taskComplete: 'k-task-complete',
            taskDelete: 'k-task-delete',
            taskWrapActive: 'k-task-wrap-active',
            taskWrap: 'k-task-wrap',
            taskDot: 'k-task-dot',
            taskDotStart: 'k-task-start',
            taskDotEnd: 'k-task-end',
            hovered: 'k-state-hover',
            selected: 'k-state-selected',
            origin: 'k-origin'
        };
        var GanttTimeline = kendo.ui.GanttTimeline = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                if (!this.options.views || !this.options.views.length) {
                    this.options.views = [
                        'day',
                        'week',
                        'month'
                    ];
                }
                isRtl = kendo.support.isRtl(element);
                this._wrapper();
                this._domTrees();
                this._views();
                this._selectable();
                this._draggable();
                this._resizable();
                this._percentResizeDraggable();
                this._createDependencyDraggable();
                this._attachEvents();
                this._tooltip();
            },
            options: {
                name: 'GanttTimeline',
                messages: {
                    views: {
                        day: 'Day',
                        week: 'Week',
                        month: 'Month',
                        year: 'Year',
                        start: 'Start',
                        end: 'End'
                    }
                },
                snap: true,
                selectable: true,
                editable: true
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                clearTimeout(this._tooltipTimeout);
                if (this._currentTimeUpdateTimer) {
                    clearInterval(this._currentTimeUpdateTimer);
                }
                this._unbindView(this._selectedView);
                if (this._moveDraggable) {
                    this._moveDraggable.destroy();
                }
                if (this._resizeDraggable) {
                    this._resizeDraggable.destroy();
                }
                if (this._percentDraggable) {
                    this._percentDraggable.destroy();
                }
                if (this._dependencyDraggable) {
                    this._dependencyDraggable.destroy();
                }
                if (this.touch) {
                    this.touch.destroy();
                }
                this._headerTree = null;
                this._taskTree = null;
                this._dependencyTree = null;
                this.wrapper.off(NS);
                kendo.destroy(this.wrapper);
            },
            _wrapper: function () {
                var styles = GanttTimeline.styles;
                var that = this;
                var options = this.options;
                var calculateSize = function () {
                    var rowHeight = typeof options.rowHeight === STRING ? options.rowHeight : options.rowHeight + 'px';
                    var table = $(kendo.format(SIZE_CALCULATION_TEMPLATE, rowHeight));
                    var calculatedRowHeight;
                    var calculatedCellHeight;
                    var content = that.wrapper.find(DOT + styles.tasksWrapper);
                    content.append(table);
                    calculatedRowHeight = outerHeight(table.find('tr'));
                    calculatedCellHeight = table.find('td').height();
                    table.remove();
                    return {
                        'row': calculatedRowHeight,
                        'cell': calculatedCellHeight
                    };
                };
                this.wrapper = this.element.addClass(styles.wrapper).append('<div class=\'' + styles.gridHeader + '\'><div class=\'' + styles.gridHeaderWrap + '\'></div></div>').append('<div class=\'' + styles.gridContentWrap + '\'><div class=\'' + styles.tasksWrapper + '\'></div><div class=\'' + styles.dependenciesWrapper + '\'></div></div>');
                if (options.rowHeight) {
                    this._calculatedSize = calculateSize();
                }
            },
            _domTrees: function () {
                var styles = GanttTimeline.styles;
                var tree = kendo.dom.Tree;
                var wrapper = this.wrapper;
                this._headerTree = new tree(wrapper.find(DOT + styles.gridHeaderWrap)[0]);
                this._taskTree = new tree(wrapper.find(DOT + styles.tasksWrapper)[0]);
                this._dependencyTree = new tree(wrapper.find(DOT + styles.dependenciesWrapper)[0]);
            },
            _views: function () {
                var views = this.options.views;
                var view;
                var isSettings;
                var name;
                var defaultView;
                var selected;
                this.views = {};
                for (var i = 0, l = views.length; i < l; i++) {
                    view = views[i];
                    isSettings = isPlainObject(view);
                    if (isSettings && view.selectable === false) {
                        continue;
                    }
                    name = isSettings ? typeof view.type !== 'string' ? view.title : view.type : view;
                    defaultView = defaultViews[name];
                    if (defaultView) {
                        if (isSettings) {
                            view.type = defaultView.type;
                        }
                        defaultView.title = this.options.messages.views[name];
                    }
                    view = extend({ title: name }, defaultView, isSettings ? view : {});
                    if (name) {
                        this.views[name] = view;
                        if (!selected || view.selected) {
                            selected = name;
                        }
                    }
                }
                if (selected) {
                    this._selectedViewName = selected;
                }
            },
            view: function (name) {
                if (name) {
                    this._selectView(name);
                    this.trigger('navigate', {
                        view: name,
                        action: 'changeView'
                    });
                }
                return this._selectedView;
            },
            _selectView: function (name) {
                if (name && this.views[name]) {
                    if (this._selectedView) {
                        this._unbindView(this._selectedView);
                    }
                    this._selectedView = this._initializeView(name);
                    this._selectedViewName = name;
                }
            },
            _viewByIndex: function (index) {
                var view;
                var views = this.views;
                for (view in views) {
                    if (!index) {
                        return view;
                    }
                    index--;
                }
            },
            _initializeView: function (name) {
                var view = this.views[name];
                if (view) {
                    var type = view.type;
                    if (typeof type === 'string') {
                        type = kendo.getter(view.type)(window);
                    }
                    if (type) {
                        var newRange = {};
                        extend(newRange, this.options.range, view.range);
                        var newDate = view.date || this.options.date;
                        view = new type(this.wrapper, trimOptions(extend(true, {
                            headerTree: this._headerTree,
                            taskTree: this._taskTree,
                            dependencyTree: this._dependencyTree,
                            calculatedSize: this._calculatedSize
                        }, view, this.options, {
                            date: newDate,
                            range: newRange
                        })));
                    } else {
                        throw new Error('There is no such view');
                    }
                }
                return view;
            },
            _unbindView: function (view) {
                if (view) {
                    view.destroy();
                }
            },
            _range: function (tasks) {
                var startOrder = {
                    field: 'start',
                    dir: 'asc'
                };
                var endOrder = {
                    field: 'end',
                    dir: 'desc'
                };
                if (!tasks || !tasks.length) {
                    return {
                        start: new Date(),
                        end: new Date()
                    };
                }
                var start = new Query(tasks).sort(startOrder).toArray()[0].start || new Date();
                var end = new Query(tasks).sort(endOrder).toArray()[0].end || new Date();
                return {
                    start: new Date(start),
                    end: new Date(end)
                };
            },
            _render: function (tasks) {
                var view = this.view();
                var range = this._range(tasks);
                var date = view.options.date;
                this._tasks = tasks;
                view.range(range);
                view.renderLayout();
                view.render(tasks);
                if (date) {
                    view._scrollToDate(date);
                }
            },
            _renderDependencies: function (dependencies) {
                this.view()._renderDependencies(dependencies);
            },
            _taskByUid: function (uid) {
                var tasks = this._tasks;
                var length = tasks.length;
                var task;
                for (var i = 0; i < length; i++) {
                    task = tasks[i];
                    if (task.uid === uid) {
                        return task;
                    }
                }
            },
            _draggable: function () {
                var that = this;
                var element;
                var task;
                var currentStart;
                var startOffset;
                var snap = this.options.snap;
                var styles = GanttTimeline.styles;
                var editable = this.options.editable;
                var cleanUp = function () {
                    that.view()._removeDragHint();
                    if (element) {
                        element.css('opacity', 1);
                    }
                    element = null;
                    task = null;
                    that.dragInProgress = false;
                };
                if (!editable || editable.move === false || editable.update === false) {
                    return;
                }
                this._moveDraggable = new kendo.ui.Draggable(this.wrapper, {
                    distance: 0,
                    filter: DOT + styles.task,
                    holdToDrag: kendo.support.mobileOS,
                    ignore: DOT + styles.taskResizeHandle
                });
                this._moveDraggable.bind('dragstart', function (e) {
                    var view = that.view();
                    element = e.currentTarget.parent();
                    task = that._taskByUid(e.currentTarget.attr('data-uid'));
                    if (that.trigger('moveStart', { task: task })) {
                        e.preventDefault();
                        return;
                    }
                    currentStart = task.start;
                    startOffset = view._timeByPosition(e.x.location, snap) - currentStart;
                    view._createDragHint(element);
                    element.css('opacity', 0.5);
                    clearTimeout(that._tooltipTimeout);
                    that.dragInProgress = true;
                }).bind('drag', kendo.throttle(function (e) {
                    if (!that.dragInProgress) {
                        return;
                    }
                    var view = that.view();
                    var date = new Date(view._timeByPosition(e.x.location, snap) - startOffset);
                    var updateHintDate = date;
                    if (!that.trigger('move', {
                            task: task,
                            start: date
                        })) {
                        currentStart = date;
                        if (isRtl) {
                            updateHintDate = new Date(currentStart.getTime() + task.duration());
                        }
                        view._updateDragHint(updateHintDate);
                    }
                }, 15)).bind('dragend', function () {
                    that.trigger('moveEnd', {
                        task: task,
                        start: currentStart
                    });
                    cleanUp();
                }).bind('dragcancel', function () {
                    cleanUp();
                }).userEvents.bind('select', function () {
                    blurActiveElement();
                });
            },
            _resizable: function () {
                var that = this;
                var element;
                var task;
                var currentStart;
                var currentEnd;
                var resizeStart;
                var snap = this.options.snap;
                var styles = GanttTimeline.styles;
                var editable = this.options.editable;
                var cleanUp = function () {
                    that.view()._removeResizeHint();
                    element = null;
                    task = null;
                    that.dragInProgress = false;
                };
                if (!editable || editable.resize === false || editable.update === false) {
                    return;
                }
                this._resizeDraggable = new kendo.ui.Draggable(this.wrapper, {
                    distance: 0,
                    filter: DOT + styles.taskResizeHandle,
                    holdToDrag: false
                });
                this._resizeDraggable.bind('dragstart', function (e) {
                    resizeStart = e.currentTarget.hasClass(styles.taskResizeHandleWest);
                    if (isRtl) {
                        resizeStart = !resizeStart;
                    }
                    element = e.currentTarget.closest(DOT + styles.task);
                    task = that._taskByUid(element.attr('data-uid'));
                    if (that.trigger('resizeStart', { task: task })) {
                        e.preventDefault();
                        return;
                    }
                    currentStart = task.start;
                    currentEnd = task.end;
                    that.view()._createResizeHint(task);
                    clearTimeout(that._tooltipTimeout);
                    that.dragInProgress = true;
                }).bind('drag', kendo.throttle(function (e) {
                    if (!that.dragInProgress) {
                        return;
                    }
                    var view = that.view();
                    var date = view._timeByPosition(e.x.location, snap, !resizeStart);
                    if (resizeStart) {
                        if (date < currentEnd) {
                            currentStart = date;
                        } else {
                            currentStart = currentEnd;
                        }
                    } else {
                        if (date > currentStart) {
                            currentEnd = date;
                        } else {
                            currentEnd = currentStart;
                        }
                    }
                    if (!that.trigger('resize', {
                            task: task,
                            start: currentStart,
                            end: currentEnd
                        })) {
                        view._updateResizeHint(currentStart, currentEnd, resizeStart);
                    }
                }, 15)).bind('dragend', function () {
                    that.trigger('resizeEnd', {
                        task: task,
                        resizeStart: resizeStart,
                        start: currentStart,
                        end: currentEnd
                    });
                    cleanUp();
                }).bind('dragcancel', function () {
                    cleanUp();
                }).userEvents.bind('select', function () {
                    blurActiveElement();
                });
            },
            _percentResizeDraggable: function () {
                var that = this;
                var task;
                var taskElement;
                var taskElementOffset;
                var timelineOffset;
                var originalPercentWidth;
                var maxPercentWidth;
                var currentPercentComplete;
                var tooltipTop;
                var tooltipLeft;
                var styles = GanttTimeline.styles;
                var delta;
                var editable = this.options.editable;
                var cleanUp = function () {
                    that.view()._removePercentCompleteTooltip();
                    taskElement = null;
                    task = null;
                    that.dragInProgress = false;
                };
                var updateElement = function (width) {
                    taskElement.find(DOT + styles.taskComplete).width(width).end().siblings(DOT + styles.taskDragHandle).css(isRtl ? 'right' : 'left', width);
                };
                if (!editable || editable.dragPercentComplete === false || editable.update === false) {
                    return;
                }
                this._percentDraggable = new kendo.ui.Draggable(this.wrapper, {
                    distance: 0,
                    filter: DOT + styles.taskDragHandle,
                    holdToDrag: false
                });
                this._percentDraggable.bind('dragstart', function (e) {
                    if (that.trigger('percentResizeStart')) {
                        e.preventDefault();
                        return;
                    }
                    taskElement = e.currentTarget.siblings(DOT + styles.task);
                    task = that._taskByUid(taskElement.attr('data-uid'));
                    currentPercentComplete = task.percentComplete;
                    taskElementOffset = taskElement.offset();
                    timelineOffset = this.element.offset();
                    originalPercentWidth = taskElement.find(DOT + styles.taskComplete).width();
                    maxPercentWidth = outerWidth(taskElement);
                    clearTimeout(that._tooltipTimeout);
                    that.dragInProgress = true;
                }).bind('drag', kendo.throttle(function (e) {
                    if (!that.dragInProgress) {
                        return;
                    }
                    delta = isRtl ? -e.x.initialDelta : e.x.initialDelta;
                    var currentWidth = Math.max(0, Math.min(maxPercentWidth, originalPercentWidth + delta));
                    currentPercentComplete = Math.round(currentWidth / maxPercentWidth * 100);
                    updateElement(currentWidth);
                    tooltipTop = taskElementOffset.top - timelineOffset.top;
                    tooltipLeft = taskElementOffset.left + currentWidth - timelineOffset.left;
                    if (isRtl) {
                        tooltipLeft += maxPercentWidth - 2 * currentWidth;
                    }
                    that.view()._updatePercentCompleteTooltip(tooltipTop, tooltipLeft, currentPercentComplete);
                }, 15)).bind('dragend', function () {
                    that.trigger('percentResizeEnd', {
                        task: task,
                        percentComplete: currentPercentComplete / 100
                    });
                    cleanUp();
                }).bind('dragcancel', function () {
                    updateElement(originalPercentWidth);
                    cleanUp();
                }).userEvents.bind('select', function () {
                    blurActiveElement();
                });
            },
            _createDependencyDraggable: function () {
                var that = this;
                var originalHandle;
                var hoveredHandle = $();
                var hoveredTask = $();
                var startX;
                var startY;
                var useVML = browser.msie && browser.version < 9;
                var styles = GanttTimeline.styles;
                var editable = this.options.editable;
                var cleanUp = function () {
                    originalHandle.css('display', '').removeClass(styles.hovered);
                    originalHandle.parent().removeClass(styles.origin);
                    originalHandle = null;
                    toggleHandles(false);
                    hoveredTask = $();
                    hoveredHandle = $();
                    that.view()._removeDependencyDragHint();
                    that.dragInProgress = false;
                };
                var toggleHandles = function (value) {
                    if (!hoveredTask.hasClass(styles.origin)) {
                        hoveredTask.find(DOT + styles.taskDot).css('display', value ? 'block' : '');
                        hoveredHandle.toggleClass(styles.hovered, value);
                    }
                };
                if (!editable || editable.dependencyCreate === false) {
                    return;
                }
                if (useVML && document.namespaces) {
                    document.namespaces.add('kvml', 'urn:schemas-microsoft-com:vml', '#default#VML');
                }
                this._dependencyDraggable = new kendo.ui.Draggable(this.wrapper, {
                    distance: 0,
                    filter: DOT + styles.taskDot,
                    holdToDrag: false
                });
                this._dependencyDraggable.bind('dragstart', function (e) {
                    if (that.trigger('dependencyDragStart')) {
                        e.preventDefault();
                        return;
                    }
                    originalHandle = e.currentTarget.css('display', 'block').addClass(styles.hovered);
                    originalHandle.parent().addClass(styles.origin);
                    var elementOffset = originalHandle.offset();
                    var tablesOffset = that.wrapper.find(DOT + styles.tasksWrapper).offset();
                    startX = Math.round(elementOffset.left - tablesOffset.left + outerHeight(originalHandle) / 2);
                    startY = Math.round(elementOffset.top - tablesOffset.top + outerWidth(originalHandle) / 2);
                    clearTimeout(that._tooltipTimeout);
                    that.dragInProgress = true;
                }).bind('drag', kendo.throttle(function (e) {
                    if (!that.dragInProgress) {
                        return;
                    }
                    that.view()._removeDependencyDragHint();
                    var target = $(kendo.elementUnderCursor(e));
                    var tablesOffset = that.wrapper.find(DOT + styles.tasksWrapper).offset();
                    var currentX = e.x.location - tablesOffset.left;
                    var currentY = e.y.location - tablesOffset.top;
                    that.view()._updateDependencyDragHint({
                        x: startX,
                        y: startY
                    }, {
                        x: currentX,
                        y: currentY
                    }, useVML);
                    toggleHandles(false);
                    hoveredHandle = target.hasClass(styles.taskDot) ? target : $();
                    hoveredTask = target.closest(DOT + styles.taskWrap);
                    toggleHandles(true);
                }, 15)).bind('dragend', function () {
                    if (hoveredHandle.length) {
                        var fromStart = originalHandle.hasClass(styles.taskDotStart);
                        var toStart = hoveredHandle.hasClass(styles.taskDotStart);
                        var type = fromStart ? toStart ? 3 : 2 : toStart ? 1 : 0;
                        var predecessor = that._taskByUid(originalHandle.siblings(DOT + styles.task).attr('data-uid'));
                        var successor = that._taskByUid(hoveredHandle.siblings(DOT + styles.task).attr('data-uid'));
                        if (predecessor !== successor) {
                            that.trigger('dependencyDragEnd', {
                                type: type,
                                predecessor: predecessor,
                                successor: successor
                            });
                        }
                    }
                    cleanUp();
                }).bind('dragcancel', function () {
                    cleanUp();
                }).userEvents.bind('select', function () {
                    blurActiveElement();
                });
            },
            _selectable: function () {
                var that = this;
                var styles = GanttTimeline.styles;
                if (this.options.selectable) {
                    this.wrapper.on(CLICK + NS, DOT + styles.task, function (e) {
                        e.stopPropagation();
                        if (!e.ctrlKey) {
                            that.trigger('select', { uid: $(this).attr('data-uid') });
                        } else {
                            that.trigger('clear');
                        }
                    }).on(CLICK + NS, DOT + styles.taskWrap, function (e) {
                        e.stopPropagation();
                        $(this).css('z-index', '0');
                        var target = $(document.elementFromPoint(e.clientX, e.clientY));
                        if (target.hasClass(styles.line)) {
                            target.click();
                        }
                        $(this).css('z-index', '');
                    }).on(CLICK + NS, DOT + styles.tasksWrapper, function () {
                        if (that.selectDependency().length > 0) {
                            that.clearSelection();
                        } else {
                            that.trigger('clear');
                        }
                    }).on(CLICK + NS, DOT + styles.line, function (e) {
                        e.stopPropagation();
                        that.selectDependency(this);
                    });
                }
            },
            select: function (value) {
                var element = this.wrapper.find(value);
                var styles = GanttTimeline.styles;
                if (element.length) {
                    this.clearSelection();
                    element.addClass(styles.selected);
                    if (kendo.support.mobileOS) {
                        element.parent().addClass(styles.taskWrapActive);
                    }
                    return;
                }
                return this.wrapper.find(DOT + styles.task + DOT + styles.selected);
            },
            selectDependency: function (value) {
                var element = this.wrapper.find(value);
                var uid;
                var styles = GanttTimeline.styles;
                if (element.length) {
                    this.clearSelection();
                    this.trigger('clear');
                    uid = $(element).attr('data-uid');
                    this.wrapper.find(DOT + styles.line + '[data-uid=\'' + uid + '\']').addClass(styles.selected);
                    return;
                }
                return this.wrapper.find(DOT + styles.line + DOT + styles.selected);
            },
            clearSelection: function () {
                var styles = GanttTimeline.styles;
                this.wrapper.find(DOT + styles.selected).removeClass(styles.selected);
                if (kendo.support.mobileOS) {
                    this.wrapper.find(DOT + styles.taskWrapActive).removeClass(styles.taskWrapActive);
                }
            },
            _attachEvents: function () {
                var that = this;
                var styles = GanttTimeline.styles;
                var editable = this.options.editable;
                if (editable) {
                    this._tabindex();
                    this.wrapper.on(CLICK + NS, DOT + styles.taskDelete, function (e) {
                        that.trigger('removeTask', { uid: $(this).closest(DOT + styles.task).attr('data-uid') });
                        e.stopPropagation();
                        e.preventDefault();
                    }).on(KEYDOWN + NS, function (e) {
                        var selectedDependency;
                        var editable = that.options.editable;
                        if (e.keyCode === keys.DELETE && editable && editable.dependencyDestroy !== false) {
                            selectedDependency = that.selectDependency();
                            if (selectedDependency.length) {
                                that.trigger('removeDependency', { uid: selectedDependency.attr('data-uid') });
                                that.clearSelection();
                            }
                        }
                    });
                    if (!kendo.support.mobileOS) {
                        this.wrapper.on(DBLCLICK + NS, DOT + styles.task, function (e) {
                            if (that.options.editable.update !== false) {
                                that.trigger('editTask', { uid: $(this).attr('data-uid') });
                                e.stopPropagation();
                                e.preventDefault();
                            }
                        });
                    } else {
                        this.touch = this.wrapper.kendoTouch({
                            filter: DOT + styles.task,
                            doubletap: function (e) {
                                if (that.options.editable.update !== false) {
                                    that.trigger('editTask', { uid: $(e.touch.currentTarget).attr('data-uid') });
                                }
                            }
                        }).data('kendoTouch');
                    }
                }
            },
            _tooltip: function () {
                var that = this;
                var tooltipOptions = this.options.tooltip;
                var styles = GanttTimeline.styles;
                var currentMousePosition;
                var mouseMoveHandler = function (e) {
                    currentMousePosition = e.clientX;
                };
                if (tooltipOptions && tooltipOptions.visible === false) {
                    return;
                }
                if (!kendo.support.mobileOS) {
                    this.wrapper.on(MOUSEENTER + NS, DOT + styles.task, function () {
                        var element = this;
                        var task = that._taskByUid($(this).attr('data-uid'));
                        if (that.dragInProgress) {
                            return;
                        }
                        that._tooltipTimeout = setTimeout(function () {
                            that.view()._createTaskTooltip(task, element, currentMousePosition);
                        }, 800);
                        $(this).on(MOUSEMOVE, mouseMoveHandler);
                    }).on(MOUSELEAVE + NS, DOT + styles.task, function () {
                        clearTimeout(that._tooltipTimeout);
                        that.view()._removeTaskTooltip();
                        $(this).off(MOUSEMOVE, mouseMoveHandler);
                    });
                } else {
                    this.wrapper.on(CLICK + NS, DOT + styles.taskDelete, function (e) {
                        e.stopPropagation();
                        that.view()._removeTaskTooltip();
                    }).on(MOUSELEAVE + NS, DOT + styles.task, function (e) {
                        var parents = $(e.relatedTarget).parents(DOT + styles.taskWrap, DOT + styles.task);
                        if (parents.length === 0) {
                            that.view()._removeTaskTooltip();
                        }
                    });
                    if (this.touch) {
                        this.touch.bind('tap', function (e) {
                            var element = e.touch.target;
                            var task = that._taskByUid($(element).attr('data-uid'));
                            var currentPosition = e.touch.x.client;
                            if (that.view()._taskTooltip) {
                                that.view()._removeTaskTooltip();
                            }
                            that.view()._createTaskTooltip(task, element, currentPosition);
                        }).bind('doubletap', function () {
                            that.view()._removeTaskTooltip();
                        });
                    }
                }
            }
        });
        extend(true, GanttTimeline, { styles: timelineStyles });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.gantt', [
        'kendo.data',
        'kendo.popup',
        'kendo.window',
        'kendo.resizable',
        'kendo.gantt.list',
        'kendo.gantt.timeline',
        'kendo.grid',
        'kendo.pdf'
    ], f);
}(function () {
    var __meta__ = {
        id: 'gantt',
        name: 'Gantt',
        category: 'web',
        description: 'The Gantt component.',
        depends: [
            'data',
            'popup',
            'resizable',
            'window',
            'gantt.list',
            'gantt.timeline',
            'grid'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo;
        var supportsMedia = 'matchMedia' in window;
        var browser = kendo.support.browser;
        var mobileOS = kendo.support.mobileOS;
        var Observable = kendo.Observable;
        var Widget = kendo.ui.Widget;
        var DataSource = kendo.data.DataSource;
        var ObservableObject = kendo.data.ObservableObject;
        var ObservableArray = kendo.data.ObservableArray;
        var Query = kendo.data.Query;
        var isArray = $.isArray;
        var inArray = $.inArray;
        var isFunction = kendo.isFunction;
        var proxy = $.proxy;
        var extend = $.extend;
        var isPlainObject = $.isPlainObject;
        var map = $.map;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var keys = kendo.keys;
        var defaultIndicatorWidth = 3;
        var NS = '.kendoGantt';
        var PERCENTAGE_FORMAT = 'p0';
        var TABINDEX = 'tabIndex';
        var CLICK = 'click';
        var WIDTH = 'width';
        var STRING = 'string';
        var DIRECTIONS = {
            'down': {
                origin: 'bottom left',
                position: 'top left'
            },
            'up': {
                origin: 'top left',
                position: 'bottom left'
            }
        };
        var ARIA_DESCENDANT = 'aria-activedescendant';
        var ARIA_LABEL = 'aria-label';
        var ACTIVE_CELL = 'gantt_active_cell';
        var ACTIVE_OPTION = 'action-option-focused';
        var DOT = '.';
        var TASK_DELETE_CONFIRM = 'Are you sure you want to delete this task?';
        var DEPENDENCY_DELETE_CONFIRM = 'Are you sure you want to delete this dependency?';
        var TOGGLE_BUTTON_TEMPLATE = kendo.template('<button class="#=styles.buttonToggle#" type="button" ' + ARIA_LABEL + '="Toggle"><span class="#=styles.iconToggle#"></span></button>');
        var BUTTON_TEMPLATE = '<button class="#=styles.button# #=className#" type="button" ' + '#if (action) {#' + 'data-action="#=action#"' + '#}#' + '><span class="#=iconClass#"></span><span>#=text#</span></button>';
        var COMMAND_BUTTON_TEMPLATE = '<a class="#=className#" #=attr# href="\\#">#=text#</a>';
        var VIEWBUTTONTEMPLATE = kendo.template('<li class="#=styles.currentView# #=styles.viewButtonDefault#"><a href="\\#" class="#=styles.link#">&nbps;</a></li>');
        var HEADER_VIEWS_TEMPLATE = kendo.template('<ul class="#=styles.viewsWrapper#">' + '#for(var view in views){#' + '<li class="#=styles.viewButtonDefault# #=styles.viewButton#-#= view.toLowerCase() #" data-#=ns#name="#=view#"><a href="\\#" class="#=styles.link#">#=views[view].title#</a></li>' + '#}#' + '</ul>');
        var TASK_DROPDOWN_TEMPLATE = kendo.template('<div class="#=styles.popupWrapper#">' + '<ul class="#=styles.popupList#" role="listbox">' + '#for(var i = 0, l = actions.length; i < l; i++){#' + '<li class="#=styles.item#" data-action="#=actions[i].data#" role="option">#=actions[i].text#</span>' + '#}#' + '</ul>' + '</div>');
        var DATERANGEEDITOR = function (container, options) {
            var attr = {
                name: options.field,
                title: options.title
            };
            var validationRules = options.model.fields[options.field].validation;
            if (validationRules && isPlainObject(validationRules) && validationRules.message) {
                attr[kendo.attr('dateCompare-msg')] = validationRules.message;
            }
            $('<input type="text" required ' + kendo.attr('type') + '="date" ' + kendo.attr('role') + '="datetimepicker" ' + kendo.attr('bind') + '="value:' + options.field + '" ' + kendo.attr('validate') + '=\'true\' />').attr(attr).appendTo(container);
            $('<span ' + kendo.attr('for') + '="' + options.field + '" class="k-invalid-msg"/>').hide().appendTo(container);
        };
        var RESOURCESEDITOR = function (container, options) {
            $('<a href="#" class="' + options.styles.button + '">' + options.messages.assignButton + '</a>').click(options.click).appendTo(container);
        };
        var ganttStyles = {
            wrapper: 'k-widget k-gantt',
            rowHeight: 'k-gantt-rowheight',
            listWrapper: 'k-gantt-layout k-gantt-treelist',
            list: 'k-gantt-treelist',
            timelineWrapper: 'k-gantt-layout k-gantt-timeline',
            timeline: 'k-gantt-timeline',
            splitBarWrapper: 'k-splitbar k-state-default k-splitbar-horizontal k-splitbar-draggable-horizontal k-gantt-layout',
            splitBar: 'k-splitbar',
            splitBarHover: 'k-splitbar-horizontal-hover',
            popupWrapper: 'k-list-container',
            popupList: 'k-list k-reset',
            resizeHandle: 'k-resize-handle',
            icon: 'k-icon',
            item: 'k-item',
            line: 'k-line',
            buttonDelete: 'k-gantt-delete',
            buttonCancel: 'k-gantt-cancel',
            buttonSave: 'k-gantt-update',
            buttonToggle: 'k-gantt-toggle',
            primary: 'k-primary',
            hovered: 'k-state-hover',
            selected: 'k-state-selected',
            focused: 'k-state-focused',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            popup: {
                form: 'k-popup-edit-form',
                editForm: 'k-gantt-edit-form',
                formContainer: 'k-edit-form-container',
                resourcesFormContainer: 'k-resources-form-container',
                message: 'k-popup-message',
                buttonsContainer: 'k-edit-buttons k-state-default',
                button: 'k-button',
                editField: 'k-edit-field',
                editLabel: 'k-edit-label',
                resourcesField: 'k-gantt-resources'
            },
            toolbar: {
                headerWrapper: 'k-floatwrap k-header k-gantt-toolbar',
                footerWrapper: 'k-floatwrap k-header k-gantt-toolbar',
                toolbar: 'k-gantt-toolbar',
                expanded: 'k-state-expanded',
                views: 'k-gantt-views',
                viewsWrapper: 'k-reset k-header k-gantt-views',
                actions: 'k-gantt-actions',
                button: 'k-button k-button-icontext',
                buttonToggle: 'k-button k-button-icon k-gantt-toggle',
                iconPlus: 'k-icon k-i-plus',
                iconPdf: 'k-icon k-i-file-pdf',
                iconToggle: 'k-icon k-i-layout-1-by-4',
                viewButtonDefault: 'k-state-default',
                viewButton: 'k-view',
                currentView: 'k-current-view',
                link: 'k-link',
                pdfButton: 'k-gantt-pdf',
                appendButton: 'k-gantt-create'
            }
        };
        function selector(uid) {
            return '[' + kendo.attr('uid') + (uid ? '=\'' + uid + '\']' : ']');
        }
        function trimOptions(options) {
            delete options.name;
            delete options.prefix;
            delete options.remove;
            delete options.edit;
            delete options.add;
            delete options.navigate;
            return options;
        }
        function dateCompareValidator(input) {
            if (input.filter('[name=end], [name=start]').length) {
                var field = input.attr('name');
                var picker = kendo.widgetInstance(input, kendo.ui);
                var dates = {};
                var container = input;
                var editable;
                var model;
                while (container !== window && !editable) {
                    container = container.parent();
                    editable = container.data('kendoEditable');
                }
                model = editable ? editable.options.model : null;
                if (!model) {
                    return true;
                }
                dates.start = model.start;
                dates.end = model.end;
                dates[field] = picker ? picker.value() : kendo.parseDate(input.value());
                return dates.start <= dates.end;
            }
            return true;
        }
        function focusTable(table, direct) {
            var wrapper = table.parents('[' + kendo.attr('role') + '="gantt"]');
            var scrollPositions = [];
            var parents = scrollableParents(wrapper);
            table.attr(TABINDEX, 0);
            if (direct) {
                parents.each(function (index, parent) {
                    scrollPositions[index] = $(parent).scrollTop();
                });
            }
            try {
                table[0].setActive();
            } catch (e) {
                table[0].focus();
            }
            if (direct) {
                parents.each(function (index, parent) {
                    $(parent).scrollTop(scrollPositions[index]);
                });
            }
        }
        function scrollableParents(element) {
            return $(element).parentsUntil('body').filter(function (index, element) {
                var computedStyle = kendo.getComputedStyles(element, ['overflow']);
                return computedStyle.overflow != 'visible';
            }).add(window);
        }
        var defaultCommands;
        var TaskDropDown = Observable.extend({
            init: function (element, options) {
                Observable.fn.init.call(this);
                this.element = element;
                this.options = extend(true, {}, this.options, options);
                this._popup();
            },
            options: {
                direction: 'down',
                navigatable: false
            },
            _current: function (method) {
                var ganttStyles = Gantt.styles;
                var current = this.list.find(DOT + ganttStyles.focused);
                var sibling = current[method]();
                if (sibling.length) {
                    current.removeClass(ganttStyles.focused).removeAttr('id');
                    sibling.addClass(ganttStyles.focused).attr('id', ACTIVE_OPTION);
                    this.list.find('ul').removeAttr(ARIA_DESCENDANT).attr(ARIA_DESCENDANT, ACTIVE_OPTION);
                }
            },
            _popup: function () {
                var that = this;
                var ganttStyles = Gantt.styles;
                var itemSelector = 'li' + DOT + ganttStyles.item;
                var appendButtonSelector = DOT + ganttStyles.toolbar.appendButton;
                var actions = this.options.messages.actions;
                var navigatable = this.options.navigatable;
                this.list = $(TASK_DROPDOWN_TEMPLATE({
                    styles: ganttStyles,
                    actions: [
                        {
                            data: 'add',
                            text: actions.addChild
                        },
                        {
                            data: 'insert-before',
                            text: actions.insertBefore
                        },
                        {
                            data: 'insert-after',
                            text: actions.insertAfter
                        }
                    ]
                }));
                this.element.append(this.list);
                this.popup = new kendo.ui.Popup(this.list, extend({
                    anchor: this.element.find(appendButtonSelector),
                    open: function () {
                        that._adjustListWidth();
                    },
                    animation: this.options.animation
                }, DIRECTIONS[this.options.direction]));
                this.element.on(CLICK + NS, appendButtonSelector, function (e) {
                    var target = $(this);
                    var action = target.attr(kendo.attr('action'));
                    e.preventDefault();
                    if (action) {
                        that.trigger('command', { type: action });
                    } else {
                        that.popup.open();
                        if (navigatable) {
                            that.list.find('li:first').addClass(ganttStyles.focused).attr('id', ACTIVE_OPTION).end().find('ul').attr({
                                TABINDEX: 0,
                                'aria-activedescendant': ACTIVE_OPTION
                            }).focus();
                        }
                    }
                });
                this.list.find(itemSelector).hover(function () {
                    $(this).addClass(ganttStyles.hovered);
                }, function () {
                    $(this).removeClass(ganttStyles.hovered);
                }).end().on(CLICK + NS, itemSelector, function () {
                    that.trigger('command', { type: $(this).attr(kendo.attr('action')) });
                    that.popup.close();
                });
                if (navigatable) {
                    this.popup.bind('close', function () {
                        that.list.find(itemSelector).removeClass(ganttStyles.focused).end().find('ul').attr(TABINDEX, 0);
                        that.element.parents('[' + kendo.attr('role') + '="gantt"]').find(DOT + ganttStyles.gridContent + ' > table:first').focus();
                    });
                    this.list.find('ul').on('keydown' + NS, function (e) {
                        var key = e.keyCode;
                        switch (key) {
                        case keys.UP:
                            e.preventDefault();
                            that._current('prev');
                            break;
                        case keys.DOWN:
                            e.preventDefault();
                            that._current('next');
                            break;
                        case keys.ENTER:
                            that.list.find(DOT + ganttStyles.focused).click();
                            break;
                        case keys.ESC:
                            e.preventDefault();
                            that.popup.close();
                            break;
                        }
                    });
                }
            },
            _adjustListWidth: function () {
                var list = this.list;
                var ganttStyles = Gantt.styles;
                var width = list[0].style.width;
                var wrapper = this.element.find(DOT + ganttStyles.toolbar.appendButton);
                var listOuterWidth = outerWidth(list);
                var computedStyle;
                var computedWidth;
                if (!list.data(WIDTH) && width) {
                    return;
                }
                computedStyle = window.getComputedStyle ? window.getComputedStyle(wrapper[0], null) : 0;
                computedWidth = computedStyle ? parseFloat(computedStyle.width) : outerWidth(wrapper);
                if (computedStyle && (browser.mozilla || browser.msie)) {
                    computedWidth += parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) + parseFloat(computedStyle.borderLeftWidth) + parseFloat(computedStyle.borderRightWidth);
                }
                if (list.css('box-sizing') !== 'border-box') {
                    width = computedWidth - (outerWidth(list) - list.width());
                } else {
                    width = computedWidth;
                }
                if (listOuterWidth > width) {
                    width = listOuterWidth;
                }
                list.css({
                    fontFamily: wrapper.css('font-family'),
                    width: width
                }).data(WIDTH, width);
            },
            destroy: function () {
                clearTimeout(this._focusTimeout);
                this.popup.destroy();
                this.element.off(NS);
                this.list.off(NS);
                this.unbind();
            }
        });
        var createDataSource = function (type, name) {
            return function (options) {
                options = isArray(options) ? { data: options } : options;
                var dataSource = options || {};
                var data = dataSource.data;
                dataSource.data = data;
                if (!(dataSource instanceof type) && dataSource instanceof DataSource) {
                    throw new Error('Incorrect DataSource type. Only ' + name + ' instances are supported');
                }
                return dataSource instanceof type ? dataSource : new type(dataSource);
            };
        };
        var GanttDependency = kendo.data.Model.define({
            id: 'id',
            fields: {
                id: { type: 'number' },
                predecessorId: { type: 'number' },
                successorId: { type: 'number' },
                type: { type: 'number' }
            }
        });
        var GanttDependencyDataSource = DataSource.extend({
            init: function (options) {
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: GanttDependency,
                        model: GanttDependency
                    }
                }, options));
            },
            successors: function (id) {
                return this._dependencies('predecessorId', id);
            },
            predecessors: function (id) {
                return this._dependencies('successorId', id);
            },
            dependencies: function (id) {
                var predecessors = this.predecessors(id);
                var successors = this.successors(id);
                predecessors.push.apply(predecessors, successors);
                return predecessors;
            },
            _dependencies: function (field, id) {
                var data = this.view();
                var filter = {
                    field: field,
                    operator: 'eq',
                    value: id
                };
                data = new Query(data).filter(filter).toArray();
                return data;
            }
        });
        GanttDependencyDataSource.create = createDataSource(GanttDependencyDataSource, 'GanttDependencyDataSource');
        var GanttTask = kendo.data.Model.define({
            duration: function () {
                var end = this.end;
                var start = this.start;
                return end - start;
            },
            isMilestone: function () {
                return this.duration() === 0;
            },
            _offset: function (value) {
                var field = [
                    'start',
                    'end'
                ];
                var newValue;
                for (var i = 0; i < field.length; i++) {
                    newValue = new Date(this.get(field[i]).getTime() + value);
                    this.set(field[i], newValue);
                }
            },
            id: 'id',
            fields: {
                id: { type: 'number' },
                parentId: {
                    type: 'number',
                    defaultValue: null,
                    validation: { required: true }
                },
                orderId: {
                    type: 'number',
                    validation: { required: true }
                },
                title: {
                    type: 'string',
                    defaultValue: 'New task'
                },
                start: {
                    type: 'date',
                    validation: { required: true }
                },
                end: {
                    type: 'date',
                    validation: {
                        required: true,
                        dateCompare: dateCompareValidator,
                        message: 'End date should be after or equal to the start date'
                    }
                },
                percentComplete: {
                    type: 'number',
                    validation: {
                        required: true,
                        min: 0,
                        max: 1,
                        step: 0.01
                    }
                },
                summary: { type: 'boolean' },
                expanded: {
                    type: 'boolean',
                    defaultValue: true
                }
            }
        });
        var GanttDataSource = DataSource.extend({
            init: function (options) {
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: GanttTask,
                        model: GanttTask
                    }
                }, options));
            },
            remove: function (task) {
                var parentId = task.get('parentId');
                var children = this.taskAllChildren(task);
                this._removeItems(children);
                task = DataSource.fn.remove.call(this, task);
                this._childRemoved(parentId, task.get('orderId'));
                return task;
            },
            add: function (task) {
                if (!task) {
                    return;
                }
                task = this._toGanttTask(task);
                return this.insert(this.taskSiblings(task).length, task);
            },
            insert: function (index, task) {
                if (!task) {
                    return;
                }
                task = this._toGanttTask(task);
                task.set('orderId', index);
                task = DataSource.fn.insert.call(this, index, task);
                this._reorderSiblings(task, this.taskSiblings(task).length - 1);
                this._resolveSummaryFields(this.taskParent(task));
                return task;
            },
            taskChildren: function (task) {
                var data = this.view();
                var filter = {
                    field: 'parentId',
                    operator: 'eq',
                    value: null
                };
                var order = this._sort && this._sort.length ? this._sort : {
                    field: 'orderId',
                    dir: 'asc'
                };
                var taskId;
                if (!!task) {
                    taskId = task.get('id');
                    if (taskId === undefined || taskId === null || taskId === '') {
                        return [];
                    }
                    filter.value = taskId;
                }
                data = new Query(data).filter(filter).sort(order).toArray();
                return data;
            },
            taskAllChildren: function (task) {
                var data = [];
                var that = this;
                var callback = function (task) {
                    var tasks = that.taskChildren(task);
                    data.push.apply(data, tasks);
                    map(tasks, callback);
                };
                if (!!task) {
                    callback(task);
                } else {
                    data = this.view();
                }
                return data;
            },
            taskSiblings: function (task) {
                if (!task) {
                    return null;
                }
                var parent = this.taskParent(task);
                return this.taskChildren(parent);
            },
            taskParent: function (task) {
                if (!task || task.get('parentId') === null) {
                    return null;
                }
                return this.get(task.parentId);
            },
            taskLevel: function (task) {
                var level = 0;
                var parent = this.taskParent(task);
                while (parent !== null) {
                    level += 1;
                    parent = this.taskParent(parent);
                }
                return level;
            },
            taskTree: function (task) {
                var data = [];
                var current;
                var tasks = this.taskChildren(task);
                for (var i = 0, l = tasks.length; i < l; i++) {
                    current = tasks[i];
                    data.push(current);
                    if (current.get('expanded')) {
                        var children = this.taskTree(current);
                        data.push.apply(data, children);
                    }
                }
                return data;
            },
            update: function (task, taskInfo) {
                var that = this;
                var oldValue;
                var offsetChildren = function (parentTask, offset) {
                    var children = that.taskAllChildren(parentTask);
                    for (var i = 0, l = children.length; i < l; i++) {
                        children[i]._offset(offset);
                    }
                };
                var modelChangeHandler = function (e) {
                    var field = e.field;
                    var model = e.sender;
                    switch (field) {
                    case 'start':
                        that._resolveSummaryStart(that.taskParent(model));
                        offsetChildren(model, model.get(field).getTime() - oldValue.getTime());
                        break;
                    case 'end':
                        that._resolveSummaryEnd(that.taskParent(model));
                        break;
                    case 'percentComplete':
                        that._resolveSummaryPercentComplete(that.taskParent(model));
                        break;
                    case 'orderId':
                        that._reorderSiblings(model, oldValue);
                        break;
                    }
                };
                if (taskInfo.parentId !== undefined) {
                    oldValue = task.get('parentId');
                    if (oldValue !== taskInfo.parentId) {
                        task.set('parentId', taskInfo.parentId);
                        that._childRemoved(oldValue, task.get('orderId'));
                        task.set('orderId', that.taskSiblings(task).length - 1);
                        that._resolveSummaryFields(that.taskParent(task));
                    }
                    delete taskInfo.parentId;
                }
                task.bind('change', modelChangeHandler);
                for (var field in taskInfo) {
                    oldValue = task.get(field);
                    task.set(field, taskInfo[field]);
                }
                task.unbind('change', modelChangeHandler);
            },
            _resolveSummaryFields: function (summary) {
                if (!summary) {
                    return;
                }
                this._updateSummary(summary);
                if (!this.taskChildren(summary).length) {
                    return;
                }
                this._resolveSummaryStart(summary);
                this._resolveSummaryEnd(summary);
                this._resolveSummaryPercentComplete(summary);
            },
            _resolveSummaryStart: function (summary) {
                var that = this;
                var getSummaryStart = function (parentTask) {
                    var children = that.taskChildren(parentTask);
                    var min = children[0].start.getTime();
                    var currentMin;
                    for (var i = 1, l = children.length; i < l; i++) {
                        currentMin = children[i].start.getTime();
                        if (currentMin < min) {
                            min = currentMin;
                        }
                    }
                    return new Date(min);
                };
                this._updateSummaryRecursive(summary, 'start', getSummaryStart);
            },
            _resolveSummaryEnd: function (summary) {
                var that = this;
                var getSummaryEnd = function (parentTask) {
                    var children = that.taskChildren(parentTask);
                    var max = children[0].end.getTime();
                    var currentMax;
                    for (var i = 1, l = children.length; i < l; i++) {
                        currentMax = children[i].end.getTime();
                        if (currentMax > max) {
                            max = currentMax;
                        }
                    }
                    return new Date(max);
                };
                this._updateSummaryRecursive(summary, 'end', getSummaryEnd);
            },
            _resolveSummaryPercentComplete: function (summary) {
                var that = this;
                var getSummaryPercentComplete = function (parentTask) {
                    var children = that.taskChildren(parentTask);
                    var percentComplete = new Query(children).aggregate([{
                            field: 'percentComplete',
                            aggregate: 'average'
                        }]);
                    return percentComplete.percentComplete.average;
                };
                this._updateSummaryRecursive(summary, 'percentComplete', getSummaryPercentComplete);
            },
            _updateSummaryRecursive: function (summary, field, callback) {
                if (!summary) {
                    return;
                }
                var value = callback(summary);
                summary.set(field, value);
                var parent = this.taskParent(summary);
                if (parent) {
                    this._updateSummaryRecursive(parent, field, callback);
                }
            },
            _childRemoved: function (parentId, index) {
                var parent = parentId === null ? null : this.get(parentId);
                var children = this.taskChildren(parent);
                for (var i = index, l = children.length; i < l; i++) {
                    children[i].set('orderId', i);
                }
                this._resolveSummaryFields(parent);
            },
            _reorderSiblings: function (task, oldOrderId) {
                var orderId = task.get('orderId');
                var direction = orderId > oldOrderId;
                var startIndex = direction ? oldOrderId : orderId;
                var endIndex = direction ? orderId : oldOrderId;
                var newIndex = direction ? startIndex : startIndex + 1;
                var siblings = this.taskSiblings(task);
                endIndex = Math.min(endIndex, siblings.length - 1);
                for (var i = startIndex; i <= endIndex; i++) {
                    if (siblings[i] === task) {
                        continue;
                    }
                    siblings[i].set('orderId', newIndex);
                    newIndex += 1;
                }
            },
            _updateSummary: function (task) {
                if (task !== null) {
                    var childCount = this.taskChildren(task).length;
                    task.set('summary', childCount > 0);
                }
            },
            _toGanttTask: function (task) {
                if (!(task instanceof GanttTask)) {
                    var taskInfo = task;
                    task = this._createNewModel();
                    task.accept(taskInfo);
                }
                return task;
            }
        });
        GanttDataSource.create = createDataSource(GanttDataSource, 'GanttDataSource');
        extend(true, kendo.data, {
            GanttDataSource: GanttDataSource,
            GanttTask: GanttTask,
            GanttDependencyDataSource: GanttDependencyDataSource,
            GanttDependency: GanttDependency
        });
        var editors = {
            desktop: {
                dateRange: DATERANGEEDITOR,
                resources: RESOURCESEDITOR
            }
        };
        var Editor = kendo.Observable.extend({
            init: function (element, options) {
                kendo.Observable.fn.init.call(this);
                this.element = element;
                this.options = extend(true, {}, this.options, options);
                this.createButton = this.options.createButton;
            },
            fields: function (editors, model) {
                var that = this;
                var options = this.options;
                var messages = options.messages.editor;
                var resources = options.resources;
                var fields;
                var click = function (e) {
                    e.preventDefault();
                    resources.editor(that.container.find(DOT + Gantt.styles.popup.resourcesField), model);
                };
                if (options.editable.template) {
                    fields = $.map(model.fields, function (value, key) {
                        return { field: key };
                    });
                } else {
                    fields = [
                        {
                            field: 'title',
                            title: messages.title
                        },
                        {
                            field: 'start',
                            title: messages.start,
                            editor: editors.dateRange
                        },
                        {
                            field: 'end',
                            title: messages.end,
                            editor: editors.dateRange
                        },
                        {
                            field: 'percentComplete',
                            title: messages.percentComplete,
                            format: PERCENTAGE_FORMAT
                        }
                    ];
                    if (model.get(resources.field)) {
                        fields.push({
                            field: resources.field,
                            title: messages.resources,
                            messages: messages,
                            editor: editors.resources,
                            click: click,
                            styles: Gantt.styles.popup
                        });
                    }
                }
                return fields;
            },
            _buildEditTemplate: function (model, fields, editableFields) {
                var resources = this.options.resources;
                var template = this.options.editable.template;
                var settings = extend({}, kendo.Template, this.options.templateSettings);
                var paramName = settings.paramName;
                var popupStyles = Gantt.styles.popup;
                var html = '';
                if (template) {
                    if (typeof template === STRING) {
                        template = window.unescape(template);
                    }
                    html += kendo.template(template, settings)(model);
                } else {
                    for (var i = 0, length = fields.length; i < length; i++) {
                        var field = fields[i];
                        html += '<div class="' + popupStyles.editLabel + '"><label for="' + field.field + '">' + (field.title || field.field || '') + '</label></div>';
                        if (field.field === resources.field) {
                            html += '<div class="' + popupStyles.resourcesField + '" style="display:none"></div>';
                        }
                        if (!model.editable || model.editable(field.field)) {
                            editableFields.push(field);
                            html += '<div ' + kendo.attr('container-for') + '="' + field.field + '" class="' + popupStyles.editField + '"></div>';
                        } else {
                            var tmpl = '#:';
                            if (field.field) {
                                field = kendo.expr(field.field, paramName);
                                tmpl += field + '==null?\'\':' + field;
                            } else {
                                tmpl += '\'\'';
                            }
                            tmpl += '#';
                            tmpl = kendo.template(tmpl, settings);
                            html += '<div class="' + popupStyles.editField + '">' + tmpl(model) + '</div>';
                        }
                    }
                }
                return html;
            }
        });
        var PopupEditor = Editor.extend({
            destroy: function () {
                this.close();
                this.unbind();
            },
            editTask: function (task) {
                this.editable = this._createPopupEditor(task);
            },
            close: function () {
                var that = this;
                var destroy = function () {
                    if (that.editable) {
                        that.editable.destroy();
                        that.editable = null;
                        that.container = null;
                    }
                    if (that.popup) {
                        that.popup.destroy();
                        that.popup = null;
                    }
                };
                if (this.editable && this.container.is(':visible')) {
                    that.trigger('close', { window: that.container });
                    this.container.data('kendoWindow').bind('deactivate', destroy).close();
                } else {
                    destroy();
                }
            },
            showDialog: function (options) {
                var buttons = options.buttons;
                var popupStyles = Gantt.styles.popup;
                var html = kendo.format('<div class="{0}"><div class="{1}"><p class="{2}">{3}</p><div class="{4}">', popupStyles.form, popupStyles.formContainer, popupStyles.message, options.text, popupStyles.buttonsContainer);
                for (var i = 0, length = buttons.length; i < length; i++) {
                    html += this.createButton(buttons[i]);
                }
                html += '</div></div></div>';
                var wrapper = this.element;
                if (this.popup) {
                    this.popup.destroy();
                }
                var popup = this.popup = $(html).appendTo(wrapper).eq(0).on('click', DOT + popupStyles.button, function (e) {
                    e.preventDefault();
                    popup.close();
                    var buttonIndex = $(e.currentTarget).index();
                    buttons[buttonIndex].click();
                }).kendoWindow({
                    modal: true,
                    resizable: false,
                    draggable: false,
                    title: options.title,
                    visible: false,
                    deactivate: function () {
                        this.destroy();
                        wrapper.focus();
                    }
                }).getKendoWindow();
                popup.center().open();
            },
            _createPopupEditor: function (task) {
                var that = this;
                var options = {};
                var messages = this.options.messages;
                var ganttStyles = Gantt.styles;
                var popupStyles = ganttStyles.popup;
                var html = kendo.format('<div {0}="{1}" class="{2} {3}"><div class="{4}">', kendo.attr('uid'), task.uid, popupStyles.form, popupStyles.editForm, popupStyles.formContainer);
                var fields = this.fields(editors.desktop, task);
                var editableFields = [];
                html += this._buildEditTemplate(task, fields, editableFields);
                html += '<div class="' + popupStyles.buttonsContainer + '">';
                html += this.createButton({
                    name: 'update',
                    text: messages.save,
                    className: Gantt.styles.primary
                });
                html += this.createButton({
                    name: 'cancel',
                    text: messages.cancel
                });
                if (that.options.editable.destroy !== false) {
                    html += this.createButton({
                        name: 'delete',
                        text: messages.destroy
                    });
                }
                html += '</div></div></div>';
                var container = this.container = $(html).appendTo(this.element).eq(0).kendoWindow(extend({
                    modal: true,
                    resizable: false,
                    draggable: true,
                    title: messages.editor.editorTitle,
                    visible: false,
                    close: function (e) {
                        if (e.userTriggered) {
                            if (that.trigger('cancel', {
                                    container: container,
                                    model: task
                                })) {
                                e.preventDefault();
                            }
                        }
                    }
                }, options));
                var editableWidget = container.kendoEditable({
                    fields: editableFields,
                    model: task,
                    clearContainer: false,
                    validateOnBlur: true,
                    target: that.options.target
                }).data('kendoEditable');
                kendo.cycleForm(container);
                if (!this.trigger('edit', {
                        container: container,
                        model: task
                    })) {
                    container.data('kendoWindow').center().open();
                    container.on(CLICK + NS, DOT + ganttStyles.buttonCancel, function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger('cancel', {
                            container: container,
                            model: task
                        });
                    });
                    container.on(CLICK + NS, DOT + ganttStyles.buttonSave, function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        var fields = that.fields(editors.desktop, task);
                        var updateInfo = {};
                        var field;
                        for (var i = 0, length = fields.length; i < length; i++) {
                            field = fields[i].field;
                            updateInfo[field] = task.get(field);
                        }
                        that.trigger('save', {
                            container: container,
                            model: task,
                            updateInfo: updateInfo
                        });
                    });
                    container.on(CLICK + NS, DOT + ganttStyles.buttonDelete, function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        that.trigger('remove', {
                            container: container,
                            model: task
                        });
                    });
                } else {
                    that.trigger('cancel', {
                        container: container,
                        model: task
                    });
                }
                return editableWidget;
            }
        });
        var ResourceEditor = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.wrapper = this.element;
                this.model = this.options.model;
                this.resourcesField = this.options.resourcesField;
                this.createButton = this.options.createButton;
                this._initContainer();
                this._attachHandlers();
            },
            events: ['save'],
            open: function () {
                this.window.center().open();
            },
            close: function () {
                this.window.bind('deactivate', proxy(this.destroy, this)).close();
            },
            destroy: function () {
                this._dettachHandlers();
                this.grid.destroy();
                this.grid = null;
                this.window.destroy();
                this.window = null;
                Widget.fn.destroy.call(this);
                kendo.destroy(this.wrapper);
                this.element = this.wrapper = null;
            },
            _attachHandlers: function () {
                var ganttStyles = Gantt.styles;
                var grid = this.grid;
                var closeHandler = this._cancelProxy = proxy(this._cancel, this);
                this.container.on(CLICK + NS, DOT + ganttStyles.buttonCancel, this._cancelProxy);
                this._saveProxy = proxy(this._save, this);
                this.container.on(CLICK + NS, DOT + ganttStyles.buttonSave, this._saveProxy);
                this.window.bind('close', function (e) {
                    if (e.userTriggered) {
                        closeHandler(e);
                    }
                });
                grid.wrapper.on(CLICK + NS, 'input[type=\'checkbox\']', function () {
                    var element = $(this);
                    var row = $(element).closest('tr');
                    var model = grid.dataSource.getByUid(row.attr(kendo.attr('uid')));
                    var value = $(element).is(':checked') ? 1 : '';
                    model.set('value', value);
                });
            },
            _dettachHandlers: function () {
                this._cancelProxy = null;
                this._saveProxy = null;
                this.container.off(NS);
                this.grid.wrapper.off();
            },
            _cancel: function (e) {
                e.preventDefault();
                this.close();
            },
            _save: function (e) {
                e.preventDefault();
                this._updateModel();
                if (!this.wrapper.is(DOT + Gantt.styles.popup.resourcesField)) {
                    this.trigger('save', {
                        container: this.wrapper,
                        model: this.model
                    });
                }
                this.close();
            },
            _initContainer: function () {
                var that = this;
                var popupStyles = Gantt.styles.popup;
                var dom = kendo.format('<div class="{0} {1}"><div class="{2} {3}"/></div>"', popupStyles.form, popupStyles.editForm, popupStyles.formContainer, popupStyles.resourcesFormContainer);
                dom = $(dom);
                this.container = dom.find(DOT + popupStyles.resourcesFormContainer);
                this.window = dom.kendoWindow({
                    modal: true,
                    resizable: false,
                    draggable: true,
                    visible: false,
                    title: this.options.messages.resourcesEditorTitle,
                    open: function () {
                        that.grid.resize(true);
                    }
                }).data('kendoWindow');
                this._resourceGrid();
                this._createButtons();
            },
            _resourceGrid: function () {
                var that = this;
                var messages = this.options.messages;
                var element = $('<div id="resources-grid"/>').appendTo(this.container);
                this.grid = new kendo.ui.Grid(element, {
                    columns: [
                        {
                            field: 'name',
                            title: messages.resourcesHeader,
                            template: '<label><input type=\'checkbox\' value=\'#=name#\'' + '# if (value > 0 && value !== null) {#' + 'checked=\'checked\'' + '# } #' + '/>#=name#</labe>'
                        },
                        {
                            field: 'value',
                            title: messages.unitsHeader,
                            template: function (dataItem) {
                                var valueFormat = dataItem.format;
                                var value = dataItem.value !== null ? dataItem.value : '';
                                return valueFormat ? kendo.toString(value, valueFormat) : value;
                            }
                        }
                    ],
                    height: 280,
                    sortable: true,
                    editable: true,
                    filterable: true,
                    dataSource: {
                        data: that.options.data,
                        schema: {
                            model: {
                                id: 'id',
                                fields: {
                                    id: { from: 'id' },
                                    name: {
                                        from: 'name',
                                        type: 'string',
                                        editable: false
                                    },
                                    value: {
                                        from: 'value',
                                        type: 'number',
                                        defaultValue: ''
                                    },
                                    format: {
                                        from: 'format',
                                        type: 'string'
                                    }
                                }
                            }
                        }
                    },
                    save: function (e) {
                        var value = !!e.values.value;
                        e.container.parent().find('input[type=\'checkbox\']').prop('checked', value);
                    }
                });
            },
            _createButtons: function () {
                var buttons = this.options.buttons;
                var html = '<div class="' + Gantt.styles.popup.buttonsContainer + '">';
                for (var i = 0, length = buttons.length; i < length; i++) {
                    html += this.createButton(buttons[i]);
                }
                html += '</div>';
                this.container.append(html);
            },
            _updateModel: function () {
                var resources = [];
                var value;
                var data = this.grid.dataSource.data();
                for (var i = 0, length = data.length; i < length; i++) {
                    value = data[i].get('value');
                    if (value !== null && value > 0) {
                        resources.push(data[i]);
                    }
                }
                this.model[this.resourcesField] = resources;
            }
        });
        var Gantt = Widget.extend({
            init: function (element, options, events) {
                if (isArray(options)) {
                    options = { dataSource: options };
                }
                defaultCommands = {
                    append: {
                        text: 'Add Task',
                        action: 'add',
                        className: Gantt.styles.toolbar.appendButton,
                        iconClass: Gantt.styles.toolbar.iconPlus
                    },
                    pdf: {
                        text: 'Export to PDF',
                        className: Gantt.styles.toolbar.pdfButton,
                        iconClass: Gantt.styles.toolbar.iconPdf
                    }
                };
                Widget.fn.init.call(this, element, options);
                if (events) {
                    this._events = events;
                }
                this._wrapper();
                this._resources();
                if (!this.options.views || !this.options.views.length) {
                    this.options.views = [
                        'day',
                        'week',
                        'month'
                    ];
                }
                this._timeline();
                this._toolbar();
                this._footer();
                this._adjustDimensions();
                this._preventRefresh = true;
                this.view(this.timeline._selectedViewName);
                this._preventRefresh = false;
                this._dataSource();
                this._assignments();
                this._dropDowns();
                this._list();
                this._dependencies();
                this._resizable();
                this._scrollable();
                this._dataBind();
                this._attachEvents();
                this._createEditor();
                kendo.notify(this);
            },
            events: [
                'dataBinding',
                'dataBound',
                'add',
                'edit',
                'remove',
                'cancel',
                'save',
                'change',
                'navigate',
                'moveStart',
                'move',
                'moveEnd',
                'resizeStart',
                'resize',
                'resizeEnd',
                'columnResize'
            ],
            options: {
                name: 'Gantt',
                autoBind: true,
                navigatable: false,
                selectable: true,
                editable: true,
                resizable: false,
                columnResizeHandleWidth: defaultIndicatorWidth,
                columns: [],
                views: [],
                dataSource: {},
                dependencies: {},
                resources: {},
                assignments: {},
                taskTemplate: null,
                messages: {
                    save: 'Save',
                    cancel: 'Cancel',
                    destroy: 'Delete',
                    deleteTaskConfirmation: TASK_DELETE_CONFIRM,
                    deleteDependencyConfirmation: DEPENDENCY_DELETE_CONFIRM,
                    deleteTaskWindowTitle: 'Delete task',
                    deleteDependencyWindowTitle: 'Delete dependency',
                    views: {
                        day: 'Day',
                        week: 'Week',
                        month: 'Month',
                        year: 'Year',
                        start: 'Start',
                        end: 'End'
                    },
                    actions: {
                        append: 'Add Task',
                        addChild: 'Add Child',
                        insertBefore: 'Add Above',
                        insertAfter: 'Add Below',
                        pdf: 'Export to PDF'
                    },
                    editor: {
                        editorTitle: 'Task',
                        resourcesEditorTitle: 'Resources',
                        title: 'Title',
                        start: 'Start',
                        end: 'End',
                        percentComplete: 'Complete',
                        resources: 'Resources',
                        assignButton: 'Assign',
                        resourcesHeader: 'Resources',
                        unitsHeader: 'Units'
                    }
                },
                showWorkHours: true,
                showWorkDays: true,
                toolbar: null,
                workDayStart: new Date(1980, 1, 1, 8, 0, 0),
                workDayEnd: new Date(1980, 1, 1, 17, 0, 0),
                workWeekStart: 1,
                workWeekEnd: 5,
                hourSpan: 1,
                snap: true,
                height: 600,
                listWidth: '30%',
                rowHeight: null
            },
            select: function (value) {
                var list = this.list;
                if (!value) {
                    return list.select();
                }
                list.select(value);
                return;
            },
            clearSelection: function () {
                this.list.clearSelection();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                if (this.dataSource) {
                    this.dataSource.unbind('change', this._refreshHandler);
                    this.dataSource.unbind('progress', this._progressHandler);
                    this.dataSource.unbind('error', this._errorHandler);
                }
                if (this.dependencies) {
                    this.dependencies.unbind('change', this._dependencyRefreshHandler);
                    this.dependencies.unbind('error', this._dependencyErrorHandler);
                }
                if (this.timeline) {
                    this.timeline.unbind();
                    this.timeline.destroy();
                }
                if (this.list) {
                    this.list.unbind();
                    this.list.destroy();
                }
                if (this.footerDropDown) {
                    this.footerDropDown.destroy();
                }
                if (this.headerDropDown) {
                    this.headerDropDown.destroy();
                }
                if (this._editor) {
                    this._editor.destroy();
                }
                if (this._resizeDraggable) {
                    this._resizeDraggable.destroy();
                }
                this.toolbar.off(NS);
                if (supportsMedia) {
                    this._mediaQuery.removeListener(this._mediaQueryHandler);
                    this._mediaQuery = null;
                }
                $(window).off('resize' + NS, this._resizeHandler);
                $(this.wrapper).off(NS);
                this.toolbar = null;
                this.footer = null;
            },
            setOptions: function (options) {
                var newOptions = kendo.deepExtend({}, this.options, options);
                var events = this._events;
                if (!options.views) {
                    var selectedView = this.view().name;
                    newOptions.views = $.map(this.options.views, function (view) {
                        var isSettings = isPlainObject(view);
                        var name = isSettings ? typeof view.type !== 'string' ? view.title : view.type : view;
                        if (selectedView === name) {
                            if (isSettings) {
                                view.selected = true;
                            } else {
                                view = {
                                    type: name,
                                    selected: true
                                };
                            }
                        } else if (isSettings) {
                            view.selected = false;
                        }
                        return view;
                    });
                }
                if (!options.dataSource) {
                    newOptions.dataSource = this.dataSource;
                }
                if (!options.dependencies) {
                    newOptions.dependencies = this.dependencies;
                }
                if (!options.resources) {
                    newOptions.resources = this.resources;
                }
                if (!options.assignments) {
                    newOptions.assignments = this.assignments;
                }
                this.destroy();
                this.element.empty();
                this.options = null;
                this.init(this.element, newOptions, events);
                Widget.fn._setEvents.call(this, newOptions);
            },
            _attachEvents: function () {
                this._resizeHandler = proxy(this.resize, this, false);
                $(window).on('resize' + NS, this._resizeHandler);
            },
            _wrapper: function () {
                var ganttStyles = Gantt.styles;
                var splitBarHandleClassName = [
                    ganttStyles.icon,
                    ganttStyles.resizeHandle
                ].join(' ');
                var options = this.options;
                var height = options.height;
                var width = options.width;
                this.wrapper = this.element.addClass(ganttStyles.wrapper).append('<div class=\'' + ganttStyles.listWrapper + '\'><div></div></div>').append('<div class=\'' + ganttStyles.splitBarWrapper + '\'><div class=\'' + splitBarHandleClassName + '\'></div></div>').append('<div class=\'' + ganttStyles.timelineWrapper + '\'><div></div></div>');
                this.wrapper.find(DOT + ganttStyles.list).width(options.listWidth);
                if (height) {
                    this.wrapper.height(height);
                }
                if (width) {
                    this.wrapper.width(width);
                }
                if (options.rowHeight) {
                    this.wrapper.addClass(ganttStyles.rowHeight);
                }
            },
            _toolbar: function () {
                var that = this;
                var ganttStyles = Gantt.styles;
                var viewsSelector = DOT + ganttStyles.toolbar.views + ' > li';
                var pdfSelector = DOT + ganttStyles.toolbar.pdfButton;
                var toggleSelector = DOT + ganttStyles.buttonToggle;
                var contentSelector = DOT + ganttStyles.gridContent;
                var treelist = $(DOT + ganttStyles.list);
                var timeline = $(DOT + ganttStyles.timeline);
                var hoveredClassName = ganttStyles.hovered;
                var actions = this.options.toolbar;
                var actionsWrap = $('<div class=\'' + ganttStyles.toolbar.actions + '\'>');
                var toolbar;
                var views;
                var toggleButton;
                var handler = function (e) {
                    if (e.matches) {
                        treelist.css({
                            'display': 'none',
                            'max-width': 0
                        });
                    } else {
                        treelist.css({
                            'display': 'inline-block',
                            'width': '30%',
                            'max-width': 'none'
                        });
                        timeline.css('display', 'inline-block');
                        that.refresh();
                        timeline.find(contentSelector).scrollTop(that.scrollTop);
                    }
                    that._resize();
                };
                if (!isFunction(actions)) {
                    actions = typeof actions === STRING ? actions : this._actions(actions);
                    actions = proxy(kendo.template(actions), this);
                }
                toggleButton = $(TOGGLE_BUTTON_TEMPLATE({ styles: ganttStyles.toolbar }));
                views = $(HEADER_VIEWS_TEMPLATE({
                    ns: kendo.ns,
                    views: this.timeline.views,
                    styles: ganttStyles.toolbar
                }));
                actionsWrap.append(actions({}));
                toolbar = $('<div class=\'' + ganttStyles.toolbar.headerWrapper + '\'>').append(toggleButton).append(views).append(actionsWrap);
                if (views.find('li').length > 1) {
                    views.prepend(VIEWBUTTONTEMPLATE({ styles: ganttStyles.toolbar }));
                }
                this.wrapper.prepend(toolbar);
                this.toolbar = toolbar;
                if (supportsMedia) {
                    this._mediaQueryHandler = proxy(handler, this);
                    this._mediaQuery = window.matchMedia('(max-width: 480px)');
                    this._mediaQuery.addListener(this._mediaQueryHandler);
                }
                toolbar.on(CLICK + NS, viewsSelector, function (e) {
                    e.preventDefault();
                    var list = that.list;
                    var name = $(this).attr(kendo.attr('name'));
                    var currentView = views.find(DOT + ganttStyles.toolbar.currentView);
                    if (currentView.is(':visible')) {
                        currentView.parent().toggleClass(ganttStyles.toolbar.expanded);
                    }
                    if (list.editable && list.editable.trigger('validate')) {
                        return;
                    }
                    if (!that.trigger('navigate', { view: name })) {
                        that.view(name);
                    }
                }).on(CLICK + NS, pdfSelector, function (e) {
                    e.preventDefault();
                    that.saveAsPDF();
                }).on(CLICK + NS, toggleSelector, function (e) {
                    e.preventDefault();
                    if (treelist.is(':visible')) {
                        treelist.css({
                            'display': 'none',
                            'width': '0'
                        });
                        timeline.css({
                            'display': 'inline-block',
                            'width': '100%'
                        });
                        that.refresh();
                        timeline.find(contentSelector).scrollTop(that.scrollTop);
                    } else {
                        timeline.css({
                            'display': 'none',
                            'width': 0
                        });
                        treelist.css({
                            'display': 'inline-block',
                            'width': '100%',
                            'max-width': 'none'
                        }).find(contentSelector).scrollTop(that.scrollTop);
                    }
                    that._resize();
                });
                this.wrapper.find(DOT + ganttStyles.toolbar.toolbar + ' li').hover(function () {
                    $(this).addClass(hoveredClassName);
                }, function () {
                    $(this).removeClass(hoveredClassName);
                });
            },
            _actions: function () {
                var options = this.options;
                var editable = options.editable;
                var actions = options.toolbar;
                var html = '';
                if (!isArray(actions)) {
                    if (editable && editable.create !== false) {
                        actions = ['append'];
                    } else {
                        return html;
                    }
                }
                for (var i = 0, length = actions.length; i < length; i++) {
                    html += this._createButton(actions[i]);
                }
                return html;
            },
            _footer: function () {
                var editable = this.options.editable;
                if (!editable || editable.create === false) {
                    return;
                }
                var ganttStyles = Gantt.styles.toolbar;
                var messages = this.options.messages.actions;
                var button = $(kendo.template(BUTTON_TEMPLATE)(extend(true, { styles: ganttStyles }, defaultCommands.append, { text: messages.append })));
                var actionsWrap = $('<div class=\'' + ganttStyles.actions + '\'>').append(button);
                var footer = $('<div class=\'' + ganttStyles.footerWrapper + '\'>').append(actionsWrap);
                this.wrapper.append(footer);
                this.footer = footer;
            },
            _createButton: function (command) {
                var template = command.template || BUTTON_TEMPLATE;
                var messages = this.options.messages.actions;
                var commandName = typeof command === STRING ? command : command.name || command.text;
                var className = defaultCommands[commandName] ? defaultCommands[commandName].className : 'k-gantt-' + (commandName || '').replace(/\s/g, '');
                var options = {
                    iconClass: '',
                    action: '',
                    text: commandName,
                    className: className,
                    styles: Gantt.styles.toolbar
                };
                if (!commandName && !(isPlainObject(command) && command.template)) {
                    throw new Error('Custom commands should have name specified');
                }
                options = extend(true, options, defaultCommands[commandName], { text: messages[commandName] });
                if (isPlainObject(command)) {
                    if (command.className && inArray(options.className, command.className.split(' ')) < 0) {
                        command.className += ' ' + options.className;
                    }
                    options = extend(true, options, command);
                }
                return kendo.template(template)(options);
            },
            _adjustDimensions: function () {
                var element = this.element;
                var ganttStyles = Gantt.styles;
                var listSelector = DOT + ganttStyles.list;
                var timelineSelector = DOT + ganttStyles.timeline;
                var splitBarSelector = DOT + ganttStyles.splitBar;
                var toolbarHeight = outerHeight(this.toolbar);
                var footerHeight = this.footer ? outerHeight(this.footer) : 0;
                var totalHeight = element.height();
                var totalWidth = element.width();
                var splitBarWidth = outerWidth(element.find(splitBarSelector));
                var treeListWidth = outerWidth(element.find(listSelector));
                element.children([
                    listSelector,
                    timelineSelector,
                    splitBarSelector
                ].join(',')).height(totalHeight - (toolbarHeight + footerHeight)).end().children(timelineSelector).width(totalWidth - (splitBarWidth + treeListWidth));
                if (totalWidth < treeListWidth + splitBarWidth) {
                    element.find(listSelector).width(totalWidth - splitBarWidth);
                }
            },
            _scrollTo: function (value) {
                var view = this.timeline.view();
                var list = this.list;
                var attr = kendo.attr('uid');
                var id = typeof value === 'string' ? value : value.closest('tr' + selector()).attr(attr);
                var action;
                var scrollTarget;
                var scrollIntoView = function () {
                    if (scrollTarget.length !== 0) {
                        action();
                    }
                };
                if (view.content.is(':visible')) {
                    scrollTarget = view.content.find(selector(id));
                    action = function () {
                        view._scrollTo(scrollTarget);
                    };
                } else {
                    scrollTarget = list.content.find(selector(id));
                    action = function () {
                        scrollTarget.get(0).scrollIntoView();
                    };
                }
                scrollIntoView();
            },
            _dropDowns: function () {
                var that = this;
                var actionsSelector = DOT + Gantt.styles.toolbar.actions;
                var actionMessages = this.options.messages.actions;
                var timeline = this.timeline;
                var editable = this.options.editable;
                var handler = function (e) {
                    var type = e.type;
                    var orderId;
                    var dataSource = that.dataSource;
                    var task = dataSource._createNewModel();
                    var selected = that.dataItem(that.select());
                    var parent = dataSource.taskParent(selected);
                    var firstSlot = timeline.view()._timeSlots()[0];
                    var target = type === 'add' ? selected : parent;
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        return;
                    }
                    task.set('title', 'New task');
                    if (target) {
                        task.set('parentId', target.get('id'));
                        task.set('start', target.get('start'));
                        task.set('end', target.get('end'));
                    } else {
                        task.set('start', firstSlot.start);
                        task.set('end', firstSlot.end);
                    }
                    if (type !== 'add') {
                        orderId = selected.get('orderId');
                        orderId = type === 'insert-before' ? orderId : orderId + 1;
                    }
                    that._createTask(task, orderId);
                };
                if (!editable || editable.create === false) {
                    return;
                }
                this.footerDropDown = new TaskDropDown(this.footer.children(actionsSelector).eq(0), {
                    messages: { actions: actionMessages },
                    direction: 'up',
                    animation: { open: { effects: 'slideIn:up' } },
                    navigatable: that.options.navigatable
                });
                this.headerDropDown = new TaskDropDown(this.toolbar.children(actionsSelector).eq(0), {
                    messages: { actions: actionMessages },
                    navigatable: that.options.navigatable
                });
                this.footerDropDown.bind('command', handler);
                this.headerDropDown.bind('command', handler);
            },
            _list: function () {
                var that = this;
                var navigatable = that.options.navigatable;
                var ganttStyles = Gantt.styles;
                var listWrapper = this.wrapper.find(DOT + ganttStyles.list);
                var element = listWrapper.find('> div');
                var toggleButtons = this.wrapper.find(DOT + ganttStyles.toolbar.actions + ' > button');
                var options = {
                    columns: this.options.columns || [],
                    dataSource: this.dataSource,
                    selectable: this.options.selectable,
                    editable: this.options.editable,
                    resizable: this.options.resizable,
                    columnResizeHandleWidth: this.options.columnResizeHandleWidth,
                    listWidth: outerWidth(listWrapper),
                    resourcesField: this.resources.field,
                    rowHeight: this.options.rowHeight
                };
                var columns = options.columns;
                var column;
                var restoreFocus = function () {
                    if (navigatable) {
                        that._current(that._cachedCurrent);
                        focusTable(that.list.content.find('table'), true);
                    }
                    delete that._cachedCurrent;
                };
                for (var i = 0; i < columns.length; i++) {
                    column = columns[i];
                    if (column.field === this.resources.field && typeof column.editor !== 'function') {
                        column.editor = proxy(this._createResourceEditor, this);
                    }
                }
                this.list = new kendo.ui.GanttList(element, options);
                this.list.bind('render', function () {
                    that._navigatable();
                }, true).bind('edit', function (e) {
                    that._cachedCurrent = e.cell;
                    if (that.trigger('edit', {
                            task: e.model,
                            container: e.cell
                        })) {
                        e.preventDefault();
                    }
                }).bind('cancel', function (e) {
                    if (that.trigger('cancel', {
                            task: e.model,
                            container: e.cell
                        })) {
                        e.preventDefault();
                    }
                    restoreFocus();
                }).bind('update', function (e) {
                    that._updateTask(e.task, e.updateInfo);
                    restoreFocus();
                }).bind('change', function () {
                    that.trigger('change');
                    var selection = that.list.select();
                    if (selection.length) {
                        toggleButtons.removeAttr('data-action', 'add');
                        that.timeline.select('[data-uid=\'' + selection.attr('data-uid') + '\']');
                    } else {
                        toggleButtons.attr('data-action', 'add');
                        that.timeline.clearSelection();
                    }
                }).bind('columnResize', function (e) {
                    that.trigger('columnResize', {
                        column: e.column,
                        oldWidth: e.oldWidth,
                        newWidth: e.newWidth
                    });
                });
            },
            _timeline: function () {
                var that = this;
                var ganttStyles = Gantt.styles;
                var options = trimOptions(extend(true, { resourcesField: this.resources.field }, this.options));
                var element = this.wrapper.find(DOT + ganttStyles.timeline + ' > div');
                var currentViewSelector = DOT + ganttStyles.toolbar.currentView + ' > ' + DOT + ganttStyles.toolbar.link;
                this.timeline = new kendo.ui.GanttTimeline(element, options);
                this.timeline.bind('navigate', function (e) {
                    var viewName = e.view.replace(/\./g, '\\.').toLowerCase();
                    var text = that.toolbar.find(DOT + ganttStyles.toolbar.views + ' > li').removeClass(ganttStyles.selected).end().find(DOT + ganttStyles.toolbar.viewButton + '-' + viewName).addClass(ganttStyles.selected).find(DOT + ganttStyles.toolbar.link).text();
                    that.toolbar.find(currentViewSelector).text(text);
                    that.refresh();
                }).bind('moveStart', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        e.preventDefault();
                        return;
                    }
                    if (that.trigger('moveStart', { task: e.task })) {
                        e.preventDefault();
                    }
                }).bind('move', function (e) {
                    var task = e.task;
                    var start = e.start;
                    var end = new Date(start.getTime() + task.duration());
                    if (that.trigger('move', {
                            task: task,
                            start: start,
                            end: end
                        })) {
                        e.preventDefault();
                    }
                }).bind('moveEnd', function (e) {
                    var task = e.task;
                    var start = e.start;
                    var end = new Date(start.getTime() + task.duration());
                    if (!that.trigger('moveEnd', {
                            task: task,
                            start: start,
                            end: end
                        })) {
                        that._updateTask(that.dataSource.getByUid(task.uid), {
                            start: start,
                            end: end
                        });
                    }
                }).bind('resizeStart', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        e.preventDefault();
                        return;
                    }
                    if (that.trigger('resizeStart', { task: e.task })) {
                        e.preventDefault();
                    }
                }).bind('resize', function (e) {
                    if (that.trigger('resize', {
                            task: e.task,
                            start: e.start,
                            end: e.end
                        })) {
                        e.preventDefault();
                    }
                }).bind('resizeEnd', function (e) {
                    var task = e.task;
                    var updateInfo = {};
                    if (e.resizeStart) {
                        updateInfo.start = e.start;
                    } else {
                        updateInfo.end = e.end;
                    }
                    if (!that.trigger('resizeEnd', {
                            task: task,
                            start: e.start,
                            end: e.end
                        })) {
                        that._updateTask(that.dataSource.getByUid(task.uid), updateInfo);
                    }
                }).bind('percentResizeStart', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        e.preventDefault();
                    }
                }).bind('percentResizeEnd', function (e) {
                    that._updateTask(that.dataSource.getByUid(e.task.uid), { percentComplete: e.percentComplete });
                }).bind('dependencyDragStart', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        e.preventDefault();
                    }
                }).bind('dependencyDragEnd', function (e) {
                    var dependency = that.dependencies._createNewModel({
                        type: e.type,
                        predecessorId: e.predecessor.id,
                        successorId: e.successor.id
                    });
                    that._createDependency(dependency);
                }).bind('select', function (e) {
                    var editable = that.list.editable;
                    if (editable) {
                        editable.trigger('validate');
                    }
                    that.select('[data-uid=\'' + e.uid + '\']');
                }).bind('editTask', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        return;
                    }
                    that.editTask(e.uid);
                }).bind('clear', function () {
                    that.clearSelection();
                }).bind('removeTask', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        return;
                    }
                    that.removeTask(that.dataSource.getByUid(e.uid));
                }).bind('removeDependency', function (e) {
                    var editable = that.list.editable;
                    if (editable && editable.trigger('validate')) {
                        return;
                    }
                    that.removeDependency(that.dependencies.getByUid(e.uid));
                });
            },
            _dataSource: function () {
                var options = this.options;
                var dataSource = options.dataSource;
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                if (this.dataSource && this._refreshHandler) {
                    this.dataSource.unbind('change', this._refreshHandler).unbind('progress', this._progressHandler).unbind('error', this._errorHandler);
                } else {
                    this._refreshHandler = proxy(this.refresh, this);
                    this._progressHandler = proxy(this._requestStart, this);
                    this._errorHandler = proxy(this._error, this);
                }
                this.dataSource = kendo.data.GanttDataSource.create(dataSource).bind('change', this._refreshHandler).bind('progress', this._progressHandler).bind('error', this._errorHandler);
            },
            _dependencies: function () {
                var dependencies = this.options.dependencies || {};
                var dataSource = isArray(dependencies) ? { data: dependencies } : dependencies;
                if (this.dependencies && this._dependencyRefreshHandler) {
                    this.dependencies.unbind('change', this._dependencyRefreshHandler).unbind('error', this._dependencyErrorHandler);
                } else {
                    this._dependencyRefreshHandler = proxy(this.refreshDependencies, this);
                    this._dependencyErrorHandler = proxy(this._error, this);
                }
                this.dependencies = kendo.data.GanttDependencyDataSource.create(dataSource).bind('change', this._dependencyRefreshHandler).bind('error', this._dependencyErrorHandler);
            },
            _resources: function () {
                var resources = this.options.resources;
                var dataSource = resources.dataSource || {};
                this.resources = {
                    field: 'resources',
                    dataTextField: 'name',
                    dataColorField: 'color',
                    dataFormatField: 'format'
                };
                extend(this.resources, resources);
                this.resources.dataSource = kendo.data.DataSource.create(dataSource);
            },
            _assignments: function () {
                var assignments = this.options.assignments;
                var dataSource = assignments.dataSource || {};
                if (this.assignments) {
                    this.assignments.dataSource.unbind('change', this._assignmentsRefreshHandler);
                } else {
                    this._assignmentsRefreshHandler = proxy(this.refresh, this);
                }
                this.assignments = {
                    dataTaskIdField: 'taskId',
                    dataResourceIdField: 'resourceId',
                    dataValueField: 'value'
                };
                extend(this.assignments, assignments);
                this.assignments.dataSource = kendo.data.DataSource.create(dataSource);
                this.assignments.dataSource.bind('change', this._assignmentsRefreshHandler);
            },
            _createEditor: function () {
                var that = this;
                var editor = this._editor = new PopupEditor(this.wrapper, extend({}, this.options, {
                    target: this,
                    resources: {
                        field: this.resources.field,
                        editor: proxy(this._createResourceEditor, this)
                    },
                    createButton: proxy(this._createPopupButton, this)
                }));
                editor.bind('cancel', function (e) {
                    var task = that.dataSource.getByUid(e.model.uid);
                    if (that.trigger('cancel', {
                            container: e.container,
                            task: task
                        })) {
                        e.preventDefault();
                        return;
                    }
                    that.cancelTask();
                }).bind('edit', function (e) {
                    var task = that.dataSource.getByUid(e.model.uid);
                    if (that.trigger('edit', {
                            container: e.container,
                            task: task
                        })) {
                        e.preventDefault();
                    }
                }).bind('save', function (e) {
                    var task = that.dataSource.getByUid(e.model.uid);
                    that.saveTask(task, e.updateInfo);
                }).bind('remove', function (e) {
                    that.removeTask(e.model.uid);
                }).bind('close', that._onDialogClose);
            },
            _onDialogClose: function () {
            },
            _createResourceEditor: function (container, options) {
                var that = this;
                var model = options instanceof ObservableObject ? options : options.model;
                var id = model.get('id');
                var messages = this.options.messages;
                var resourcesField = that.resources.field;
                var editor = this._resourceEditor = new ResourceEditor(container, {
                    resourcesField: resourcesField,
                    data: this._wrapResourceData(id),
                    model: model,
                    messages: extend({}, messages.editor),
                    buttons: [
                        {
                            name: 'update',
                            text: messages.save,
                            className: Gantt.styles.primary
                        },
                        {
                            name: 'cancel',
                            text: messages.cancel
                        }
                    ],
                    createButton: proxy(this._createPopupButton, this),
                    save: function (e) {
                        that._updateAssignments(e.model.get('id'), e.model.get(resourcesField));
                    }
                });
                editor.open();
            },
            _createPopupButton: function (command) {
                var commandName = command.name || command.text;
                var options = {
                    className: Gantt.styles.popup.button + ' k-gantt-' + (commandName || '').replace(/\s/g, ''),
                    text: commandName,
                    attr: ''
                };
                if (!commandName && !(isPlainObject(command) && command.template)) {
                    throw new Error('Custom commands should have name specified');
                }
                if (isPlainObject(command)) {
                    if (command.className) {
                        command.className += ' ' + options.className;
                    }
                    options = extend(true, options, command);
                }
                return kendo.template(COMMAND_BUTTON_TEMPLATE)(options);
            },
            view: function (type) {
                return this.timeline.view(type);
            },
            range: function (range) {
                var dataSource = this.dataSource;
                var view = this.view();
                var timeline = this.timeline;
                if (range) {
                    view.options.range = {
                        start: range.start,
                        end: range.end
                    };
                    timeline._render(dataSource.taskTree());
                    timeline._renderDependencies(this.dependencies.view());
                }
                return {
                    start: view.start,
                    end: view.end
                };
            },
            date: function (date) {
                var view = this.view();
                if (date) {
                    view.options.date = date;
                    view._scrollToDate(date);
                }
                return view.options.date;
            },
            dataItem: function (value) {
                if (!value) {
                    return null;
                }
                var list = this.list;
                var element = list.content.find(value);
                return list._modelFromElement(element);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                this.list._setDataSource(this.dataSource);
                if (this.options.autoBind) {
                    dataSource.fetch();
                }
            },
            setDependenciesDataSource: function (dependencies) {
                this.options.dependencies = dependencies;
                this._dependencies();
                if (this.options.autoBind) {
                    dependencies.fetch();
                }
            },
            items: function () {
                return this.wrapper.children('.k-task');
            },
            _updateAssignments: function (id, resources) {
                var dataSource = this.assignments.dataSource;
                var taskId = this.assignments.dataTaskIdField;
                var resourceId = this.assignments.dataResourceIdField;
                var hasMatch = false;
                var assignments = new Query(dataSource.view()).filter({
                    field: taskId,
                    operator: 'eq',
                    value: id
                }).toArray();
                var assignment;
                var resource;
                var value;
                while (assignments.length) {
                    assignment = assignments[0];
                    for (var i = 0, length = resources.length; i < length; i++) {
                        resource = resources[i];
                        if (assignment.get(resourceId) === resource.get('id')) {
                            value = resources[i].get('value');
                            this._updateAssignment(assignment, value);
                            resources.splice(i, 1);
                            hasMatch = true;
                            break;
                        }
                    }
                    if (!hasMatch) {
                        this._removeAssignment(assignment);
                    }
                    hasMatch = false;
                    assignments.shift();
                }
                for (var j = 0, newLength = resources.length; j < newLength; j++) {
                    resource = resources[j];
                    this._createAssignment(resource, id);
                }
                dataSource.sync();
            },
            cancelTask: function () {
                var editor = this._editor;
                var container = editor.container;
                if (container) {
                    editor.close();
                }
            },
            editTask: function (uid) {
                var task = typeof uid === 'string' ? this.dataSource.getByUid(uid) : uid;
                if (!task) {
                    return;
                }
                var taskCopy = this.dataSource._createNewModel(task.toJSON());
                taskCopy.uid = task.uid;
                this.cancelTask();
                this._editTask(taskCopy);
            },
            _editTask: function (task) {
                this._editor.editTask(task);
            },
            saveTask: function (task, updateInfo) {
                var editor = this._editor;
                var container = editor.container;
                var editable = editor.editable;
                if (container && editable && editable.end()) {
                    this._updateTask(task, updateInfo);
                }
            },
            _updateTask: function (task, updateInfo) {
                var resourcesField = this.resources.field;
                if (!this.trigger('save', {
                        task: task,
                        values: updateInfo
                    })) {
                    this._preventRefresh = true;
                    this.dataSource.update(task, updateInfo);
                    if (updateInfo[resourcesField]) {
                        this._updateAssignments(task.get('id'), updateInfo[resourcesField]);
                    }
                    this._syncDataSource();
                }
            },
            _updateAssignment: function (assignment, value) {
                var resourceValueField = this.assignments.dataValueField;
                assignment.set(resourceValueField, value);
            },
            removeTask: function (uid) {
                var that = this;
                var task = typeof uid === 'string' ? this.dataSource.getByUid(uid) : uid;
                if (!task) {
                    return;
                }
                this._taskConfirm(function (cancel) {
                    if (!cancel) {
                        that._removeTask(task);
                    }
                }, task);
            },
            _createTask: function (task, index) {
                if (!this.trigger('add', {
                        task: task,
                        dependency: null
                    })) {
                    var dataSource = this.dataSource;
                    this._preventRefresh = true;
                    if (index === undefined) {
                        dataSource.add(task);
                    } else {
                        dataSource.insert(index, task);
                    }
                    this._scrollToUid = task.uid;
                    this._syncDataSource();
                }
            },
            _createDependency: function (dependency) {
                if (!this.trigger('add', {
                        task: null,
                        dependency: dependency
                    })) {
                    this._preventDependencyRefresh = true;
                    this.dependencies.add(dependency);
                    this._preventDependencyRefresh = false;
                    this.dependencies.sync();
                }
            },
            _createAssignment: function (resource, id) {
                var assignments = this.assignments;
                var dataSource = assignments.dataSource;
                var taskId = assignments.dataTaskIdField;
                var resourceId = assignments.dataResourceIdField;
                var resourceValue = assignments.dataValueField;
                var assignment = dataSource._createNewModel();
                assignment[taskId] = id;
                assignment[resourceId] = resource.get('id');
                assignment[resourceValue] = resource.get('value');
                dataSource.add(assignment);
            },
            removeDependency: function (uid) {
                var that = this;
                var dependency = typeof uid === 'string' ? this.dependencies.getByUid(uid) : uid;
                if (!dependency) {
                    return;
                }
                this._dependencyConfirm(function (cancel) {
                    if (!cancel) {
                        that._removeDependency(dependency);
                    }
                }, dependency);
            },
            _removeTaskDependencies: function (task, dependencies) {
                this._preventDependencyRefresh = true;
                for (var i = 0, length = dependencies.length; i < length; i++) {
                    this.dependencies.remove(dependencies[i]);
                }
                this._preventDependencyRefresh = false;
                this.dependencies.sync();
            },
            _removeTaskAssignments: function (task) {
                var dataSource = this.assignments.dataSource;
                var assignments = dataSource.view();
                var filter = {
                    field: this.assignments.dataTaskIdField,
                    operator: 'eq',
                    value: task.get('id')
                };
                assignments = new Query(assignments).filter(filter).toArray();
                this._preventRefresh = true;
                for (var i = 0, length = assignments.length; i < length; i++) {
                    dataSource.remove(assignments[i]);
                }
                this._preventRefresh = false;
                dataSource.sync();
            },
            _removeTask: function (task) {
                var dependencies = this.dependencies.dependencies(task.id);
                if (!this.trigger('remove', {
                        task: task,
                        dependencies: dependencies
                    })) {
                    this._removeTaskDependencies(task, dependencies);
                    this._removeTaskAssignments(task);
                    this._preventRefresh = true;
                    if (this.dataSource.remove(task)) {
                        this._syncDataSource();
                    }
                    this._preventRefresh = false;
                }
            },
            _removeDependency: function (dependency) {
                if (!this.trigger('remove', {
                        task: null,
                        dependencies: [dependency]
                    })) {
                    if (this.dependencies.remove(dependency)) {
                        this.dependencies.sync();
                    }
                }
            },
            _removeAssignment: function (assignment) {
                this.assignments.dataSource.remove(assignment);
            },
            _taskConfirm: function (callback, task) {
                var messages = this.options.messages;
                this._confirm(callback, {
                    model: task,
                    text: messages.deleteTaskConfirmation,
                    title: messages.deleteTaskWindowTitle
                });
            },
            _dependencyConfirm: function (callback, dependency) {
                var messages = this.options.messages;
                this._confirm(callback, {
                    model: dependency,
                    text: messages.deleteDependencyConfirmation,
                    title: messages.deleteDependencyWindowTitle
                });
            },
            _confirm: function (callback, options) {
                var editable = this.options.editable;
                var messages;
                var buttons;
                if (editable === true || editable.confirmation !== false) {
                    messages = this.options.messages;
                    buttons = [
                        {
                            name: 'delete',
                            text: messages.destroy,
                            className: Gantt.styles.primary,
                            click: function () {
                                callback();
                            }
                        },
                        {
                            name: 'cancel',
                            text: messages.cancel,
                            click: function () {
                                callback(true);
                            }
                        }
                    ];
                    this.showDialog(extend(true, {}, options, { buttons: buttons }));
                } else {
                    callback();
                }
            },
            showDialog: function (options) {
                this._editor.showDialog(options);
            },
            refresh: function () {
                if (this._preventRefresh || this.list.editable) {
                    return;
                }
                this._progress(false);
                var dataSource = this.dataSource;
                var taskTree = dataSource.taskTree();
                var scrollToUid = this._scrollToUid;
                var current;
                var cachedUid;
                var cachedIndex = -1;
                if (this.current) {
                    cachedUid = this.current.closest('tr').attr(kendo.attr('uid'));
                    cachedIndex = this.current.index();
                }
                if (this.trigger('dataBinding')) {
                    return;
                }
                if (this.resources.dataSource.data().length !== 0) {
                    this._assignResources(taskTree);
                }
                if (this._editor) {
                    this._editor.close();
                }
                this.clearSelection();
                this.list._render(taskTree);
                this.timeline._render(taskTree);
                this.timeline._renderDependencies(this.dependencies.view());
                if (scrollToUid) {
                    this._scrollTo(scrollToUid);
                    this.select(selector(scrollToUid));
                }
                if ((scrollToUid || cachedUid) && cachedIndex >= 0) {
                    current = this.list.content.find('tr' + selector(scrollToUid || cachedUid) + ' > td:eq(' + cachedIndex + ')');
                    this._current(current);
                }
                this._scrollToUid = null;
                this.trigger('dataBound');
            },
            refreshDependencies: function () {
                if (this._preventDependencyRefresh) {
                    return;
                }
                if (this.trigger('dataBinding')) {
                    return;
                }
                this.timeline._renderDependencies(this.dependencies.view());
                this.trigger('dataBound');
            },
            _assignResources: function (taskTree) {
                var resources = this.resources;
                var assignments = this.assignments;
                var groupAssigments = function () {
                    var data = assignments.dataSource.view();
                    var group = { field: assignments.dataTaskIdField };
                    data = new Query(data).group(group).toArray();
                    return data;
                };
                var assigments = groupAssigments();
                var applyTaskResource = function (task, action) {
                    var taskId = task.get('id');
                    kendo.setter(resources.field)(task, new ObservableArray([]));
                    for (var i = 0, length = assigments.length; i < length; i++) {
                        if (assigments[i].value === taskId) {
                            action(task, assigments[i].items);
                        }
                    }
                };
                var wrapTask = function (task, items) {
                    for (var j = 0, length = items.length; j < length; j++) {
                        var item = items[j];
                        var resource = resources.dataSource.get(item.get(assignments.dataResourceIdField));
                        var resourceValue = item.get(assignments.dataValueField);
                        var resourcedId = item.get(assignments.dataResourceIdField);
                        var valueFormat = resource.get(resources.dataFormatField) || PERCENTAGE_FORMAT;
                        var formatedValue = kendo.toString(resourceValue, valueFormat);
                        task[resources.field].push(new ObservableObject({
                            id: resourcedId,
                            name: resource.get(resources.dataTextField),
                            color: resource.get(resources.dataColorField),
                            value: resourceValue,
                            formatedValue: formatedValue
                        }));
                    }
                };
                for (var i = 0, length = taskTree.length; i < length; i++) {
                    applyTaskResource(taskTree[i], wrapTask);
                }
            },
            _wrapResourceData: function (id) {
                var that = this;
                var result = [];
                var resource;
                var resources = this.resources.dataSource.view();
                var assignments = this.assignments.dataSource.view();
                var taskAssignments = new Query(assignments).filter({
                    field: that.assignments.dataTaskIdField,
                    operator: 'eq',
                    value: id
                }).toArray();
                var valuePerResource = function (id) {
                    var resourceValue = null;
                    new Query(taskAssignments).filter({
                        field: that.assignments.dataResourceIdField,
                        operator: 'eq',
                        value: id
                    }).select(function (assignment) {
                        resourceValue += assignment.get(that.assignments.dataValueField);
                    });
                    return resourceValue;
                };
                for (var i = 0, length = resources.length; i < length; i++) {
                    resource = resources[i];
                    result.push({
                        id: resource.get('id'),
                        name: resource.get(that.resources.dataTextField),
                        format: resource.get(that.resources.dataFormatField) || PERCENTAGE_FORMAT,
                        value: valuePerResource(resource.id)
                    });
                }
                return result;
            },
            _syncDataSource: function () {
                this._preventRefresh = false;
                this._requestStart();
                this.dataSource.sync();
            },
            _requestStart: function () {
                this._progress(true);
            },
            _error: function () {
                this._progress(false);
            },
            _progress: function (toggle) {
                kendo.ui.progress(this.element, toggle);
            },
            _resizable: function () {
                var that = this;
                var wrapper = this.wrapper;
                var ganttStyles = Gantt.styles;
                var contentSelector = DOT + ganttStyles.gridContent;
                var treeListWrapper = wrapper.find(DOT + ganttStyles.list);
                var timelineWrapper = wrapper.find(DOT + ganttStyles.timeline);
                var treeListWidth;
                var timelineWidth;
                var timelineScroll;
                this._resizeDraggable = wrapper.find(DOT + ganttStyles.splitBar).height(treeListWrapper.height()).hover(function () {
                    $(this).addClass(ganttStyles.splitBarHover);
                }, function () {
                    $(this).removeClass(ganttStyles.splitBarHover);
                }).end().kendoResizable({
                    orientation: 'horizontal',
                    handle: DOT + ganttStyles.splitBar,
                    'start': function () {
                        treeListWidth = treeListWrapper.width();
                        timelineWidth = timelineWrapper.width();
                        timelineScroll = timelineWrapper.find(contentSelector).scrollLeft();
                    },
                    'resize': function (e) {
                        var delta = e.x.initialDelta;
                        if (kendo.support.isRtl(wrapper)) {
                            delta *= -1;
                        }
                        if (treeListWidth + delta < 0 || timelineWidth - delta < 0) {
                            return;
                        }
                        treeListWrapper.width(treeListWidth + delta);
                        timelineWrapper.width(timelineWidth - delta);
                        timelineWrapper.find(contentSelector).scrollLeft(timelineScroll + delta);
                        that.timeline.view()._renderCurrentTime();
                    }
                }).data('kendoResizable');
            },
            _scrollable: function () {
                var that = this;
                var ganttStyles = Gantt.styles;
                var contentSelector = DOT + ganttStyles.gridContent;
                var headerSelector = DOT + ganttStyles.gridHeaderWrap;
                var timelineHeader = this.timeline.element.find(headerSelector);
                var timelineContent = this.timeline.element.find(contentSelector);
                var treeListHeader = this.list.element.find(headerSelector);
                var treeListContent = this.list.element.find(contentSelector);
                if (mobileOS) {
                    treeListContent.css('overflow-y', 'auto');
                }
                timelineContent.on('scroll', function () {
                    that.scrollTop = this.scrollTop;
                    timelineHeader.scrollLeft(this.scrollLeft);
                    treeListContent.scrollTop(this.scrollTop);
                });
                treeListContent.on('scroll', function () {
                    treeListHeader.scrollLeft(this.scrollLeft);
                }).on('DOMMouseScroll' + NS + ' mousewheel' + NS, function (e) {
                    var scrollTop = timelineContent.scrollTop();
                    var delta = kendo.wheelDeltaY(e);
                    if (delta) {
                        e.preventDefault();
                        $(e.currentTarget).one('wheel' + NS, false);
                        timelineContent.scrollTop(scrollTop + -delta);
                    }
                });
            },
            _navigatable: function () {
                var that = this;
                var navigatable = this.options.navigatable;
                var editable = this.options.editable;
                var headerTable = this.list.header.find('table');
                var contentTable = this.list.content.find('table');
                var ganttStyles = Gantt.styles;
                var isRtl = kendo.support.isRtl(this.wrapper);
                var timelineContent = this.timeline.element.find(DOT + ganttStyles.gridContent);
                var tables = headerTable.add(contentTable);
                var attr = selector();
                var cellIndex;
                var expandState = {
                    collapse: false,
                    expand: true
                };
                var scroll = function (reverse) {
                    var width = that.timeline.view()._timeSlots()[0].offsetWidth;
                    timelineContent.scrollLeft(timelineContent.scrollLeft() + (reverse ? -width : width));
                };
                var moveVertical = function (method) {
                    var parent = that.current.parent('tr' + selector());
                    var index = that.current.index();
                    var subling = parent[method]();
                    if (that.select().length !== 0) {
                        that.clearSelection();
                    }
                    if (subling.length !== 0) {
                        that._current(subling.children('td:eq(' + index + ')'));
                        that._scrollTo(that.current);
                    } else {
                        if (that.current.is('td') && method == 'prev') {
                            focusTable(headerTable);
                        } else if (that.current.is('th') && method == 'next') {
                            focusTable(contentTable);
                        }
                    }
                };
                var moveHorizontal = function (method) {
                    var subling = that.current[method]();
                    if (subling.length !== 0) {
                        that._current(subling);
                        cellIndex = that.current.index();
                    }
                };
                var toggleExpandedState = function (value) {
                    var model = that.dataItem(that.current);
                    if (model.summary && model.expanded !== value) {
                        model.set('expanded', value);
                    }
                };
                var deleteAction = function () {
                    var editable = that.options.editable;
                    if (!editable || editable.destroy === false || that.list.editable) {
                        return;
                    }
                    var selectedTask = that.select();
                    var uid = kendo.attr('uid');
                    if (selectedTask.length) {
                        that.removeTask(selectedTask.attr(uid));
                    }
                };
                $(this.wrapper).on('mousedown' + NS, 'tr' + attr + ', div' + attr + ':not(' + DOT + ganttStyles.line + ')', function (e) {
                    var currentTarget = $(e.currentTarget);
                    var isInput = $(e.target).is(':button,a,:input,a>.k-icon,textarea,span.k-icon,span.k-link,.k-input,.k-multiselect-wrap');
                    var current;
                    if (e.ctrlKey) {
                        return;
                    }
                    if (navigatable) {
                        if (currentTarget.is('tr')) {
                            current = $(e.target).closest('td');
                        } else {
                            current = that.list.content.find('tr' + selector(currentTarget.attr(kendo.attr('uid'))) + ' > td:first');
                        }
                        that._current(current);
                    }
                    if ((navigatable || editable) && !isInput) {
                        that._focusTimeout = setTimeout(function () {
                            focusTable(that.list.content.find('table'), true);
                        }, 2);
                    }
                });
                if (navigatable !== true) {
                    contentTable.on('keydown' + NS, function (e) {
                        if (e.keyCode == keys.DELETE) {
                            deleteAction();
                        }
                    });
                    return;
                }
                tables.on('focus' + NS, function () {
                    var selector = this === contentTable.get(0) ? 'td' : 'th';
                    var selection = that.select();
                    var current = that.current || $(selection.length ? selection : this).find(selector + ':eq(' + (cellIndex || 0) + ')');
                    that._current(current);
                }).on('blur' + NS, function () {
                    that._current();
                    if (this == headerTable) {
                        $(this).attr(TABINDEX, -1);
                    }
                }).on('keydown' + NS, function (e) {
                    var key = e.keyCode;
                    var isCell;
                    if (!that.current) {
                        return;
                    }
                    isCell = that.current.is('td');
                    switch (key) {
                    case keys.RIGHT:
                        e.preventDefault();
                        if (e.altKey) {
                            scroll();
                        } else if (e.ctrlKey) {
                            toggleExpandedState(isRtl ? expandState.collapse : expandState.expand);
                        } else {
                            moveHorizontal(isRtl ? 'prev' : 'next');
                        }
                        break;
                    case keys.LEFT:
                        e.preventDefault();
                        if (e.altKey) {
                            scroll(true);
                        } else if (e.ctrlKey) {
                            toggleExpandedState(isRtl ? expandState.expand : expandState.collapse);
                        } else {
                            moveHorizontal(isRtl ? 'next' : 'prev');
                        }
                        break;
                    case keys.UP:
                        e.preventDefault();
                        moveVertical('prev');
                        break;
                    case keys.DOWN:
                        e.preventDefault();
                        moveVertical('next');
                        break;
                    case keys.SPACEBAR:
                        e.preventDefault();
                        if (isCell) {
                            that.select(that.current.closest('tr'));
                        }
                        break;
                    case keys.ENTER:
                        e.preventDefault();
                        if (isCell) {
                            if (that.options.editable && that.options.editable.update !== false) {
                                that._cachedCurrent = that.current;
                                that.list._startEditHandler(that.current);
                                $(this).one('keyup', function (e) {
                                    e.stopPropagation();
                                });
                            }
                        } else {
                            that.current.children('a.k-link').click();
                        }
                        break;
                    case keys.ESC:
                        e.stopPropagation();
                        break;
                    case keys.DELETE:
                        if (isCell) {
                            deleteAction();
                        }
                        break;
                    default:
                        if (key >= 49 && key <= 57) {
                            that.view(that.timeline._viewByIndex(key - 49));
                        }
                        break;
                    }
                });
            },
            _current: function (element) {
                var ganttStyles = Gantt.styles;
                var activeElement;
                if (this.current && this.current.length) {
                    this.current.removeClass(ganttStyles.focused).removeAttr('id');
                }
                if (element && element.length) {
                    this.current = element.addClass(ganttStyles.focused).attr('id', ACTIVE_CELL);
                    activeElement = $(kendo._activeElement());
                    if (activeElement.is('table') && this.wrapper.find(activeElement).length > 0) {
                        activeElement.removeAttr(ARIA_DESCENDANT).attr(ARIA_DESCENDANT, ACTIVE_CELL);
                    }
                } else {
                    this.current = null;
                }
            },
            _dataBind: function () {
                var that = this;
                if (that.options.autoBind) {
                    this._preventRefresh = true;
                    this._preventDependencyRefresh = true;
                    var promises = $.map([
                        this.dataSource,
                        this.dependencies,
                        this.resources.dataSource,
                        this.assignments.dataSource
                    ], function (dataSource) {
                        return dataSource.fetch();
                    });
                    $.when.apply(null, promises).done(function () {
                        that._preventRefresh = false;
                        that._preventDependencyRefresh = false;
                        that.refresh();
                    });
                }
            },
            _resize: function () {
                this._adjustDimensions();
                this.timeline.view()._adjustHeight();
                this.timeline.view()._renderCurrentTime();
                this.list._adjustHeight();
            }
        });
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Gantt.fn);
            Gantt.fn._drawPDF = function () {
                var ganttStyles = Gantt.styles;
                var listClass = '.' + ganttStyles.list;
                var listWidth = this.wrapper.find(listClass).width();
                var content = this.wrapper.clone();
                content.find(listClass).css('width', listWidth);
                return this._drawPDFShadow({ content: content }, { avoidLinks: this.options.pdf.avoidLinks });
            };
        }
        kendo.ui.plugin(Gantt);
        extend(true, Gantt, { styles: ganttStyles });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.treelist', [
        'kendo.dom',
        'kendo.data',
        'kendo.columnsorter',
        'kendo.editable',
        'kendo.window',
        'kendo.filtermenu',
        'kendo.selectable',
        'kendo.resizable',
        'kendo.treeview.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'treelist',
        name: 'TreeList',
        category: 'web',
        description: 'The TreeList widget displays self-referencing data and offers rich support for interacting with data, sorting, filtering, and selection.',
        depends: [
            'dom',
            'data'
        ],
        features: [
            {
                id: 'treelist-sorting',
                name: 'Sorting',
                description: 'Support for column sorting',
                depends: ['columnsorter']
            },
            {
                id: 'treelist-filtering',
                name: 'Filtering',
                description: 'Support for record filtering',
                depends: ['filtermenu']
            },
            {
                id: 'treelist-editing',
                name: 'Editing',
                description: 'Support for record editing',
                depends: [
                    'editable',
                    'window'
                ]
            },
            {
                id: 'treelist-selection',
                name: 'Selection',
                description: 'Support for row selection',
                depends: ['selectable']
            },
            {
                id: 'treelist-column-resize',
                name: 'Column resizing',
                description: 'Support for column resizing',
                depends: ['resizable']
            },
            {
                id: 'treelist-dragging',
                name: 'Drag & Drop',
                description: 'Support for drag & drop of rows',
                depends: ['treeview.draganddrop']
            },
            {
                id: 'treelist-excel-export',
                name: 'Excel export',
                description: 'Export data as Excel spreadsheet',
                depends: ['excel']
            },
            {
                id: 'treelist-pdf-export',
                name: 'PDF export',
                description: 'Export data as PDF',
                depends: [
                    'pdf',
                    'drawing'
                ]
            }
        ]
    };
    (function ($, undefined) {
        var data = kendo.data;
        var extend = $.extend;
        var kendoDom = kendo.dom;
        var kendoDomElement = kendoDom.element;
        var kendoTextElement = kendoDom.text;
        var kendoHtmlElement = kendoDom.html;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var ui = kendo.ui;
        var DataBoundWidget = ui.DataBoundWidget;
        var DataSource = data.DataSource;
        var ObservableArray = data.ObservableArray;
        var Query = data.Query;
        var Model = data.Model;
        var proxy = $.proxy;
        var map = $.map;
        var grep = $.grep;
        var inArray = $.inArray;
        var isPlainObject = $.isPlainObject;
        var push = Array.prototype.push;
        var STRING = 'string';
        var CHANGE = 'change';
        var ERROR = 'error';
        var PROGRESS = 'progress';
        var DOT = '.';
        var NS = '.kendoTreeList';
        var CLICK = 'click';
        var MOUSEDOWN = 'mousedown';
        var EDIT = 'edit';
        var SAVE = 'save';
        var EXPAND = 'expand';
        var COLLAPSE = 'collapse';
        var REMOVE = 'remove';
        var DATABINDING = 'dataBinding';
        var DATABOUND = 'dataBound';
        var CANCEL = 'cancel';
        var FILTERMENUINIT = 'filterMenuInit';
        var COLUMNHIDE = 'columnHide';
        var COLUMNSHOW = 'columnShow';
        var HEADERCELLS = 'th.k-header';
        var COLUMNREORDER = 'columnReorder';
        var COLUMNRESIZE = 'columnResize';
        var COLUMNMENUINIT = 'columnMenuInit';
        var COLUMNLOCK = 'columnLock';
        var COLUMNUNLOCK = 'columnUnlock';
        var PARENTIDFIELD = 'parentId';
        var DRAGSTART = 'dragstart';
        var DRAG = 'drag';
        var DROP = 'drop';
        var DRAGEND = 'dragend';
        var classNames = {
            wrapper: 'k-treelist k-grid k-widget k-display-block',
            header: 'k-header',
            button: 'k-button',
            alt: 'k-alt',
            editCell: 'k-edit-cell',
            group: 'k-treelist-group',
            gridToolbar: 'k-grid-toolbar',
            gridHeader: 'k-grid-header',
            gridHeaderWrap: 'k-grid-header-wrap',
            gridContent: 'k-grid-content',
            gridContentWrap: 'k-grid-content',
            gridFilter: 'k-grid-filter',
            footerTemplate: 'k-footer-template',
            loading: 'k-i-loading',
            refresh: 'k-i-reload',
            retry: 'k-request-retry',
            selected: 'k-state-selected',
            status: 'k-status',
            link: 'k-link',
            withIcon: 'k-with-icon',
            filterable: 'k-filterable',
            icon: 'k-icon',
            iconFilter: 'k-i-filter',
            iconCollapse: 'k-i-collapse',
            iconExpand: 'k-i-expand',
            iconHidden: 'k-i-none',
            iconPlaceHolder: 'k-icon k-i-none',
            input: 'k-input',
            dropPositions: 'k-i-insert-up k-i-insert-down k-i-plus k-i-insert-middle',
            dropTop: 'k-i-insert-up',
            dropBottom: 'k-i-insert-down',
            dropAdd: 'k-i-plus',
            dropMiddle: 'k-i-insert-middle',
            dropDenied: 'k-i-cancel',
            dragStatus: 'k-drag-status',
            dragClue: 'k-drag-clue',
            dragClueText: 'k-clue-text'
        };
        var defaultCommands = {
            create: {
                imageClass: 'k-i-plus',
                className: 'k-grid-add',
                methodName: 'addRow'
            },
            createchild: {
                imageClass: 'k-i-plus',
                className: 'k-grid-add',
                methodName: 'addRow'
            },
            destroy: {
                imageClass: 'k-i-close',
                className: 'k-grid-delete',
                methodName: 'removeRow'
            },
            edit: {
                imageClass: 'k-i-edit',
                className: 'k-grid-edit',
                methodName: 'editRow'
            },
            update: {
                imageClass: 'k-i-check',
                className: 'k-primary k-grid-update',
                methodName: 'saveRow'
            },
            canceledit: {
                imageClass: 'k-i-cancel',
                className: 'k-grid-cancel',
                methodName: '_cancelEdit'
            },
            excel: {
                imageClass: 'k-i-file-excel',
                className: 'k-grid-excel',
                methodName: 'saveAsExcel'
            },
            pdf: {
                imageClass: 'k-i-file-pdf',
                className: 'k-grid-pdf',
                methodName: 'saveAsPDF'
            }
        };
        var TreeListModel = Model.define({
            id: 'id',
            parentId: PARENTIDFIELD,
            fields: {
                id: { type: 'number' },
                parentId: {
                    type: 'number',
                    nullable: true
                }
            },
            init: function (value) {
                Model.fn.init.call(this, value);
                this._loaded = false;
                if (!this.parentIdField) {
                    this.parentIdField = PARENTIDFIELD;
                }
                this.parentId = this.get(this.parentIdField);
            },
            accept: function (data) {
                Model.fn.accept.call(this, data);
                this.parentId = this.get(this.parentIdField);
            },
            set: function (field, value, initiator) {
                if (field == PARENTIDFIELD && this.parentIdField != PARENTIDFIELD) {
                    this[this.parentIdField] = value;
                }
                Model.fn.set.call(this, field, value, initiator);
                if (field == this.parentIdField) {
                    this.parentId = this.get(this.parentIdField);
                }
            },
            loaded: function (value) {
                if (value !== undefined) {
                    this._loaded = value;
                } else {
                    return this._loaded;
                }
            },
            shouldSerialize: function (field) {
                return Model.fn.shouldSerialize.call(this, field) && field !== '_loaded' && field != '_error' && field != '_edit' && !(this.parentIdField !== 'parentId' && field === 'parentId');
            }
        });
        TreeListModel.parentIdField = PARENTIDFIELD;
        TreeListModel.define = function (base, options) {
            if (options === undefined) {
                options = base;
                base = TreeListModel;
            }
            var parentId = options.parentId || PARENTIDFIELD;
            options.parentIdField = parentId;
            var model = Model.define(base, options);
            if (parentId) {
                model.parentIdField = parentId;
            }
            return model;
        };
        function is(field) {
            return function (object) {
                return object[field];
            };
        }
        function not(func) {
            return function (object) {
                return !func(object);
            };
        }
        var TreeListDataSource = DataSource.extend({
            init: function (options) {
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: TreeListModel,
                        model: TreeListModel
                    }
                }, options));
            },
            _createNewModel: function (data) {
                var model = {};
                var fromModel = data instanceof Model;
                if (fromModel) {
                    model = data;
                }
                model = DataSource.fn._createNewModel.call(this, model);
                if (!fromModel) {
                    if (data.parentId) {
                        data[model.parentIdField] = data.parentId;
                    }
                    model.accept(data);
                }
                return model;
            },
            _shouldWrap: function () {
                return true;
            },
            _push: function (result, operation) {
                var data = DataSource.fn._readData.call(this, result);
                if (!data) {
                    data = result;
                }
                this[operation](data);
            },
            _readData: function (newData) {
                var data = this.data();
                newData = DataSource.fn._readData.call(this, newData);
                this._replaceData(data.toJSON().concat(newData), data);
                if (newData instanceof ObservableArray) {
                    return newData;
                }
                return data;
            },
            _replaceData: function (source, target) {
                var sourceLength = source.length;
                for (var i = 0; i < sourceLength; i++) {
                    target[i] = source[i];
                }
                target.length = sourceLength;
            },
            _readAggregates: function (data) {
                var result = extend(this._aggregateResult, this.reader.aggregates(data));
                if ('' in result) {
                    result[this._defaultParentId()] = result[''];
                    delete result[''];
                }
                return result;
            },
            remove: function (root) {
                var items = this._subtree(this._childrenMap(this.data()), root.id);
                this._removeItems(items);
                DataSource.fn.remove.call(this, root);
            },
            _filterCallback: function (query) {
                var i, item;
                var map = {};
                var result = [];
                var data = query.toArray();
                for (i = 0; i < data.length; i++) {
                    item = data[i];
                    while (item) {
                        if (!map[item.id]) {
                            map[item.id] = true;
                            result.push(item);
                        }
                        if (!map[item.parentId]) {
                            map[item.parentId] = true;
                            item = this.parentNode(item);
                            if (item) {
                                result.push(item);
                            }
                        } else {
                            break;
                        }
                    }
                }
                return new Query(result);
            },
            _subtree: function (map, id) {
                var result = map[id] || [];
                var defaultParentId = this._defaultParentId();
                for (var i = 0, len = result.length; i < len; i++) {
                    if (result[i].id !== defaultParentId) {
                        result = result.concat(this._subtree(map, result[i].id));
                    }
                }
                return result;
            },
            _childrenMap: function (data) {
                var map = {};
                var i, item, id, parentId;
                data = this._observeView(data);
                for (i = 0; i < data.length; i++) {
                    item = data[i];
                    id = item.id;
                    parentId = item.parentId;
                    map[id] = map[id] || [];
                    map[parentId] = map[parentId] || [];
                    map[parentId].push(item);
                }
                return map;
            },
            _calculateAggregates: function (data, options) {
                options = options || {};
                var result = {};
                var item, subtree, i;
                var filter = options.filter;
                if (filter) {
                    data = Query.process(data, {
                        filter: filter,
                        filterCallback: proxy(this._filterCallback, this)
                    }).data;
                }
                var map = this._childrenMap(data);
                result[this._defaultParentId()] = new Query(this._subtree(map, this._defaultParentId())).aggregate(options.aggregate);
                for (i = 0; i < data.length; i++) {
                    item = data[i];
                    subtree = this._subtree(map, item.id);
                    result[item.id] = new Query(subtree).aggregate(options.aggregate);
                }
                return result;
            },
            _queryProcess: function (data, options) {
                options = options || {};
                options.filterCallback = proxy(this._filterCallback, this);
                var defaultParentId = this._defaultParentId();
                var result = Query.process(data, options);
                var map = this._childrenMap(result.data);
                var hasLoadedChildren, i, item, children;
                data = map[defaultParentId] || [];
                for (i = 0; i < data.length; i++) {
                    item = data[i];
                    if (item.id === defaultParentId) {
                        continue;
                    }
                    children = map[item.id];
                    hasLoadedChildren = !!(children && children.length);
                    if (!item.loaded()) {
                        item.loaded(hasLoadedChildren || !item.hasChildren);
                    }
                    if (item.loaded() || item.hasChildren !== true) {
                        item.hasChildren = hasLoadedChildren;
                    }
                    if (hasLoadedChildren) {
                        data = data.slice(0, i + 1).concat(children, data.slice(i + 1));
                    }
                }
                result.data = data;
                return result;
            },
            _queueRequest: function (options, callback) {
                callback.call(this);
            },
            _modelLoaded: function (id) {
                var model = this.get(id);
                model.loaded(true);
                model.hasChildren = this.childNodes(model).length > 0;
            },
            _modelError: function (id, e) {
                this.get(id)._error = e;
            },
            success: function (data, requestParams) {
                if (!requestParams || typeof requestParams.id == 'undefined') {
                    this._data = this._observe([]);
                }
                return DataSource.fn.success.call(this, data, requestParams);
            },
            load: function (model) {
                var method = '_query';
                var remote = this.options.serverSorting || this.options.serverPaging || this.options.serverFiltering || this.options.serverGrouping || this.options.serverAggregates;
                var defaultPromise = $.Deferred().resolve().promise();
                if (model.loaded()) {
                    if (remote) {
                        return defaultPromise;
                    }
                } else if (model.hasChildren) {
                    method = 'read';
                }
                return this[method]({ id: model.id }).done(proxy(this._modelLoaded, this, model.id)).fail(proxy(this._modelError, this, model.id));
            },
            contains: function (root, child) {
                var rootId = root.id;
                while (child) {
                    if (child.parentId === rootId) {
                        return true;
                    }
                    child = this.parentNode(child);
                }
                return false;
            },
            _byParentId: function (id, defaultId) {
                var result = [];
                var view = this.view();
                var current;
                if (id === defaultId) {
                    return [];
                }
                for (var i = 0; i < view.length; i++) {
                    current = view.at(i);
                    if (current.parentId == id) {
                        result.push(current);
                    }
                }
                return result;
            },
            _defaultParentId: function () {
                return this.reader.model.fn.defaults[this.reader.model.parentIdField];
            },
            childNodes: function (model) {
                return this._byParentId(model.id, this._defaultParentId());
            },
            rootNodes: function () {
                return this._byParentId(this._defaultParentId());
            },
            parentNode: function (model) {
                return this.get(model.parentId);
            },
            level: function (model) {
                var result = -1;
                if (!(model instanceof TreeListModel)) {
                    model = this.get(model);
                }
                do {
                    model = this.parentNode(model);
                    result++;
                } while (model);
                return result;
            },
            filter: function (value) {
                var baseFilter = DataSource.fn.filter;
                if (value === undefined) {
                    return baseFilter.call(this, value);
                }
                baseFilter.call(this, value);
            }
        });
        TreeListDataSource.create = function (options) {
            if ($.isArray(options)) {
                options = { data: options };
            } else if (options instanceof ObservableArray) {
                options = { data: options.toJSON() };
            }
            return options instanceof TreeListDataSource ? options : new TreeListDataSource(options);
        };
        function isCellVisible() {
            return this.style.display !== 'none';
        }
        function leafDataCells(container) {
            var rows = container.find('>tr:not(.k-filter-row)');
            var filter = function () {
                var el = $(this);
                return !el.hasClass('k-group-cell') && !el.hasClass('k-hierarchy-cell');
            };
            var cells = $();
            if (rows.length > 1) {
                cells = rows.find('th').filter(filter).filter(function () {
                    return this.rowSpan > 1;
                });
            }
            cells = cells.add(rows.last().find('th').filter(filter));
            var indexAttr = kendo.attr('index');
            cells.sort(function (a, b) {
                a = $(a);
                b = $(b);
                var indexA = a.attr(indexAttr);
                var indexB = b.attr(indexAttr);
                if (indexA === undefined) {
                    indexA = $(a).index();
                }
                if (indexB === undefined) {
                    indexB = $(b).index();
                }
                indexA = parseInt(indexA, 10);
                indexB = parseInt(indexB, 10);
                return indexA > indexB ? 1 : indexA < indexB ? -1 : 0;
            });
            return cells;
        }
        function createPlaceholders(options) {
            var spans = [];
            var className = options.className;
            for (var i = 0, level = options.level; i < level; i++) {
                spans.push(kendoDomElement('span', { className: className }));
            }
            return spans;
        }
        function columnsWidth(cols) {
            var colWidth, width = 0;
            for (var idx = 0, length = cols.length; idx < length; idx++) {
                colWidth = cols[idx].style.width;
                if (colWidth && colWidth.indexOf('%') == -1) {
                    width += parseInt(colWidth, 10);
                }
            }
            return width;
        }
        function syncTableHeight(table1, table2) {
            table1 = table1[0];
            table2 = table2[0];
            if (table1.rows.length !== table2.rows.length) {
                var lockedHeigth = table1.offsetHeight;
                var tableHeigth = table2.offsetHeight;
                var row;
                var diff;
                if (lockedHeigth > tableHeigth) {
                    row = table2.rows[table2.rows.length - 1];
                    diff = lockedHeigth - tableHeigth;
                } else {
                    row = table1.rows[table1.rows.length - 1];
                    diff = tableHeigth - lockedHeigth;
                }
                row.style.height = row.offsetHeight + diff + 'px';
            }
        }
        var Editor = kendo.Observable.extend({
            init: function (element, options) {
                kendo.Observable.fn.init.call(this);
                options = this.options = extend(true, {}, this.options, options);
                this.element = element;
                this.bind(this.events, options);
                this.model = this.options.model;
                this.fields = this._fields(this.options.columns);
                this._initContainer();
                this.createEditable();
            },
            events: [],
            _initContainer: function () {
                this.wrapper = this.element;
            },
            createEditable: function () {
                var options = this.options;
                this.editable = new ui.Editable(this.wrapper, {
                    fields: this.fields,
                    target: options.target,
                    clearContainer: options.clearContainer,
                    model: this.model
                });
            },
            _isEditable: function (column) {
                return column.field && this.model.editable(column.field);
            },
            _fields: function (columns) {
                var fields = [];
                var idx, length, column;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    if (this._isEditable(column)) {
                        fields.push({
                            field: column.field,
                            format: column.format,
                            editor: column.editor
                        });
                    }
                }
                return fields;
            },
            end: function () {
                return this.editable.end();
            },
            close: function () {
                this.destroy();
            },
            destroy: function () {
                this.editable.destroy();
                this.editable.element.find('[' + kendo.attr('container-for') + ']').empty().end().removeAttr(kendo.attr('role'));
                this.model = this.wrapper = this.element = this.columns = this.editable = null;
            }
        });
        var PopupEditor = Editor.extend({
            init: function (element, options) {
                Editor.fn.init.call(this, element, options);
                this._attachHandlers();
                kendo.cycleForm(this.wrapper);
                this.open();
            },
            events: [
                CANCEL,
                SAVE
            ],
            options: {
                window: {
                    modal: true,
                    resizable: false,
                    draggable: true,
                    title: 'Edit',
                    visible: false
                }
            },
            _initContainer: function () {
                var options = this.options;
                var formContent = [];
                this.wrapper = $('<div class="k-popup-edit-form"/>').attr(kendo.attr('uid'), this.model.uid).append('<div class="k-edit-form-container"/>');
                if (options.template) {
                    this._appendTemplate(formContent);
                    this.fields = [];
                } else {
                    this._appendFields(formContent);
                }
                this._appendButtons(formContent);
                new kendoDom.Tree(this.wrapper.children()[0]).render(formContent);
                this.wrapper.appendTo(options.appendTo);
                this.window = new ui.Window(this.wrapper, options.window);
            },
            _appendTemplate: function (form) {
                var template = this.options.template;
                if (typeof template === STRING) {
                    template = window.unescape(template);
                }
                template = kendo.template(template)(this.model);
                form.push(kendoHtmlElement(template));
            },
            _appendFields: function (form) {
                var idx, length, column;
                var columns = this.options.columns;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    if (column.command) {
                        continue;
                    }
                    form.push(kendoHtmlElement('<div class="k-edit-label"><label for="' + column.field + '">' + (column.title || column.field || '') + '</label></div>'));
                    if (this._isEditable(column)) {
                        form.push(kendoHtmlElement('<div ' + kendo.attr('container-for') + '="' + column.field + '" class="k-edit-field"></div>'));
                    } else {
                        form.push(kendoDomElement('div', { 'class': 'k-edit-field' }, [this.options.fieldRenderer(column, this.model)]));
                    }
                }
            },
            _appendButtons: function (form) {
                form.push(kendoDomElement('div', { 'class': 'k-edit-buttons k-state-default' }, this.options.commandRenderer()));
            },
            _attachHandlers: function () {
                var closeHandler = this._cancelProxy = proxy(this._cancel, this);
                this.wrapper.on(CLICK + NS, '.k-grid-cancel', this._cancelProxy);
                this._saveProxy = proxy(this._save, this);
                this.wrapper.on(CLICK + NS, '.k-grid-update', this._saveProxy);
                this.window.bind('close', function (e) {
                    if (e.userTriggered) {
                        closeHandler(e);
                    }
                });
            },
            _dettachHandlers: function () {
                this._cancelProxy = null;
                this._saveProxy = null;
                this.wrapper.off(NS);
            },
            _cancel: function (e) {
                this.trigger(CANCEL, e);
            },
            _save: function () {
                this.trigger(SAVE);
            },
            open: function () {
                this.window.center().open();
            },
            close: function () {
                this.window.bind('deactivate', proxy(this.destroy, this)).close();
            },
            destroy: function () {
                this.window.destroy();
                this.window = null;
                this._dettachHandlers();
                Editor.fn.destroy.call(this);
            }
        });
        var TreeList = DataBoundWidget.extend({
            init: function (element, options) {
                DataBoundWidget.fn.init.call(this, element, options);
                this._dataSource(this.options.dataSource);
                this._columns();
                this._layout();
                this._selectable();
                this._sortable();
                this._resizable();
                this._filterable();
                this._attachEvents();
                this._toolbar();
                this._scrollable();
                this._reorderable();
                this._columnMenu();
                this._minScreenSupport();
                this._draggable();
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
                if (this._hasLockedColumns) {
                    var widget = this;
                    this.wrapper.addClass('k-grid-lockedcolumns');
                    this._resizeHandler = function () {
                        widget.resize();
                    };
                    $(window).on('resize' + NS, this._resizeHandler);
                }
                kendo.notify(this);
            },
            _draggable: function () {
                var editable = this.options.editable;
                if (!editable || !editable.move) {
                    return;
                }
                this._dragging = new kendo.ui.HierarchicalDragAndDrop(this.wrapper, {
                    $angular: this.$angular,
                    autoScroll: true,
                    filter: 'tbody>tr',
                    itemSelector: 'tr',
                    allowedContainers: this.wrapper,
                    hintText: function (row) {
                        var text = function () {
                            return $(this).text();
                        };
                        var separator = '<span class=\'k-header k-drag-separator\' />';
                        return row.children('td').map(text).toArray().join(separator);
                    },
                    contains: proxy(function (source, destination) {
                        var dest = this.dataItem(destination);
                        var src = this.dataItem(source);
                        return src == dest || this.dataSource.contains(src, dest);
                    }, this),
                    itemFromTarget: function (target) {
                        var tr = target.closest('tr');
                        return {
                            item: tr,
                            content: tr
                        };
                    },
                    dragstart: proxy(function (source) {
                        this.wrapper.addClass('k-treelist-dragging');
                        var model = this.dataItem(source);
                        return this.trigger(DRAGSTART, { source: model });
                    }, this),
                    drag: proxy(function (e) {
                        e.source = this.dataItem(e.source);
                        this.trigger(DRAG, e);
                    }, this),
                    drop: proxy(function (e) {
                        e.source = this.dataItem(e.source);
                        e.destination = this.dataItem(e.destination);
                        this.wrapper.removeClass('k-treelist-dragging');
                        return this.trigger(DROP, e);
                    }, this),
                    dragend: proxy(function (e) {
                        var dest = this.dataItem(e.destination);
                        var src = this.dataItem(e.source);
                        src.set('parentId', dest ? dest.id : null);
                        e.source = src;
                        e.destination = dest;
                        this.trigger(DRAGEND, e);
                    }, this),
                    reorderable: false,
                    dropHintContainer: function (item) {
                        return item.children('td:eq(1)');
                    },
                    dropPositionFrom: function (dropHint) {
                        return dropHint.prevAll('.k-i-none').length > 0 ? 'after' : 'before';
                    }
                });
            },
            itemFor: function (model) {
                if (typeof model == 'number') {
                    model = this.dataSource.get(model);
                }
                return this.tbody.find('[' + kendo.attr('uid') + '=' + model.uid + ']');
            },
            _scrollable: function () {
                if (this.options.scrollable) {
                    var scrollables = this.thead.closest('.k-grid-header-wrap');
                    var lockedContent = $(this.lockedContent).bind('DOMMouseScroll' + NS + ' mousewheel' + NS, proxy(this._wheelScroll, this));
                    this.content.bind('scroll' + NS, function () {
                        scrollables.scrollLeft(this.scrollLeft);
                        lockedContent.scrollTop(this.scrollTop);
                    });
                    var touchScroller = kendo.touchScroller(this.content);
                    if (touchScroller && touchScroller.movable) {
                        this._touchScroller = touchScroller;
                        touchScroller.movable.bind('change', function (e) {
                            scrollables.scrollLeft(-e.sender.x);
                            if (lockedContent) {
                                lockedContent.scrollTop(-e.sender.y);
                            }
                        });
                    }
                }
            },
            _wheelScroll: function (e) {
                if (e.ctrlKey) {
                    return;
                }
                var delta = kendo.wheelDeltaY(e);
                var lockedDiv = $(e.currentTarget);
                if (delta) {
                    if (lockedDiv[0].scrollHeight > lockedDiv[0].clientHeight && (lockedDiv[0].scrollTop < lockedDiv[0].scrollHeight - lockedDiv[0].clientHeight && delta < 0 || lockedDiv[0].scrollTop > 0 && delta > 0)) {
                        e.preventDefault();
                    }
                    lockedDiv.one('wheel' + NS, false);
                    this.content.scrollTop(this.content.scrollTop() + -delta);
                }
            },
            _progress: function () {
                var messages = this.options.messages;
                if (!this.tbody.find('tr').length) {
                    this._showStatus(kendo.template('<span class=\'#= className #\' /> #: messages.loading #')({
                        className: classNames.icon + ' ' + classNames.loading,
                        messages: messages
                    }));
                }
            },
            _error: function (e) {
                if (!this.dataSource.rootNodes().length) {
                    this._render({ error: e });
                }
            },
            refresh: function (e) {
                e = e || {};
                if (e.action == 'itemchange' && this.editor) {
                    return;
                }
                if (this.trigger(DATABINDING)) {
                    return;
                }
                this._cancelEditor();
                this._render();
                this._adjustHeight();
                this.trigger(DATABOUND);
            },
            _angularFooters: function (command) {
                var i, footer, aggregates;
                var allAggregates = this.dataSource.aggregates();
                var footerRows = this._footerItems();
                for (i = 0; i < footerRows.length; i++) {
                    footer = footerRows.eq(i);
                    aggregates = allAggregates[footer.attr('data-parentId')];
                    this._angularFooter(command, footer.find('td').get(), aggregates);
                }
            },
            _angularFooter: function (command, cells, aggregates) {
                var columns = this.columns;
                this.angular(command, function () {
                    return {
                        elements: cells,
                        data: map(columns, function (col) {
                            return {
                                column: col,
                                aggregate: aggregates && aggregates[col.field]
                            };
                        })
                    };
                });
            },
            items: function () {
                if (this._hasLockedColumns) {
                    return this._items(this.tbody).add(this._items(this.lockedTable));
                } else {
                    return this._items(this.tbody);
                }
            },
            _items: function (container) {
                return container.find('tr').filter(function () {
                    return !$(this).hasClass(classNames.footerTemplate);
                });
            },
            _footerItems: function () {
                var container = this.tbody;
                if (this._hasLockedColumns) {
                    container = container.add(this.lockedTable);
                }
                return container.find('tr').filter(function () {
                    return $(this).hasClass(classNames.footerTemplate);
                });
            },
            dataItems: function () {
                var dataItems = kendo.ui.DataBoundWidget.fn.dataItems.call(this);
                if (this._hasLockedColumns) {
                    var n = dataItems.length, tmp = new Array(2 * n);
                    for (var i = n; --i >= 0;) {
                        tmp[i] = tmp[i + n] = dataItems[i];
                    }
                    dataItems = tmp;
                }
                return dataItems;
            },
            _showStatus: function (message) {
                var status = this.element.find('.k-status');
                var content = $(this.content).add(this.lockedContent);
                if (!status.length) {
                    status = $('<div class=\'k-status\' />').appendTo(this.element);
                }
                this._contentTree.render([]);
                if (this._hasLockedColumns) {
                    this._lockedContentTree.render([]);
                }
                content.hide();
                status.html(message);
            },
            _hideStatus: function () {
                this.element.find('.k-status').remove();
                $(this.content).add(this.lockedContent).show();
            },
            _adjustHeight: function () {
                var element = this.element;
                var contentWrap = element.find(DOT + classNames.gridContentWrap);
                var header = element.find(DOT + classNames.gridHeader);
                var toolbar = element.find(DOT + classNames.gridToolbar);
                var height;
                var scrollbar = kendo.support.scrollbar();
                element.height(this.options.height);
                var isHeightSet = function (el) {
                    var initialHeight, newHeight;
                    if (el[0].style.height) {
                        return true;
                    } else {
                        initialHeight = el.height();
                    }
                    el.height('auto');
                    newHeight = el.height();
                    el.height('');
                    return initialHeight != newHeight;
                };
                if (isHeightSet(element)) {
                    height = element.height() - outerHeight(header) - outerHeight(toolbar);
                    contentWrap.height(height);
                    if (this._hasLockedColumns) {
                        scrollbar = this.table[0].offsetWidth > this.table.parent()[0].clientWidth ? scrollbar : 0;
                        this.lockedContent.height(height - scrollbar);
                    }
                }
            },
            _resize: function () {
                this._applyLockedContainersWidth();
                this._adjustHeight();
            },
            _minScreenSupport: function () {
                var any = this.hideMinScreenCols();
                if (any) {
                    this.minScreenResizeHandler = proxy(this.hideMinScreenCols, this);
                    $(window).on('resize', this.minScreenResizeHandler);
                }
            },
            hideMinScreenCols: function () {
                var cols = this.columns, any = false, screenWidth = window.innerWidth > 0 ? window.innerWidth : screen.width;
                for (var i = 0; i < cols.length; i++) {
                    var col = cols[i];
                    var minWidth = col.minScreenWidth;
                    if (minWidth !== undefined && minWidth !== null) {
                        any = true;
                        if (minWidth > screenWidth) {
                            this.hideColumn(col);
                        } else {
                            this.showColumn(col);
                        }
                    }
                }
                return any;
            },
            destroy: function () {
                DataBoundWidget.fn.destroy.call(this);
                var dataSource = this.dataSource;
                dataSource.unbind(CHANGE, this._refreshHandler);
                dataSource.unbind(ERROR, this._errorHandler);
                dataSource.unbind(PROGRESS, this._progressHandler);
                if (this._resizeHandler) {
                    $(window).off('resize' + NS, this._resizeHandler);
                }
                if (this._dragging) {
                    this._dragging.destroy();
                    this._dragging = null;
                }
                if (this.resizable) {
                    this.resizable.destroy();
                    this.resizable = null;
                }
                if (this.reorderable) {
                    this.reorderable.destroy();
                    this.reorderable = null;
                }
                if (this._draggableInstance && this._draggableInstance.element) {
                    this._draggableInstance.destroy();
                    this._draggableInstance = null;
                }
                if (this.minScreenResizeHandler) {
                    $(window).off('resize', this.minScreenResizeHandler);
                }
                this._destroyEditor();
                this.element.off(NS);
                if (this._touchScroller) {
                    this._touchScroller.destroy();
                }
                this._autoExpandable = null;
                this._refreshHandler = this._errorHandler = this._progressHandler = this._dataSourceFetchProxy = null;
                this.thead = this.content = this.tbody = this.table = this.element = this.lockedHeader = this.lockedContent = null;
                this._statusTree = this._headerTree = this._contentTree = this._lockedHeaderColsTree = this._lockedContentColsTree = this._lockedHeaderTree = this._lockedContentTree = null;
            },
            options: {
                name: 'TreeList',
                columns: [],
                autoBind: true,
                scrollable: true,
                selectable: false,
                sortable: false,
                toolbar: null,
                height: null,
                columnMenu: false,
                messages: {
                    noRows: 'No records to display',
                    loading: 'Loading...',
                    requestFailed: 'Request failed.',
                    retry: 'Retry',
                    commands: {
                        edit: 'Edit',
                        update: 'Update',
                        canceledit: 'Cancel',
                        create: 'Add new record',
                        createchild: 'Add child record',
                        destroy: 'Delete',
                        excel: 'Export to Excel',
                        pdf: 'Export to PDF'
                    }
                },
                excel: { hierarchy: true },
                resizable: false,
                filterable: false,
                editable: false,
                reorderable: false
            },
            events: [
                CHANGE,
                EDIT,
                SAVE,
                REMOVE,
                EXPAND,
                COLLAPSE,
                DATABINDING,
                DATABOUND,
                CANCEL,
                DRAGSTART,
                DRAG,
                DROP,
                DRAGEND,
                FILTERMENUINIT,
                COLUMNHIDE,
                COLUMNSHOW,
                COLUMNREORDER,
                COLUMNRESIZE,
                COLUMNMENUINIT,
                COLUMNLOCK,
                COLUMNUNLOCK
            ],
            _toggle: function (model, expand) {
                var defaultPromise = $.Deferred().resolve().promise();
                var loaded = model.loaded();
                if (model._error) {
                    model.expanded = false;
                    model._error = undefined;
                }
                if (!loaded && model.expanded) {
                    return defaultPromise;
                }
                if (typeof expand == 'undefined') {
                    expand = !model.expanded;
                }
                model.expanded = expand;
                if (!loaded) {
                    defaultPromise = this.dataSource.load(model).always(proxy(function () {
                        this._render();
                        this._syncLockedContentHeight();
                    }, this));
                }
                this._render();
                this._syncLockedContentHeight();
                return defaultPromise;
            },
            expand: function (row) {
                return this._toggle(this.dataItem(row), true);
            },
            collapse: function (row) {
                return this._toggle(this.dataItem(row), false);
            },
            _toggleChildren: function (e) {
                var icon = $(e.currentTarget);
                var model = this.dataItem(icon);
                var event = !model.expanded ? EXPAND : COLLAPSE;
                if (!this.trigger(event, { model: model })) {
                    this._toggle(model);
                }
                e.preventDefault();
            },
            _attachEvents: function () {
                var icons = DOT + classNames.iconCollapse + ', .' + classNames.iconExpand + ', .' + classNames.refresh;
                var retryButton = DOT + classNames.retry;
                this.element.on(MOUSEDOWN + NS, icons, proxy(this._toggleChildren, this)).on(CLICK + NS, retryButton, this._dataSourceFetchProxy).on(CLICK + NS, '.k-button[data-command]', proxy(this._commandClick, this));
            },
            _commandByName: function (name) {
                var columns = this.columns;
                var toolbar = $.isArray(this.options.toolbar) ? this.options.toolbar : [];
                var i, j, commands, currentName;
                name = name.toLowerCase();
                if (defaultCommands[name]) {
                    return defaultCommands[name];
                }
                for (i = 0; i < columns.length; i++) {
                    commands = columns[i].command;
                    if (commands) {
                        for (j = 0; j < commands.length; j++) {
                            currentName = commands[j].name;
                            if (!currentName) {
                                continue;
                            }
                            if (currentName.toLowerCase() == name) {
                                return commands[j];
                            }
                        }
                    }
                }
                for (i = 0; i < toolbar.length; i++) {
                    currentName = toolbar[i].name;
                    if (!currentName) {
                        continue;
                    }
                    if (currentName.toLowerCase() == name) {
                        return toolbar[i];
                    }
                }
            },
            _commandClick: function (e) {
                var button = $(e.currentTarget);
                var commandName = button.attr('data-command');
                var command = this._commandByName(commandName);
                var row = button.parentsUntil(this.wrapper, 'tr');
                row = row.length ? row : undefined;
                if (command) {
                    if (command.methodName) {
                        this[command.methodName](row);
                    } else if (command.click) {
                        command.click.call(this, e);
                    }
                    e.preventDefault();
                }
            },
            _ensureExpandableColumn: function () {
                if (this._autoExpandable) {
                    delete this._autoExpandable.expandable;
                }
                var visibleColumns = grep(this.columns, not(is('hidden')));
                var expandableColumns = grep(visibleColumns, is('expandable'));
                if (this.columns.length && !expandableColumns.length) {
                    this._autoExpandable = visibleColumns[0];
                    visibleColumns[0].expandable = true;
                }
            },
            _columns: function () {
                var columns = this.options.columns || [];
                this.columns = map(columns, function (column) {
                    column = typeof column === 'string' ? { field: column } : column;
                    return extend({ encoded: true }, column);
                });
                var lockedColumns = this._lockedColumns();
                if (lockedColumns.length > 0) {
                    this._hasLockedColumns = true;
                    this.columns = lockedColumns.concat(this._nonLockedColumns());
                }
                this._ensureExpandableColumn();
                this._columnTemplates();
                this._columnAttributes();
            },
            _columnTemplates: function () {
                var idx, length, column;
                var columns = this.columns;
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    column = columns[idx];
                    if (column.template) {
                        column.template = kendo.template(column.template);
                    }
                    if (column.headerTemplate) {
                        column.headerTemplate = kendo.template(column.headerTemplate);
                    }
                    if (column.footerTemplate) {
                        column.footerTemplate = kendo.template(column.footerTemplate);
                    }
                }
            },
            _columnAttributes: function () {
                var idx, length;
                var columns = this.columns;
                function convertStyle(attr) {
                    var properties, i, declaration;
                    if (attr && attr.style) {
                        properties = attr.style.split(';');
                        attr.style = {};
                        for (i = 0; i < properties.length; i++) {
                            declaration = properties[i].split(':');
                            var name = $.trim(declaration[0]);
                            if (name) {
                                attr.style[$.camelCase(name)] = $.trim(declaration[1]);
                            }
                        }
                    }
                }
                for (idx = 0, length = columns.length; idx < length; idx++) {
                    convertStyle(columns[idx].attributes);
                    convertStyle(columns[idx].headerAttributes);
                }
            },
            _layout: function () {
                var columns = this.columns;
                var element = this.element;
                var layout = '';
                this.wrapper = element.addClass(classNames.wrapper);
                layout = '<div class=\'#= gridHeader #\'>';
                if (this._hasLockedColumns) {
                    layout += '<div class=\'k-grid-header-locked\'>' + '<table role=\'grid\'>' + '<colgroup></colgroup>' + '<thead role=\'rowgroup\' />' + '</table>' + '</div>';
                }
                layout += '<div class=\'#= gridHeaderWrap #\'>' + '<table role=\'grid\'>' + '<colgroup></colgroup>' + '<thead role=\'rowgroup\' />' + '</table>' + '</div>' + '</div>';
                if (this._hasLockedColumns) {
                    layout += '<div class=\'k-grid-content-locked\'>' + '<table role=\'treegrid\' tabindex=\'0\'>' + '<colgroup></colgroup>' + '<tbody />' + '</table>' + '</div>';
                }
                layout += '<div class=\'#= gridContentWrap # k-auto-scrollable\'>' + '<table role=\'treegrid\' tabindex=\'0\'>' + '<colgroup></colgroup>' + '<tbody />' + '</table>' + '</div>';
                if (!this.options.scrollable) {
                    layout = '<table role=\'treegrid\' tabindex=\'0\'>' + '<colgroup></colgroup>' + '<thead class=\'#= gridHeader #\' role=\'rowgroup\' />' + '<tbody />' + '</table>';
                }
                if (this.options.toolbar) {
                    layout = '<div class=\'#= header # #= gridToolbar #\' />' + layout;
                }
                element.append(kendo.template(layout)(classNames) + '<div class=\'k-status\' />');
                this.toolbar = element.find(DOT + classNames.gridToolbar);
                var header = element.find(DOT + classNames.gridHeader).find('thead').addBack().filter('thead');
                this.thead = header.last();
                if (this.options.scrollable) {
                    var rtl = kendo.support.isRtl(element);
                    element.find('div.' + classNames.gridHeader).css(rtl ? 'padding-left' : 'padding-right', kendo.support.scrollbar());
                }
                var content = element.find(DOT + classNames.gridContentWrap);
                if (!content.length) {
                    content = element;
                } else {
                    this.content = content;
                }
                this.table = content.find('>table');
                this.tbody = this.table.find('>tbody');
                if (this._hasLockedColumns) {
                    this.lockedHeader = header.first().closest('.k-grid-header-locked');
                    this.lockedContent = element.find('.k-grid-content-locked');
                    this.lockedTable = this.lockedContent.children();
                }
                this._initVirtualTrees();
                this._renderCols();
                this._renderHeader();
                this.angular('compile', function () {
                    return {
                        elements: header.find('th.k-header').get(),
                        data: map(columns, function (col) {
                            return { column: col };
                        })
                    };
                });
            },
            _initVirtualTrees: function () {
                this._headerColsTree = new kendoDom.Tree(this.thead.prev()[0]);
                this._contentColsTree = new kendoDom.Tree(this.tbody.prev()[0]);
                this._headerTree = new kendoDom.Tree(this.thead[0]);
                this._contentTree = new kendoDom.Tree(this.tbody[0]);
                this._statusTree = new kendoDom.Tree(this.element.children('.k-status')[0]);
                if (this.lockedHeader) {
                    this._lockedHeaderColsTree = new kendoDom.Tree(this.lockedHeader.find('colgroup')[0]);
                    this._lockedContentColsTree = new kendoDom.Tree(this.lockedTable.find('>colgroup')[0]);
                    this._lockedHeaderTree = new kendoDom.Tree(this.lockedHeader.find('thead')[0]);
                    this._lockedContentTree = new kendoDom.Tree(this.lockedTable.find('>tbody')[0]);
                }
            },
            _toolbar: function () {
                var options = this.options.toolbar;
                var toolbar = this.toolbar;
                if (!options) {
                    return;
                }
                if ($.isArray(options)) {
                    var buttons = this._buildCommands(options);
                    new kendoDom.Tree(toolbar[0]).render(buttons);
                } else {
                    toolbar.append(kendo.template(options)({}));
                }
                this.angular('compile', function () {
                    return { elements: toolbar.get() };
                });
            },
            _lockedColumns: function () {
                return grep(this.columns, is('locked'));
            },
            _nonLockedColumns: function () {
                return grep(this.columns, not(is('locked')));
            },
            _templateColumns: function () {
                return grep(this.columns, is('template'));
            },
            _flushCache: function () {
                if (this.options.$angular && this._templateColumns().length) {
                    this._contentTree.render([]);
                    if (this._hasLockedColumns) {
                        this._lockedContentTree.render([]);
                    }
                }
            },
            _render: function (options) {
                options = options || {};
                var messages = this.options.messages;
                var data = this.dataSource.rootNodes();
                var uidAttr = kendo.attr('uid');
                var selected = this.select().removeClass('k-state-selected').map(function (_, row) {
                    return $(row).attr(uidAttr);
                });
                this._absoluteIndex = 0;
                this._angularItems('cleanup');
                this._angularFooters('cleanup');
                this._flushCache();
                if (options.error) {
                    this._showStatus(kendo.template('#: messages.requestFailed # ' + '<button class=\'#= buttonClass #\'>#: messages.retry #</button>')({
                        buttonClass: [
                            classNames.button,
                            classNames.retry
                        ].join(' '),
                        messages: messages
                    }));
                } else if (!data.length) {
                    this._showStatus(kendo.htmlEncode(messages.noRows));
                } else {
                    this._hideStatus();
                    this._contentTree.render(this._trs({
                        columns: this._nonLockedColumns(),
                        aggregates: options.aggregates,
                        selected: selected,
                        data: data,
                        visible: true,
                        level: 0
                    }));
                    if (this._hasLockedColumns) {
                        this._absoluteIndex = 0;
                        this._lockedContentTree.render(this._trs({
                            columns: this._lockedColumns(),
                            aggregates: options.aggregates,
                            selected: selected,
                            data: data,
                            visible: true,
                            level: 0
                        }));
                    }
                }
                if (this._touchScroller) {
                    this._touchScroller.contentResized();
                }
                this._muteAngularRebind(function () {
                    this._angularItems('compile');
                    this._angularFooters('compile');
                });
                this.items().filter(function () {
                    return $.inArray($(this).attr(uidAttr), selected) >= 0;
                }).addClass('k-state-selected');
                this._adjustRowsHeight();
            },
            _adjustRowsHeight: function () {
                if (!this._hasLockedColumns) {
                    return;
                }
                var table = this.table;
                var lockedTable = this.lockedTable;
                var rows = table[0].rows;
                var length = rows.length;
                var idx;
                var lockedRows = lockedTable[0].rows;
                var containers = table.add(lockedTable);
                var containersLength = containers.length;
                var heights = [];
                var lockedHeaderRows = this.lockedHeader.find('tr');
                var headerRows = this.thead.find('tr');
                lockedHeaderRows.add(headerRows).height('auto').height(Math.max(lockedHeaderRows.height(), headerRows.height()));
                for (idx = 0; idx < length; idx++) {
                    if (!lockedRows[idx]) {
                        break;
                    }
                    if (rows[idx].style.height) {
                        rows[idx].style.height = lockedRows[idx].style.height = '';
                    }
                }
                for (idx = 0; idx < length; idx++) {
                    if (!lockedRows[idx]) {
                        break;
                    }
                    var offsetHeight1 = rows[idx].offsetHeight;
                    var offsetHeight2 = lockedRows[idx].offsetHeight;
                    var height = 0;
                    if (offsetHeight1 > offsetHeight2) {
                        height = offsetHeight1;
                    } else if (offsetHeight1 < offsetHeight2) {
                        height = offsetHeight2;
                    }
                    heights.push(height);
                }
                for (idx = 0; idx < containersLength; idx++) {
                    containers[idx].style.display = 'none';
                }
                for (idx = 0; idx < length; idx++) {
                    if (heights[idx]) {
                        rows[idx].style.height = lockedRows[idx].style.height = heights[idx] + 1 + 'px';
                    }
                }
                for (idx = 0; idx < containersLength; idx++) {
                    containers[idx].style.display = '';
                }
            },
            _ths: function (columns) {
                var ths = [];
                var column, title, children, cellClasses, attr, headerContent;
                for (var i = 0, length = columns.length; i < length; i++) {
                    column = columns[i];
                    children = [];
                    cellClasses = [classNames.header];
                    if (column.headerTemplate) {
                        title = column.headerTemplate({});
                    } else {
                        title = column.title || column.field || '';
                    }
                    if (column.headerTemplate) {
                        headerContent = kendoHtmlElement(title);
                    } else {
                        headerContent = kendoTextElement(title);
                    }
                    if (column.sortable) {
                        children.push(kendoDomElement('a', {
                            href: '#',
                            className: classNames.link
                        }, [headerContent]));
                    } else {
                        children.push(headerContent);
                    }
                    attr = {
                        'data-field': column.field,
                        'data-title': column.title,
                        'style': column.hidden === true ? { 'display': 'none' } : {},
                        className: cellClasses.join(' '),
                        'role': 'columnheader'
                    };
                    attr = extend(true, {}, attr, column.headerAttributes);
                    ths.push(kendoDomElement('th', attr, children));
                }
                return ths;
            },
            _cols: function (columns) {
                var cols = [];
                var width, attr;
                for (var i = 0; i < columns.length; i++) {
                    if (columns[i].hidden === true) {
                        continue;
                    }
                    width = columns[i].width;
                    attr = {};
                    if (width && parseInt(width, 10) !== 0) {
                        attr.style = { width: typeof width === 'string' ? width : width + 'px' };
                    }
                    cols.push(kendoDomElement('col', attr));
                }
                return cols;
            },
            _renderCols: function () {
                var columns = this._nonLockedColumns();
                this._headerColsTree.render(this._cols(columns));
                if (this.options.scrollable) {
                    this._contentColsTree.render(this._cols(columns));
                }
                if (this._hasLockedColumns) {
                    columns = this._lockedColumns();
                    this._lockedHeaderColsTree.render(this._cols(columns));
                    this._lockedContentColsTree.render(this._cols(columns));
                }
            },
            _renderHeader: function () {
                var columns = this._nonLockedColumns();
                this._headerTree.render([kendoDomElement('tr', { 'role': 'row' }, this._ths(columns))]);
                if (this._hasLockedColumns) {
                    columns = this._lockedColumns();
                    this._lockedHeaderTree.render([kendoDomElement('tr', { 'role': 'row' }, this._ths(columns))]);
                    this._applyLockedContainersWidth();
                }
            },
            _applyLockedContainersWidth: function () {
                if (!this._hasLockedColumns) {
                    return;
                }
                var lockedWidth = columnsWidth(this.lockedHeader.find('>table>colgroup>col'));
                var headerTable = this.thead.parent();
                var nonLockedWidth = columnsWidth(headerTable.find('>colgroup>col'));
                var wrapperWidth = this.wrapper[0].clientWidth;
                var scrollbar = kendo.support.scrollbar();
                if (lockedWidth >= wrapperWidth) {
                    lockedWidth = wrapperWidth - 3 * scrollbar;
                }
                this.lockedHeader.add(this.lockedContent).width(lockedWidth);
                headerTable.add(this.table).width(nonLockedWidth);
                var width = wrapperWidth - lockedWidth - 2;
                this.content.width(width);
                headerTable.parent().width(width - scrollbar);
            },
            _trs: function (options) {
                var model, attr, className, hasChildren, childNodes, i, length;
                var rows = [];
                var level = options.level;
                var data = options.data;
                var dataSource = this.dataSource;
                var aggregates = dataSource.aggregates() || {};
                var columns = options.columns;
                for (i = 0, length = data.length; i < length; i++) {
                    className = [];
                    model = data[i];
                    childNodes = model.loaded() && dataSource.childNodes(model);
                    hasChildren = childNodes && childNodes.length;
                    attr = { 'role': 'row' };
                    attr[kendo.attr('uid')] = model.uid;
                    if (hasChildren) {
                        attr['aria-expanded'] = !!model.expanded;
                    }
                    if (options.visible) {
                        if (this._absoluteIndex % 2 !== 0) {
                            className.push(classNames.alt);
                        }
                        this._absoluteIndex++;
                    } else {
                        attr.style = { display: 'none' };
                    }
                    if ($.inArray(model.uid, options.selected) >= 0) {
                        className.push(classNames.selected);
                    }
                    if (hasChildren) {
                        className.push(classNames.group);
                    }
                    if (model._edit) {
                        className.push('k-grid-edit-row');
                    }
                    attr.className = className.join(' ');
                    rows.push(this._tds({
                        model: model,
                        attr: attr,
                        level: level
                    }, columns, proxy(this._td, this)));
                    if (hasChildren) {
                        rows = rows.concat(this._trs({
                            columns: columns,
                            aggregates: aggregates,
                            selected: options.selected,
                            visible: options.visible && !!model.expanded,
                            data: childNodes,
                            level: level + 1
                        }));
                    }
                }
                if (this._hasFooterTemplate()) {
                    attr = {
                        className: classNames.footerTemplate,
                        'data-parentId': model.parentId
                    };
                    if (!options.visible) {
                        attr.style = { display: 'none' };
                    }
                    rows.push(this._tds({
                        model: aggregates[model.parentId],
                        attr: attr,
                        level: level
                    }, columns, this._footerTd));
                }
                return rows;
            },
            _footerTd: function (options) {
                var content = [];
                var column = options.column;
                var template = options.column.footerTemplate || $.noop;
                var aggregates = options.model[column.field] || {};
                var attr = {
                    'role': 'gridcell',
                    'style': column.hidden === true ? { 'display': 'none' } : {}
                };
                if (column.expandable) {
                    content = content.concat(createPlaceholders({
                        level: options.level + 1,
                        className: classNames.iconPlaceHolder
                    }));
                }
                if (column.attributes) {
                    extend(attr, column.attributes);
                }
                content.push(kendoHtmlElement(template(aggregates) || ''));
                return kendoDomElement('td', attr, content);
            },
            _hasFooterTemplate: function () {
                return !!grep(this.columns, function (c) {
                    return c.footerTemplate;
                }).length;
            },
            _tds: function (options, columns, renderer) {
                var children = [];
                var column;
                for (var i = 0, l = columns.length; i < l; i++) {
                    column = columns[i];
                    children.push(renderer({
                        model: options.model,
                        column: column,
                        level: options.level
                    }));
                }
                return kendoDomElement('tr', options.attr, children);
            },
            _td: function (options) {
                var children = [];
                var model = options.model;
                var column = options.column;
                var iconClass;
                var attr = {
                    'role': 'gridcell',
                    'style': column.hidden === true ? { 'display': 'none' } : {}
                };
                if (model._edit && column.field && model.editable(column.field)) {
                    attr[kendo.attr('container-for')] = column.field;
                } else {
                    if (column.expandable) {
                        children = createPlaceholders({
                            level: options.level,
                            className: classNames.iconPlaceHolder
                        });
                        iconClass = [classNames.icon];
                        if (model.hasChildren) {
                            iconClass.push(model.expanded ? classNames.iconCollapse : classNames.iconExpand);
                        } else {
                            iconClass.push(classNames.iconHidden);
                        }
                        if (model._error) {
                            iconClass.push(classNames.refresh);
                        } else if (!model.loaded() && model.expanded) {
                            iconClass.push(classNames.loading);
                        }
                        children.push(kendoDomElement('span', { className: iconClass.join(' ') }));
                        attr.style['white-space'] = 'nowrap';
                    }
                    if (column.attributes) {
                        extend(true, attr, column.attributes);
                    }
                    if (column.command) {
                        if (model._edit) {
                            children = this._buildCommands([
                                'update',
                                'canceledit'
                            ]);
                        } else {
                            children = this._buildCommands(column.command);
                        }
                    } else {
                        children.push(this._cellContent(column, model));
                    }
                }
                return kendoDomElement('td', attr, children);
            },
            _cellContent: function (column, model) {
                var value;
                if (column.template) {
                    value = column.template(model);
                } else if (column.field) {
                    value = model.get(column.field);
                    if (value !== null && column.format) {
                        value = kendo.format(column.format, value);
                    }
                }
                if (value === null || typeof value == 'undefined') {
                    value = '';
                }
                if (column.template || !column.encoded) {
                    return kendoHtmlElement(value);
                } else {
                    return kendoTextElement(value);
                }
            },
            _buildCommands: function (commands) {
                var i, result = [];
                for (i = 0; i < commands.length; i++) {
                    result.push(this._button(commands[i]));
                }
                return result;
            },
            _button: function (command) {
                var name = (command.name || command).toLowerCase();
                var text = this.options.messages.commands[name];
                var icon = [];
                command = extend({}, defaultCommands[name], { text: text }, command);
                if (command.imageClass) {
                    icon.push(kendoDomElement('span', {
                        className: [
                            'k-icon',
                            command.imageClass
                        ].join(' ')
                    }));
                }
                return kendoDomElement('button', {
                    'type': 'button',
                    'data-command': name,
                    className: [
                        'k-button',
                        'k-button-icontext',
                        command.className
                    ].join(' ')
                }, icon.concat([kendoTextElement(command.text || command.name)]));
            },
            _positionResizeHandle: function (e) {
                var th = $(e.currentTarget);
                var resizeHandle = this.resizeHandle;
                var position = th.position();
                var left = position.left;
                var cellWidth = outerWidth(th);
                var container = th.closest('div');
                var clientX = e.clientX + $(window).scrollLeft();
                var indicatorWidth = this.options.columnResizeHandleWidth || 3;
                left += container.scrollLeft();
                if (!resizeHandle) {
                    resizeHandle = this.resizeHandle = $('<div class="k-resize-handle"><div class="k-resize-handle-inner" /></div>');
                }
                var cellOffset = th.offset().left + cellWidth;
                var show = clientX > cellOffset - indicatorWidth && clientX < cellOffset + indicatorWidth;
                if (!show) {
                    resizeHandle.hide();
                    return;
                }
                container.append(resizeHandle);
                resizeHandle.show().css({
                    top: position.top,
                    left: left + cellWidth - indicatorWidth - 1,
                    height: outerHeight(th),
                    width: indicatorWidth * 3
                }).data('th', th);
                var that = this;
                resizeHandle.off('dblclick' + NS).on('dblclick' + NS, function () {
                    var index = th.index();
                    if ($.contains(that.thead[0], th[0])) {
                        index += grep(that.columns, function (val) {
                            return val.locked && !val.hidden;
                        }).length;
                    }
                    that.autoFitColumn(index);
                });
            },
            autoFitColumn: function (column) {
                var that = this, options = that.options, columns = that.columns, index, browser = kendo.support.browser, th, headerTable, isLocked, visibleLocked = that.lockedHeader ? leafDataCells(that.lockedHeader.find('>table>thead')).filter(isCellVisible).length : 0, col;
                if (typeof column == 'number') {
                    column = columns[column];
                } else if (isPlainObject(column)) {
                    column = grep(columns, function (item) {
                        return item === column;
                    })[0];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || column.hidden) {
                    return;
                }
                index = inArray(column, columns);
                isLocked = column.locked;
                if (isLocked) {
                    headerTable = that.lockedHeader.children('table');
                } else {
                    headerTable = that.thead.parent();
                }
                th = headerTable.find('[data-index=\'' + index + '\']');
                var contentTable = isLocked ? that.lockedTable : that.table, footer = that.footer || $();
                if (that.footer && that.lockedContent) {
                    footer = isLocked ? that.footer.children('.k-grid-footer-locked') : that.footer.children('.k-grid-footer-wrap');
                }
                var footerTable = footer.find('table').first();
                if (that.lockedHeader && visibleLocked >= index && !isLocked) {
                    index -= visibleLocked;
                }
                for (var j = 0; j < columns.length; j++) {
                    if (columns[j] === column) {
                        break;
                    } else {
                        if (columns[j].hidden) {
                            index--;
                        }
                    }
                }
                if (options.scrollable) {
                    col = headerTable.find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')').add(contentTable.children('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')')).add(footerTable.find('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')'));
                } else {
                    col = contentTable.children('colgroup').find('col:not(.k-group-col):not(.k-hierarchy-col):eq(' + index + ')');
                }
                var tables = headerTable.add(contentTable).add(footerTable);
                var oldColumnWidth = outerWidth(th);
                col.width('');
                tables.css('table-layout', 'fixed');
                col.width('auto');
                tables.addClass('k-autofitting');
                tables.css('table-layout', '');
                var newColumnWidth = Math.ceil(Math.max(outerWidth(th), outerWidth(contentTable.find('tr').eq(0).children('td:visible').eq(index)), outerWidth(footerTable.find('tr').eq(0).children('td:visible').eq(index))));
                col.width(newColumnWidth);
                column.width = newColumnWidth;
                if (options.scrollable) {
                    var cols = headerTable.find('col'), colWidth, totalWidth = 0;
                    for (var idx = 0, length = cols.length; idx < length; idx += 1) {
                        colWidth = cols[idx].style.width;
                        if (colWidth && colWidth.indexOf('%') == -1) {
                            totalWidth += parseInt(colWidth, 10);
                        } else {
                            totalWidth = 0;
                            break;
                        }
                    }
                    if (totalWidth) {
                        tables.each(function () {
                            this.style.width = totalWidth + 'px';
                        });
                    }
                }
                if (browser.msie && browser.version == 8) {
                    tables.css('display', 'inline-table');
                    setTimeout(function () {
                        tables.css('display', 'table');
                    }, 1);
                }
                tables.removeClass('k-autofitting');
                that.trigger(COLUMNRESIZE, {
                    column: column,
                    oldWidth: oldColumnWidth,
                    newWidth: newColumnWidth
                });
                that._applyLockedContainersWidth();
                that._syncLockedContentHeight();
                that._syncLockedHeaderHeight();
            },
            _adjustLockedHorizontalScrollBar: function () {
                var table = this.table, content = table.parent();
                var scrollbar = table[0].offsetWidth > content[0].clientWidth ? kendo.support.scrollbar() : 0;
                this.lockedContent.height(content.height() - scrollbar);
            },
            _syncLockedContentHeight: function () {
                if (this.lockedTable) {
                    if (!this._touchScroller) {
                        this._adjustLockedHorizontalScrollBar();
                    }
                    this._adjustRowsHeight(this.table, this.lockedTable);
                }
            },
            _syncLockedHeaderHeight: function () {
                if (this.lockedHeader) {
                    var lockedTable = this.lockedHeader.children('table');
                    var table = this.thead.parent();
                    this._adjustRowsHeight(lockedTable, table);
                    syncTableHeight(lockedTable, table);
                }
            },
            _resizable: function () {
                if (!this.options.resizable) {
                    return;
                }
                if (this.resizable) {
                    this.resizable.destroy();
                }
                var treelist = this;
                $(this.lockedHeader).find('thead').add(this.thead).on('mousemove' + NS, 'th', $.proxy(this._positionResizeHandle, this));
                this.resizable = new kendo.ui.Resizable(this.wrapper, {
                    handle: '.k-resize-handle',
                    start: function (e) {
                        var th = $(e.currentTarget).data('th');
                        var colSelector = 'col:eq(' + $.inArray(th[0], th.parent().children().filter(':visible')) + ')';
                        var header, contentTable;
                        treelist.wrapper.addClass('k-grid-column-resizing');
                        if (treelist.lockedHeader && $.contains(treelist.lockedHeader[0], th[0])) {
                            header = treelist.lockedHeader;
                            contentTable = treelist.lockedTable;
                        } else {
                            header = treelist.thead.parent();
                            contentTable = treelist.table;
                        }
                        this.col = contentTable.children('colgroup').find(colSelector).add(header.find(colSelector));
                        this.th = th;
                        this.startLocation = e.x.location;
                        this.columnWidth = outerWidth(th);
                        this.table = this.col.closest('table');
                        this.totalWidth = this.table.width();
                    },
                    resize: function (e) {
                        var minColumnWidth = 11;
                        var delta = e.x.location - this.startLocation;
                        if (this.columnWidth + delta < minColumnWidth) {
                            delta = minColumnWidth - this.columnWidth;
                        }
                        this.table.width(this.totalWidth + delta);
                        this.col.width(this.columnWidth + delta);
                    },
                    resizeend: function () {
                        treelist.wrapper.removeClass('k-grid-column-resizing');
                        var field = this.th.attr('data-field');
                        var column = grep(treelist.columns, function (c) {
                            return c.field == field;
                        });
                        var newWidth = Math.floor(outerWidth(this.th));
                        column[0].width = newWidth;
                        treelist._resize();
                        treelist._adjustRowsHeight();
                        treelist.trigger(COLUMNRESIZE, {
                            column: column,
                            oldWidth: this.columnWidth,
                            newWidth: newWidth
                        });
                        this.table = this.col = this.th = null;
                    }
                });
            },
            _sortable: function () {
                var columns = this.columns;
                var column;
                var sortableInstance;
                var cells = $(this.lockedHeader).add(this.thead).find('th');
                var cell, idx, length;
                var fieldAttr = kendo.attr('field');
                var sortable = this.options.sortable;
                if (!sortable) {
                    return;
                }
                for (idx = 0, length = cells.length; idx < length; idx++) {
                    column = columns[idx];
                    if (column.sortable !== false && !column.command && column.field) {
                        cell = cells.eq(idx);
                        sortableInstance = cell.data('kendoColumnSorter');
                        if (sortableInstance) {
                            sortableInstance.destroy();
                        }
                        cell.attr(fieldAttr, column.field).kendoColumnSorter(extend({}, sortable, column.sortable, { dataSource: this.dataSource }));
                    }
                }
            },
            _filterable: function () {
                var cells = $(this.lockedHeader).add(this.thead).find('th');
                var filterable = this.options.filterable;
                var idx, length, column, cell, filterMenuInstance;
                if (!filterable || this.options.columnMenu) {
                    return;
                }
                var filterInit = proxy(function (e) {
                    this.trigger(FILTERMENUINIT, {
                        field: e.field,
                        container: e.container
                    });
                }, this);
                for (idx = 0, length = cells.length; idx < length; idx++) {
                    column = this.columns[idx];
                    cell = cells.eq(idx);
                    filterMenuInstance = cell.data('kendoFilterMenu');
                    if (filterMenuInstance) {
                        filterMenuInstance.destroy();
                    }
                    if (column.command || column.filterable === false) {
                        continue;
                    }
                    cell.kendoFilterMenu(extend(true, {}, filterable, column.filterable, {
                        dataSource: this.dataSource,
                        init: filterInit
                    }));
                }
            },
            _change: function () {
                this.trigger(CHANGE);
            },
            _selectable: function () {
                var selectable = this.options.selectable;
                var filter;
                var element = this.table;
                var useAllItems;
                if (selectable) {
                    selectable = kendo.ui.Selectable.parseOptions(selectable);
                    if (this._hasLockedColumns) {
                        element = element.add(this.lockedTable);
                        useAllItems = selectable.multiple && selectable.cell;
                    }
                    filter = '>tbody>tr:not(.k-footer-template)';
                    if (selectable.cell) {
                        filter = filter + '>td';
                    }
                    this.selectable = new kendo.ui.Selectable(element, {
                        filter: filter,
                        aria: true,
                        multiple: selectable.multiple,
                        change: proxy(this._change, this),
                        useAllItems: useAllItems,
                        continuousItems: proxy(this._continuousItems, this, filter, selectable.cell),
                        relatedTarget: !selectable.cell && this._hasLockedColumns ? proxy(this._selectableTarget, this) : undefined
                    });
                }
            },
            _continuousItems: function (filter, cell) {
                if (!this.lockedContent) {
                    return;
                }
                var lockedItems = $(filter, this.lockedTable);
                var nonLockedItems = $(filter, this.table);
                var columns = cell ? this._lockedColumns().length : 1;
                var nonLockedColumns = cell ? this.columns.length - columns : 1;
                var result = [];
                for (var idx = 0; idx < lockedItems.length; idx += columns) {
                    push.apply(result, lockedItems.slice(idx, idx + columns));
                    push.apply(result, nonLockedItems.splice(0, nonLockedColumns));
                }
                return result;
            },
            _selectableTarget: function (items) {
                var related;
                var result = $();
                for (var idx = 0, length = items.length; idx < length; idx++) {
                    related = this._relatedRow(items[idx]);
                    if (inArray(related[0], items) < 0) {
                        result = result.add(related);
                    }
                }
                return result;
            },
            _relatedRow: function (row) {
                var lockedTable = this.lockedTable;
                row = $(row);
                if (!lockedTable) {
                    return row;
                }
                var table = row.closest(this.table.add(this.lockedTable));
                var index = table.find('>tbody>tr').index(row);
                table = table[0] === this.table[0] ? lockedTable : this.table;
                return table.find('>tbody>tr').eq(index);
            },
            select: function (value) {
                var selectable = this.selectable;
                if (!selectable) {
                    return $();
                }
                if (typeof value !== 'undefined') {
                    if (!selectable.options.multiple) {
                        selectable.clear();
                        value = value.first();
                    }
                    if (this._hasLockedColumns) {
                        value = value.add($.map(value, proxy(this._relatedRow, this)));
                    }
                }
                return selectable.value(value);
            },
            clearSelection: function () {
                var selected = this.select();
                if (selected.length) {
                    this.selectable.clear();
                    this.trigger(CHANGE);
                }
            },
            _dataSource: function (dataSource) {
                var ds = this.dataSource;
                if (ds) {
                    ds.unbind(CHANGE, this._refreshHandler);
                    ds.unbind(ERROR, this._errorHandler);
                    ds.unbind(PROGRESS, this._progressHandler);
                }
                this._refreshHandler = proxy(this.refresh, this);
                this._errorHandler = proxy(this._error, this);
                this._progressHandler = proxy(this._progress, this);
                ds = this.dataSource = TreeListDataSource.create(dataSource);
                ds.bind(CHANGE, this._refreshHandler);
                ds.bind(ERROR, this._errorHandler);
                ds.bind(PROGRESS, this._progressHandler);
                this._dataSourceFetchProxy = proxy(function () {
                    this.dataSource.fetch();
                }, this);
            },
            setDataSource: function (dataSource) {
                this._dataSource(dataSource);
                this._sortable();
                this._filterable();
                this._contentTree.render([]);
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            dataItem: function (element) {
                if (element instanceof TreeListModel) {
                    return element;
                }
                var row = $(element).closest('tr');
                var model = this.dataSource.getByUid(row.attr(kendo.attr('uid')));
                return model;
            },
            editRow: function (row) {
                var model;
                if (typeof row === STRING) {
                    row = this.tbody.find(row);
                }
                model = this.dataItem(row);
                if (!model) {
                    return;
                }
                if (this._editMode() != 'popup') {
                    model._edit = true;
                }
                this._cancelEditor();
                this._render();
                this._createEditor(model);
                this.trigger(EDIT, {
                    container: this.editor.wrapper,
                    model: model
                });
            },
            _cancelEdit: function (e) {
                e = extend(e, {
                    container: this.editor.wrapper,
                    model: this.editor.model
                });
                if (this.trigger(CANCEL, e)) {
                    return;
                }
                this.cancelRow();
            },
            cancelRow: function () {
                this._cancelEditor();
                this._render();
            },
            saveRow: function () {
                var editor = this.editor;
                var args;
                if (!editor) {
                    return;
                }
                args = {
                    model: editor.model,
                    container: editor.wrapper
                };
                if (editor.end() && !this.trigger(SAVE, args)) {
                    this.dataSource.sync();
                }
            },
            addRow: function (parent) {
                var editor = this.editor;
                var index = 0;
                var model = {};
                if (editor && !editor.end()) {
                    return;
                }
                if (parent) {
                    if (!(parent instanceof TreeListModel)) {
                        parent = this.dataItem(parent);
                    }
                    model[parent.parentIdField] = parent.id;
                    index = this.dataSource.indexOf(parent) + 1;
                    this.expand(parent).then(proxy(this._insertAt, this, model, index));
                    return;
                }
                this._insertAt(model, index);
            },
            _insertAt: function (model, index) {
                model = this.dataSource.insert(index, model);
                var row = this.itemFor(model);
                this.editRow(row);
            },
            removeRow: function (row) {
                var model = this.dataItem(row);
                var args = {
                    model: model,
                    row: row
                };
                if (model && !this.trigger(REMOVE, args)) {
                    this.dataSource.remove(model);
                    this.dataSource.sync();
                }
            },
            _cancelEditor: function () {
                var model;
                var editor = this.editor;
                if (editor) {
                    model = editor.model;
                    this._destroyEditor();
                    this.dataSource.cancelChanges(model);
                    model._edit = false;
                }
            },
            _destroyEditor: function () {
                if (!this.editor) {
                    return;
                }
                this.editor.close();
                this.editor = null;
            },
            _createEditor: function (model) {
                var row = this.itemFor(model);
                row = row.add(this._relatedRow(row));
                var mode = this._editMode();
                var options = {
                    columns: this.columns,
                    model: model,
                    target: this,
                    clearContainer: false,
                    template: this.options.editable.template
                };
                if (mode == 'inline') {
                    this.editor = new Editor(row, options);
                } else {
                    extend(options, {
                        window: this.options.editable.window,
                        commandRenderer: proxy(function () {
                            return this._buildCommands([
                                'update',
                                'canceledit'
                            ]);
                        }, this),
                        fieldRenderer: this._cellContent,
                        save: proxy(this.saveRow, this),
                        cancel: proxy(this._cancelEdit, this),
                        appendTo: this.wrapper
                    });
                    this.editor = new PopupEditor(row, options);
                }
            },
            _editMode: function () {
                var mode = 'inline', editable = this.options.editable;
                if (editable !== true) {
                    if (typeof editable == 'string') {
                        mode = editable;
                    } else {
                        mode = editable.mode || mode;
                    }
                }
                return mode.toLowerCase();
            },
            hideColumn: function (column) {
                this._toggleColumnVisibility(column, true);
            },
            showColumn: function (column) {
                this._toggleColumnVisibility(column, false);
            },
            _toggleColumnVisibility: function (column, hidden) {
                column = this._findColumn(column);
                if (!column || column.hidden === hidden) {
                    return;
                }
                column.hidden = hidden;
                this._ensureExpandableColumn();
                this._renderCols();
                this._renderHeader();
                this._render();
                this._adjustTablesWidth();
                this.trigger(hidden ? COLUMNHIDE : COLUMNSHOW, { column: column });
                if (!hidden && !column.width) {
                    this.table.add(this.thead.closest('table')).width('');
                }
            },
            _findColumn: function (column) {
                if (typeof column == 'number') {
                    column = this.columns[column];
                } else if (isPlainObject(column)) {
                    column = grep(this.columns, function (item) {
                        return item === column;
                    })[0];
                } else {
                    column = grep(this.columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                return column;
            },
            _adjustTablesWidth: function () {
                var idx, length;
                var cols = this.thead.prev().children();
                var colWidth, width = 0;
                for (idx = 0, length = cols.length; idx < length; idx++) {
                    colWidth = cols[idx].style.width;
                    if (colWidth && colWidth.indexOf('%') == -1) {
                        width += parseInt(colWidth, 10);
                    } else {
                        width = 0;
                        break;
                    }
                }
                if (width) {
                    this.table.add(this.thead.closest('table')).width(width);
                }
            },
            _reorderable: function () {
                if (!this.options.reorderable) {
                    return;
                }
                var scrollable = this.options.scrollable === true;
                var selector = (scrollable ? '.k-grid-header:first ' : 'table:first>.k-grid-header ') + HEADERCELLS;
                var that = this;
                this._draggableInstance = new ui.Draggable(this.wrapper, {
                    group: kendo.guid(),
                    filter: selector,
                    hint: function (target) {
                        return $('<div class="k-header k-drag-clue" />').css({
                            width: target.width(),
                            paddingLeft: target.css('paddingLeft'),
                            paddingRight: target.css('paddingRight'),
                            lineHeight: target.height() + 'px',
                            paddingTop: target.css('paddingTop'),
                            paddingBottom: target.css('paddingBottom')
                        }).html(target.attr(kendo.attr('title')) || target.attr(kendo.attr('field')) || target.text()).prepend('<span class="k-icon k-drag-status k-i-cancel" />');
                    }
                });
                this.reorderable = new ui.Reorderable(this.wrapper, {
                    draggable: this._draggableInstance,
                    dragOverContainers: proxy(this._allowDragOverContainers, this),
                    inSameContainer: function (e) {
                        return $(e.source).parent()[0] === $(e.target).parent()[0];
                    },
                    change: function (e) {
                        var newIndex = e.newIndex;
                        var oldIndex = e.oldIndex;
                        var before = e.position === 'before';
                        var column = that.columns[oldIndex];
                        that.trigger(COLUMNREORDER, {
                            newIndex: newIndex,
                            oldIndex: oldIndex,
                            column: column
                        });
                        that.reorderColumn(newIndex, column, before);
                    }
                });
            },
            _allowDragOverContainers: function (index) {
                return this.columns[index].lockable !== false;
            },
            reorderColumn: function (destIndex, column, before) {
                var lockChanged;
                var columns = this.columns;
                var sourceIndex = inArray(column, columns);
                var destColumn = columns[destIndex];
                var isLocked = !!destColumn.locked;
                var nonLockedColumnsLength = this._nonLockedColumns().length;
                if (sourceIndex === destIndex) {
                    return;
                }
                if (isLocked && !column.locked && nonLockedColumnsLength == 1) {
                    return;
                }
                if (!isLocked && column.locked && columns.length - nonLockedColumnsLength == 1) {
                    return;
                }
                if (before === undefined) {
                    before = destIndex < sourceIndex;
                }
                lockChanged = !!column.locked;
                lockChanged = lockChanged != isLocked;
                column.locked = isLocked;
                columns.splice(before ? destIndex : destIndex + 1, 0, column);
                columns.splice(sourceIndex < destIndex ? sourceIndex : sourceIndex + 1, 1);
                this._renderCols();
                var ths = $(this.lockedHeader).add(this.thead).find('th');
                ths.eq(sourceIndex)[before ? 'insertBefore' : 'insertAfter'](ths.eq(destIndex));
                var dom = this._headerTree.children[0].children;
                if (this._hasLockedColumns) {
                    dom = this._lockedHeaderTree.children[0].children.concat(dom);
                }
                dom.splice(before ? destIndex : destIndex + 1, 0, dom[sourceIndex]);
                dom.splice(sourceIndex < destIndex ? sourceIndex : sourceIndex + 1, 1);
                if (this._hasLockedColumns) {
                    this._lockedHeaderTree.children[0].children = dom.splice(0, this._lockedColumns().length);
                    this._headerTree.children[0].children = dom;
                }
                this._applyLockedContainersWidth();
                this.refresh();
                if (!lockChanged) {
                    return;
                }
                if (isLocked) {
                    this.trigger(COLUMNLOCK, { column: column });
                } else {
                    this.trigger(COLUMNUNLOCK, { column: column });
                }
            },
            lockColumn: function (column) {
                var columns = this.columns;
                if (typeof column == 'number') {
                    column = columns[column];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || column.hidden) {
                    return;
                }
                var index = this._lockedColumns().length - 1;
                this.reorderColumn(index, column, false);
            },
            unlockColumn: function (column) {
                var columns = this.columns;
                if (typeof column == 'number') {
                    column = columns[column];
                } else {
                    column = grep(columns, function (item) {
                        return item.field === column;
                    })[0];
                }
                if (!column || column.hidden) {
                    return;
                }
                var index = this._lockedColumns().length;
                this.reorderColumn(index, column, true);
            },
            _columnMenu: function () {
                var ths = $(this.lockedHeader).add(this.thead).find('th');
                var columns = this.columns;
                var options = this.options;
                var columnMenu = options.columnMenu;
                var column, menu, menuOptions, sortable, filterable;
                var initHandler = proxy(this._columnMenuInit, this);
                var lockedColumnsLength = this._lockedColumns().length;
                if (!columnMenu) {
                    return;
                }
                if (typeof columnMenu == 'boolean') {
                    columnMenu = {};
                }
                for (var i = 0; i < ths.length; i++) {
                    column = columns[i];
                    if (!column.field) {
                        continue;
                    }
                    menu = ths.eq(i).data('kendoColumnMenu');
                    if (menu) {
                        menu.destroy();
                    }
                    sortable = false;
                    if (column.sortable !== false && columnMenu.sortable !== false && options.sortable !== false) {
                        sortable = extend({}, options.sortable, { compare: (column.sortable || {}).compare });
                    }
                    filterable = false;
                    if (options.filterable && column.filterable !== false && columnMenu.filterable !== false) {
                        filterable = extend({ pane: this.pane }, column.filterable, options.filterable);
                    }
                    menuOptions = {
                        dataSource: this.dataSource,
                        values: column.values,
                        columns: columnMenu.columns,
                        sortable: sortable,
                        filterable: filterable,
                        messages: columnMenu.messages,
                        owner: this,
                        closeCallback: $.noop,
                        init: initHandler,
                        pane: this.pane,
                        lockedColumns: column.lockable !== false && lockedColumnsLength > 0
                    };
                    if (options.$angular) {
                        menuOptions.$angular = options.$angular;
                    }
                    ths.eq(i).kendoColumnMenu(menuOptions);
                }
            },
            _columnMenuInit: function (e) {
                this.trigger(COLUMNMENUINIT, {
                    field: e.field,
                    container: e.container
                });
            }
        });
        if (kendo.ExcelMixin) {
            kendo.ExcelMixin.extend(TreeList.prototype);
        }
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(TreeList.prototype);
            TreeList.fn._drawPDF = function (progress) {
                var promise = new $.Deferred();
                this._drawPDFShadow({ width: this.wrapper.width() }, { avoidLinks: this.options.pdf.avoidLinks }).done(function (group) {
                    var args = {
                        page: group,
                        pageNumber: 1,
                        progress: 1,
                        totalPages: 1
                    };
                    progress.notify(args);
                    promise.resolve(args.page);
                }).fail(function (err) {
                    promise.reject(err);
                });
                return promise;
            };
        }
        extend(true, kendo.data, {
            TreeListDataSource: TreeListDataSource,
            TreeListModel: TreeListModel
        });
        extend(true, kendo.ui, { TreeList: TreeList });
        ui.plugin(TreeList);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/main', ['kendo.core'], f);
}(function () {
    (function () {
        var kendo = window.kendo, deepExtend = kendo.deepExtend;
        function sqr(value) {
            return value * value;
        }
        var now = Date.now;
        if (!now) {
            now = function () {
                return new Date().getTime();
            };
        }
        function renderSize(size) {
            if (typeof size !== 'string') {
                size += 'px';
            }
            return size;
        }
        function renderPos(pos) {
            var result = [];
            if (pos) {
                var parts = kendo.toHyphens(pos).split('-');
                for (var i = 0; i < parts.length; i++) {
                    result.push('k-pos-' + parts[i]);
                }
            }
            return result.join(' ');
        }
        function arabicToRoman(n) {
            var literals = {
                1: 'i',
                10: 'x',
                100: 'c',
                2: 'ii',
                20: 'xx',
                200: 'cc',
                3: 'iii',
                30: 'xxx',
                300: 'ccc',
                4: 'iv',
                40: 'xl',
                400: 'cd',
                5: 'v',
                50: 'l',
                500: 'd',
                6: 'vi',
                60: 'lx',
                600: 'dc',
                7: 'vii',
                70: 'lxx',
                700: 'dcc',
                8: 'viii',
                80: 'lxxx',
                800: 'dccc',
                9: 'ix',
                90: 'xc',
                900: 'cm',
                1000: 'm'
            };
            var values = [
                1000,
                900,
                800,
                700,
                600,
                500,
                400,
                300,
                200,
                100,
                90,
                80,
                70,
                60,
                50,
                40,
                30,
                20,
                10,
                9,
                8,
                7,
                6,
                5,
                4,
                3,
                2,
                1
            ];
            var roman = '';
            while (n > 0) {
                if (n < values[0]) {
                    values.shift();
                } else {
                    roman += literals[values[0]];
                    n -= values[0];
                }
            }
            return roman;
        }
        function romanToArabic(r) {
            r = r.toLowerCase();
            var digits = {
                i: 1,
                v: 5,
                x: 10,
                l: 50,
                c: 100,
                d: 500,
                m: 1000
            };
            var value = 0, prev = 0;
            for (var i = 0; i < r.length; ++i) {
                var v = digits[r.charAt(i)];
                if (!v) {
                    return null;
                }
                value += v;
                if (v > prev) {
                    value -= 2 * prev;
                }
                prev = v;
            }
            return value;
        }
        function memoize(f) {
            var cache = Object.create(null);
            return function () {
                var id = '';
                for (var i = arguments.length; --i >= 0;) {
                    id += ':' + arguments[i];
                }
                return id in cache ? cache[id] : cache[id] = f.apply(this, arguments);
            };
        }
        function isUnicodeLetter(ch) {
            return RX_UNICODE_LETTER.test(ch);
        }
        deepExtend(kendo, {
            util: {
                now: now,
                renderPos: renderPos,
                renderSize: renderSize,
                sqr: sqr,
                romanToArabic: romanToArabic,
                arabicToRoman: arabicToRoman,
                memoize: memoize,
                isUnicodeLetter: isUnicodeLetter
            }
        });
        var RX_UNICODE_LETTER = new RegExp('[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0-\\u08B2\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA7AD\\uA7B0\\uA7B1\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB5F\\uAB64\\uAB65\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]');
    }());
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('util/parse-xml', [
        'kendo.core',
        'util/main'
    ], f);
}(function () {
    'use strict';
    var STRING = String.fromCharCode;
    var ENTITIES = {
        'amp': 38,
        'lt': 60,
        'gt': 62,
        'quot': 34,
        'apos': 39,
        'nbsp': 160
    };
    function CODE(str) {
        var out = [];
        for (var i = 0; i < str.length; ++i) {
            out.push(str.charCodeAt(i));
        }
        return out;
    }
    function UCS2(out, code) {
        if (code > 65535) {
            code -= 65536;
            out.push(code >>> 10 & 1023 | 55296, 56320 | code & 1023);
        } else {
            out.push(code);
        }
    }
    var START_CDATA = CODE('<![CDATA[');
    var END_CDATA = CODE(']]>');
    var END_COMMENT = CODE('-->');
    var START_COMMENT = CODE('!--');
    var END_SHORT_TAG = CODE('/>');
    var END_TAG = CODE('</');
    var END_DECLARATION = CODE('?>');
    var QUESTION_MARK = CODE('?');
    var LESS_THAN = CODE('<');
    var GREATER_THAN = CODE('>');
    var SEMICOLON = CODE(';');
    var EQUAL = CODE('=');
    var AMPERSAND = CODE('&');
    var QUOTE = CODE('"');
    var APOSTROPHE = CODE('\'');
    var SHARP = CODE('#');
    var LOWERCASE_X = CODE('x');
    var UPPERCASE_X = CODE('X');
    var EXIT = {};
    function parse(data, callbacks) {
        var index = 0;
        var stack = [];
        var object = {
            is: function (selector) {
                var i = stack.length, j = selector.length;
                while (--i >= 0 && --j >= 0) {
                    if (stack[i].$tag != selector[j] && selector[j] != '*') {
                        return false;
                    }
                }
                return j < 0 ? stack[stack.length - 1] : null;
            },
            exit: function () {
                throw EXIT;
            },
            stack: stack
        };
        function readChar(body) {
            var code = data[index++];
            if (!(code & 240 ^ 240)) {
                UCS2(body, (code & 3) << 18 | (data[index++] & 63) << 12 | (data[index++] & 63) << 6 | data[index++] & 63);
            } else if (!(code & 224 ^ 224)) {
                UCS2(body, (code & 15) << 12 | (data[index++] & 63) << 6 | data[index++] & 63);
            } else if (!(code & 192 ^ 192)) {
                UCS2(body, (code & 31) << 6 | data[index++] & 63);
            } else {
                body.push(code);
            }
        }
        function croak(msg) {
            throw new Error(msg + ', at ' + index);
        }
        function readWhile(pred) {
            var a = [];
            while (index < data.length && pred(data[index])) {
                a.push(data[index++]);
            }
            return a;
        }
        function readAsciiWhile(pred) {
            return STRING.apply(0, readWhile(pred));
        }
        function skipWhitespace() {
            readWhile(isWhitespace);
        }
        function eat(a) {
            var save = index;
            for (var i = 0; i < a.length; ++i) {
                if (data[index++] != a[i]) {
                    index = save;
                    return false;
                }
            }
            return a;
        }
        function skip(code) {
            if (!eat(code)) {
                croak('Expecting ' + code.join(', '));
            }
        }
        function isWhitespace(code) {
            return code == 9 || code == 10 || code == 13 || code == 32;
        }
        function isDigit(code) {
            return code >= 48 && code <= 57;
        }
        function isHexDigit(code) {
            return code >= 48 && code <= 57 || (code |= 32) >= 97 && code <= 102;
        }
        function isNameStart(code) {
            return code == 58 || code == 95 || (code |= 32) >= 97 && code <= 122;
        }
        function isName(code) {
            return code == 45 || isDigit(code) || isNameStart(code);
        }
        function xmlComment() {
            var body = [];
            while (index < data.length) {
                if (eat(END_COMMENT)) {
                    return call('comment', STRING.apply(0, body));
                }
                readChar(body);
            }
        }
        function xmlTag() {
            var name, attrs;
            if (eat(QUESTION_MARK)) {
                xmlDecl();
            } else if (eat(START_COMMENT)) {
                xmlComment();
            } else {
                name = xmlName();
                attrs = xmlAttrs(name);
                stack.push(attrs);
                if (eat(END_SHORT_TAG)) {
                    call('enter', name, attrs, true);
                } else {
                    skip(GREATER_THAN);
                    call('enter', name, attrs);
                    xmlContent(name);
                    if (name != xmlName()) {
                        croak('Bad closing tag');
                    }
                    call('leave', name, attrs);
                    skipWhitespace();
                    skip(GREATER_THAN);
                }
                stack.pop();
            }
        }
        function xmlContent(name) {
            var body = [];
            while (index < data.length) {
                if (eat(END_TAG)) {
                    return body.length && call('text', STRING.apply(0, body));
                } else if (eat(START_CDATA)) {
                    while (index < data.length && !eat(END_CDATA)) {
                        readChar(body);
                    }
                } else if (eat(LESS_THAN)) {
                    if (body.length) {
                        call('text', STRING.apply(0, body));
                    }
                    xmlTag();
                    body = [];
                } else if (eat(AMPERSAND)) {
                    xmlEntity(body);
                } else {
                    readChar(body);
                }
            }
            croak('Unclosed tag ' + name);
        }
        function xmlName() {
            if (!isNameStart(data[index])) {
                croak('Expecting XML name');
            }
            return readAsciiWhile(isName);
        }
        function xmlString() {
            var quote = eat(QUOTE) || eat(APOSTROPHE);
            if (!quote) {
                croak('Expecting string');
            }
            var body = [];
            while (index < data.length) {
                if (eat(quote)) {
                    return STRING.apply(0, body);
                } else if (eat(AMPERSAND)) {
                    xmlEntity(body);
                } else {
                    readChar(body);
                }
            }
            croak('Unfinished string');
        }
        function xmlEntity(body) {
            var code;
            if (eat(SHARP)) {
                if (eat(LOWERCASE_X) || eat(UPPERCASE_X)) {
                    code = parseInt(readAsciiWhile(isHexDigit), 16);
                } else {
                    code = parseInt(readAsciiWhile(isDigit), 10);
                }
                if (isNaN(code)) {
                    croak('Bad numeric entity');
                }
            } else {
                var name = xmlName();
                code = ENTITIES[name];
                if (code === undefined) {
                    croak('Unknown entity ' + name);
                }
            }
            UCS2(body, code);
            skip(SEMICOLON);
        }
        function xmlDecl() {
            call('decl', xmlName(), xmlAttrs());
            skip(END_DECLARATION);
        }
        function xmlAttrs(name) {
            var map = { $tag: name };
            while (index < data.length) {
                skipWhitespace();
                var code = data[index];
                if (code == 63 || code == 62 || code == 47) {
                    break;
                }
                map[xmlName()] = (skip(EQUAL), xmlString());
            }
            return map;
        }
        function call(what, thing, arg1, arg2) {
            var f = callbacks && callbacks[what];
            if (f) {
                f.call(object, thing, arg1, arg2);
            }
        }
        var tmp = [];
        readChar(tmp);
        if (tmp[0] != 65279) {
            index = 0;
        }
        while (index < data.length) {
            skipWhitespace();
            skip(LESS_THAN);
            xmlTag();
            skipWhitespace();
        }
    }
    kendo.util.parseXML = function parseXML() {
        try {
            return parse.apply(this, arguments);
        } catch (ex) {
            if (ex !== EXIT) {
                throw ex;
            }
        }
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/commands', [
        'kendo.core',
        'kendo.binder',
        'kendo.window',
        'kendo.list',
        'kendo.tabstrip'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var Command = 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();
                this._prevUnderline = range.underline();
                range.link(this._link);
                range.underline(true);
                if (range.value() == null) {
                    this._hasSetValue = true;
                    range.value(this._link);
                }
            },
            undo: function () {
                var range = this.range();
                range.link(this._prevLink);
                range.underline(this._prevUnderline);
                if (this._hasSetValue) {
                    range.value(null);
                }
            }
        });
        kendo.spreadsheet.GridLinesChangeCommand = TargetValueCommand.extend({
            getState: function () {
                this._state = this._range.sheet().showGridLines();
            },
            setState: function (v) {
                this._range.sheet().showGridLines(v);
            }
        });
        var PropertyChangeCommand = kendo.spreadsheet.PropertyChangeCommand = Command.extend({
            _setRange: function (range) {
                Command.prototype._setRange.call(this, range.skipHiddenCells());
            },
            init: function (options) {
                Command.fn.init.call(this, options);
                this._value = options.value;
            },
            exec: function () {
                var range = this.range();
                if (range.enable()) {
                    this.getState();
                    if (this.options.property === 'format') {
                        this._workbook.trigger('changeFormat', { range: range });
                    }
                    range[this._property](this._value);
                }
            }
        });
        kendo.spreadsheet.ClearContentCommand = Command.extend({
            exec: function () {
                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;
            },
            _batch: function (f) {
                return this.range().sheet().batch(f, {});
            },
            exec: function () {
                var self = this;
                self.getState();
                self._batch(function () {
                    self[self._type](self._style);
                });
            },
            noBorders: function () {
                this.range().insideBorders(null);
                this.outsideBorders(null);
            },
            allBorders: function (style) {
                this.range().insideBorders(style);
                this.outsideBorders(style);
            },
            leftBorder: function (style) {
                this.range().leftColumn().borderLeft(style);
            },
            rightBorder: function (style) {
                this.range().rightColumn().borderRight(style);
            },
            topBorder: function (style) {
                this.range().topRow().borderTop(style);
            },
            bottomBorder: function (style) {
                this.range().bottomRow().borderBottom(style);
            },
            outsideBorders: function (style) {
                var range = this.range();
                range.leftColumn().borderLeft(style);
                range.topRow().borderTop(style);
                range.rightColumn().borderRight(style);
                range.bottomRow().borderBottom(style);
            },
            insideBorders: function (style) {
                this.range().insideBorders(style);
                this.outsideBorders(null);
            },
            insideHorizontalBorders: function (style) {
                this.range().insideHorizontalBorders(style);
            },
            insideVerticalBorders: function (style) {
                this.range().insideVerticalBorders(style);
            }
        });
        kendo.spreadsheet.MergeCellCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._type = options.value;
            },
            exec: function () {
                this.getState();
                this[this._type]();
            },
            activate: function (ref) {
                this.range().sheet().activeCell(ref);
            },
            getState: function () {
                this._state = this.range().getState();
            },
            undo: function () {
                if (this._type !== 'unmerge') {
                    this.range().unmerge();
                    this.activate(this.range().topLeft());
                }
                this.range().setState(this._state);
            },
            cells: function () {
                var range = this.range();
                var ref = range._ref;
                range.merge();
                this.activate(ref);
            },
            horizontally: function () {
                var ref = this.range().topRow()._ref;
                this.range().forEachRow(function (range) {
                    range.merge();
                });
                this.activate(ref);
            },
            vertically: function () {
                var ref = this.range().leftColumn()._ref;
                this.range().forEachColumn(function (range) {
                    range.merge();
                });
                this.activate(ref);
            },
            unmerge: function () {
                var range = this.range();
                var ref = range._ref.topLeft;
                range.unmerge();
                this.activate(ref);
            }
        });
        kendo.spreadsheet.FreezePanesCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._type = options.value;
            },
            exec: function () {
                this.getState();
                this._topLeft = this.range().topLeft();
                this[this._type]();
            },
            getState: function () {
                this._state = this.range().sheet().getState();
            },
            undo: function () {
                this.range().sheet().setState(this._state);
            },
            panes: function () {
                var topLeft = this._topLeft;
                var sheet = this.range().sheet();
                sheet.frozenColumns(topLeft.col).frozenRows(topLeft.row);
            },
            rows: function () {
                var topLeft = this._topLeft;
                var sheet = this.range().sheet();
                sheet.frozenRows(topLeft.row);
            },
            columns: function () {
                var topLeft = this._topLeft;
                var sheet = this.range().sheet();
                sheet.frozenColumns(topLeft.col);
            },
            unfreeze: function () {
                var sheet = this.range().sheet();
                sheet.frozenRows(0).frozenColumns(0);
            }
        });
        kendo.spreadsheet.PasteCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._clipboard = options.workbook.clipboard();
                this._event = options.event;
            },
            getState: function () {
                this._range = this._workbook.activeSheet().range(this._clipboard.pasteRef());
                this._state = this._range.getState();
            },
            exec: function () {
                this.getState();
                this._clipboard.parse();
                var status = this._clipboard.canPaste();
                if (!status.canPaste) {
                    if (status.menuInvoked) {
                        return {
                            reason: 'error',
                            type: 'useKeyboard'
                        };
                    }
                    if (status.pasteOnMerged) {
                        return {
                            reason: 'error',
                            type: 'modifyMerged'
                        };
                    }
                    if (status.overflow) {
                        return {
                            reason: 'error',
                            type: 'overflow'
                        };
                    }
                    if (status.pasteOnDisabled) {
                        this._event.preventDefault();
                        return {
                            reason: 'error',
                            type: 'cannotModifyDisabled'
                        };
                    }
                    return { reason: 'error' };
                }
                var range = this._workbook.activeSheet().selection();
                var preventDefault = this._workbook.trigger('paste', { range: range });
                if (preventDefault) {
                    this._event.preventDefault();
                } else {
                    this._clipboard.paste();
                    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();
                this._event = options.event;
            },
            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;
                }
                var range = this._workbook.activeSheet().selection();
                var preventDefault = this._workbook.trigger('copy', { range: range });
                if (preventDefault) {
                    this._event.preventDefault();
                } else {
                    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();
                this._event = options.event;
            },
            exec: function () {
                if (!(this.range().enable() && this._clipboard.canCopy())) {
                    this._event.preventDefault();
                    return {
                        reason: 'error',
                        type: 'cannotModifyDisabled'
                    };
                }
                this.getState();
                var range = this._workbook.activeSheet().selection();
                var preventDefault = this._workbook.trigger('cut', { range: range });
                if (preventDefault) {
                    this._event.preventDefault();
                    return;
                }
                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();
                range.filter(!this._state);
            }
        });
        kendo.spreadsheet.SortCommand = Command.extend({
            undo: function () {
                var sheet = this.range().sheet();
                sheet.setState(this._state);
            },
            exec: function () {
                var range = this.range();
                var sheet = range.sheet();
                var activeCell = sheet.activeCell();
                var col = this.options.sheet ? activeCell.topLeft.col : this.options.column || 0;
                var ascending = this.options.value === 'asc' ? true : false;
                this._state = sheet.getState();
                if (this.options.sheet) {
                    range = this.expandRange();
                }
                var reason = range.cantSort();
                if (reason) {
                    return {
                        reason: 'error',
                        type: reason.code
                    };
                }
                range.sort({
                    column: col,
                    ascending: ascending
                });
            },
            expandRange: function () {
                var sheet = this.range().sheet();
                return new kendo.spreadsheet.Range(sheet._sheetRef, sheet);
            }
        });
        var ApplyFilterCommand = kendo.spreadsheet.ApplyFilterCommand = Command.extend({
            column: function () {
                return this.options.column || 0;
            },
            undo: function () {
                var sheet = this.range().sheet();
                sheet.clearFilter(this.column());
                if (this._state.length) {
                    this.range().filter(this._state);
                }
            },
            getState: function () {
                var sheet = this.range().sheet();
                var current = sheet.filter();
                if (current) {
                    this._state = current.columns.filter(function (c) {
                        return c.index == this.column();
                    }.bind(this));
                }
            },
            exec: function () {
                var range = this.range();
                var column = this.column();
                var current = range.sheet().filter();
                var options;
                var filterRule;
                var exists = false;
                if (this.options.valueFilter) {
                    filterRule = {
                        column: column,
                        filter: new kendo.spreadsheet.ValueFilter(this.options.valueFilter)
                    };
                } else if (this.options.customFilter) {
                    filterRule = {
                        column: column,
                        filter: new kendo.spreadsheet.CustomFilter(this.options.customFilter)
                    };
                }
                this.getState();
                if (current && current.ref.eq(range._ref) && current.columns.length) {
                    current.columns.forEach(function (element) {
                        if (element.index === column) {
                            exists = true;
                        }
                    });
                    options = current.columns.map(function (element) {
                        return element.index === column ? filterRule : {
                            column: element.index,
                            filter: element.filter
                        };
                    });
                    if (!exists) {
                        options.push(filterRule);
                    }
                } else {
                    options = filterRule;
                }
                range.filter(options);
            }
        });
        kendo.spreadsheet.ClearFilterCommand = ApplyFilterCommand.extend({
            exec: function () {
                var range = this.range();
                var column = this.column();
                this.getState();
                range.clearFilter(column);
            }
        });
        kendo.spreadsheet.HideLineCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this.axis = options.axis;
            },
            undo: function () {
                var sheet = this.range().sheet();
                sheet.setAxisState(this._state);
            },
            exec: function () {
                var sheet = this.range().sheet();
                this._state = sheet.getAxisState();
                if (this.axis == 'row') {
                    sheet.axisManager().hideSelectedRows();
                } else {
                    sheet.axisManager().hideSelectedColumns();
                }
            }
        });
        kendo.spreadsheet.UnHideLineCommand = kendo.spreadsheet.HideLineCommand.extend({
            exec: function () {
                var sheet = this.range().sheet();
                this._state = sheet.getAxisState();
                if (this.axis == 'row') {
                    sheet.axisManager().unhideSelectedRows();
                } else {
                    sheet.axisManager().unhideSelectedColumns();
                }
            }
        });
        var DeleteCommand = 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();
                var result = sheet.axisManager().preventAddColumn();
                if (result) {
                    return result;
                }
                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();
                var result = sheet.axisManager().preventAddRow();
                if (result) {
                    return result;
                }
                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'
                    };
                }
                var workbook = this.options.workbook;
                workbook.fromFile(this.options.file).then(function () {
                    var errors = workbook.excelImportErrors;
                    if (errors && errors.length) {
                        workbook._view.openDialog('importError', { errors: errors });
                    }
                });
            }
        });
        kendo.spreadsheet.SaveAsCommand = Command.extend({
            exec: function () {
                var fileName = this.options.name + this.options.extension;
                if (this.options.extension === '.xlsx') {
                    this.options.workbook.saveAsExcel({ fileName: fileName });
                } else if (this.options.extension === '.pdf') {
                    this.options.workbook.saveAsPDF($.extend(this.options.pdf, {
                        workbook: this.options.workbook,
                        fileName: fileName
                    }));
                }
            }
        });
        var NameCommand = Command.extend({
            init: function (options) {
                Command.fn.init.call(this, options);
                this._name = options.name;
                this._value = options.value;
            },
            getState: function () {
                this._state = this._workbook.nameDefinition(this._name);
            },
            setState: function () {
                this._workbook.nameDefinition(this._name, this._state);
                this._workbook.trigger('change', { recalc: true });
            }
        });
        kendo.spreadsheet.DefineNameCommand = NameCommand.extend({
            exec: function () {
                this.getState();
                try {
                    this._workbook.defineName(this._name, this._value);
                    this._workbook.trigger('change', { recalc: true });
                } catch (ex) {
                    return {
                        title: 'Error',
                        body: ex + '',
                        reason: 'error'
                    };
                }
            }
        });
        kendo.spreadsheet.DeleteNameCommand = NameCommand.extend({
            exec: function () {
                this.getState();
                this._workbook.undefineName(this._name);
                this._workbook.trigger('change', { recalc: true });
            }
        });
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/formulabar', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var classNames = { wrapper: 'k-spreadsheet-formula-bar' };
        var FormulaBar = kendo.ui.Widget.extend({
            init: function (element, options) {
                kendo.ui.Widget.call(this, element, options);
                element = this.element.addClass(FormulaBar.classNames.wrapper);
                this.formulaInput = new kendo.spreadsheet.FormulaInput($('<div/>').appendTo(element));
            },
            destroy: function () {
                if (this.formulaInput) {
                    this.formulaInput.destroy();
                }
                this.formulaInput = null;
            }
        });
        kendo.spreadsheet.FormulaBar = FormulaBar;
        $.extend(true, FormulaBar, { classNames: classNames });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/formulainput', ['kendo.core'], f);
}(function () {
    (function (kendo, window) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var Widget = kendo.ui.Widget;
        var ns = '.kendoFormulaInput';
        var keys = kendo.keys;
        var classNames = {
            wrapper: 'k-spreadsheet-formula-input',
            listWrapper: 'k-spreadsheet-formula-list'
        };
        var styles = [
            'font-family',
            'font-size',
            'font-stretch',
            'font-style',
            'font-weight',
            'letter-spacing',
            'text-transform',
            'line-height'
        ];
        var KEY_NAMES = {
            27: 'esc',
            37: 'left',
            39: 'right',
            35: 'end',
            36: 'home',
            32: 'spacebar'
        };
        var PRIVATE_FORMULA_CHECK = /(^_|[^a-z0-9]$)/i;
        var FormulaInput = Widget.extend({
            init: function (element, options) {
                Widget.call(this, element, options);
                element = this.element;
                element.addClass(FormulaInput.classNames.wrapper).attr('contenteditable', true).attr('spellcheck', false).css('white-space', 'pre');
                if (this.options.autoScale) {
                    element.on('input', this.scale.bind(this));
                }
                this._highlightedRefs = [];
                this._staticTokens = [];
                this._formulaSource();
                this._formulaList();
                this._popup();
                this._tooltip();
                element.on('keydown', this._keydown.bind(this)).on('keyup', this._keyup.bind(this)).on('blur', this._blur.bind(this)).on('input click', this._input.bind(this)).on('focus', this._focus.bind(this)).on('paste', this._paste.bind(this));
            },
            options: {
                name: 'FormulaInput',
                autoScale: false,
                filterOperator: 'startswith',
                scalePadding: 30,
                minLength: 1
            },
            events: [
                'keyup',
                'focus'
            ],
            enable: function (enable) {
                if (enable === undefined) {
                    return this.element.attr('contenteditable') === 'true';
                }
                if (enable) {
                    this.element.attr('contenteditable', enable);
                } else {
                    this.element.removeAttr('contenteditable');
                }
                this.element.toggleClass('k-state-disabled', !enable);
            },
            getPos: function () {
                var div = this.element[0];
                var sel = window.getSelection();
                var a = lookup(sel.focusNode, sel.focusOffset);
                var b = lookup(sel.anchorNode, sel.anchorOffset);
                if (a != null && b != null) {
                    if (a > b) {
                        var tmp = a;
                        a = b;
                        b = tmp;
                    }
                    return {
                        begin: a,
                        end: b,
                        collapsed: a == b
                    };
                }
                function lookup(lookupNode, pos) {
                    try {
                        (function loop(node) {
                            if (node === lookupNode) {
                                throw pos;
                            } else if (node.nodeType == 1) {
                                for (var i = node.firstChild; i; i = i.nextSibling) {
                                    loop(i);
                                }
                            } else if (node.nodeType == 3) {
                                pos += node.nodeValue.length;
                            }
                        }(div));
                    } catch (index) {
                        return index;
                    }
                }
            },
            setPos: function (begin, end) {
                var eiv = this.element[0];
                begin = lookup(eiv, begin);
                if (end != null) {
                    end = lookup(eiv, end);
                } else {
                    end = begin;
                }
                if (begin && end) {
                    var range = document.createRange();
                    range.setStart(begin.node, begin.pos);
                    range.setEnd(end.node, end.pos);
                    var sel = window.getSelection();
                    var currentRange = sel.getRangeAt(0);
                    if (differ(range, currentRange)) {
                        sel.removeAllRanges();
                        sel.addRange(range);
                    }
                }
                function differ(a, b) {
                    return a.startOffset != b.startOffset || a.endOffset != b.endOffset || a.startContainer != b.endContainer || a.endContainer != b.endContainer;
                }
                function lookup(node, pos) {
                    try {
                        (function loop(node) {
                            if (node.nodeType == 3) {
                                var len = node.nodeValue.length;
                                if (len >= pos) {
                                    throw node;
                                }
                                pos -= len;
                            } else if (node.nodeType == 1) {
                                for (var i = node.firstChild; i; i = i.nextSibling) {
                                    loop(i);
                                }
                            }
                        }(node));
                    } catch (el) {
                        return {
                            node: el,
                            pos: pos
                        };
                    }
                }
            },
            end: function () {
                this.setPos(this.length());
            },
            home: function () {
                this.setPos(0);
            },
            select: function () {
                this.setPos(0, this.length());
            },
            length: function () {
                return this.value().length;
            },
            _formulaSource: function () {
                var result = [];
                var value;
                for (var key in kendo.spreadsheet.calc.runtime.FUNCS) {
                    if (!PRIVATE_FORMULA_CHECK.test(key)) {
                        value = key.toUpperCase();
                        result.push({
                            value: value,
                            text: value
                        });
                    }
                }
                this.formulaSource = new kendo.data.DataSource({ data: result });
            },
            _formulaList: function () {
                this.list = new kendo.ui.StaticList($('<ul />').addClass(FormulaInput.classNames.listWrapper).insertAfter(this.element), {
                    autoBind: false,
                    selectable: true,
                    change: this._formulaListChange.bind(this),
                    dataSource: this.formulaSource,
                    dataValueField: 'value',
                    template: '#:data.value#'
                });
                this.list.element.on('mousedown', function (e) {
                    e.preventDefault();
                });
            },
            _formulaListChange: function () {
                var tokenCtx = this._tokenContext();
                if (!tokenCtx || this._mute) {
                    return;
                }
                var activeToken = tokenCtx.token;
                var completion = this.list.value()[0];
                var ctx = {
                    replace: true,
                    token: activeToken,
                    end: activeToken.end
                };
                if (!tokenCtx.nextToken || tokenCtx.nextToken.value != '(') {
                    completion += '(';
                }
                this._replaceAt(ctx, completion);
                this.popup.close();
            },
            _popup: function () {
                this.popup = new kendo.ui.Popup(this.list.element, { anchor: this.element });
            },
            _blur: function () {
                this.popup.close();
                clearTimeout(this._focusId);
                this.trigger('blur');
            },
            _isFormula: function () {
                return /^=/.test(this.value());
            },
            _keydown: function (e) {
                var key = e.keyCode;
                if (KEY_NAMES[key]) {
                    this.popup.close();
                    this._navigated = true;
                } else if (this._move(key)) {
                    this._navigated = true;
                    e.preventDefault();
                }
                this._keyDownTimeout = setTimeout(this._syntaxHighlight.bind(this));
            },
            _keyup: function () {
                var popup = this.popup;
                var value;
                if (this._isFormula() && !this._navigated) {
                    value = ((this._tokenContext() || {}).token || {}).value;
                    this.filter(value);
                    if (!value || !this.formulaSource.view().length) {
                        popup.close();
                    } else {
                        popup[popup.visible() ? 'position' : 'open']();
                        this.list.focusFirst();
                    }
                }
                this._navigated = false;
                this._syntaxHighlight();
                this.trigger('keyup');
            },
            _input: function () {
                this._syntaxHighlight();
            },
            _focus: function () {
                this._focusTimeout = setTimeout(this._syntaxHighlight.bind(this));
                this.trigger('focus');
            },
            _paste: function (ev) {
                ev.preventDefault();
                var pos = this.getPos();
                var text;
                if (kendo.support.browser.msie) {
                    text = window.clipboardData.getData('Text');
                } else {
                    text = ev.originalEvent.clipboardData.getData('text/plain');
                }
                var val = this.value();
                val = val.substr(0, pos.begin) + text + val.substr(pos.end);
                this.value(val);
                this.setPos(pos.begin + text.length);
                this.scale();
            },
            _move: function (key) {
                var list = this.list;
                var popup = this.popup;
                if (popup.visible()) {
                    if (key === keys.DOWN) {
                        list.focusNext();
                        if (!list.focus()) {
                            list.focusFirst();
                        }
                        return true;
                    }
                    if (key === keys.UP) {
                        list.focusPrev();
                        if (!list.focus()) {
                            list.focusLast();
                        }
                        return true;
                    }
                    if (key === keys.ENTER) {
                        list.select(list.focus());
                        popup.close();
                        return true;
                    }
                    if (key === keys.TAB) {
                        list.select(list.focus());
                        popup.close();
                        return true;
                    }
                    if (key === keys.PAGEUP) {
                        list.focusFirst();
                        return true;
                    }
                    if (key === keys.PAGEDOWN) {
                        list.focusLast();
                        return true;
                    }
                }
                return key === keys.ENTER || key === keys.TAB;
            },
            _tokenContext: function () {
                var point = this.getPos();
                var value = this.value();
                if (!value || !point || !point.collapsed) {
                    return null;
                }
                var tokens = kendo.spreadsheet.calc.tokenize(value, this.row(), this.col());
                var tok;
                for (var i = 0; i < tokens.length; ++i) {
                    tok = tokens[i];
                    if (touches(tok, point) && /^(?:str|sym|func)$/.test(tok.type)) {
                        return {
                            token: tok,
                            nextToken: tokens[i + 1]
                        };
                    }
                }
                return null;
            },
            _sync: function () {
                if (this._editorToSync && this.isActive()) {
                    this._editorToSync.value(this.value());
                }
            },
            _textContainer: function () {
                var computedStyles = kendo.getComputedStyles(this.element[0], styles);
                computedStyles.position = 'absolute';
                computedStyles.visibility = 'hidden';
                computedStyles.whiteSpace = 'pre';
                computedStyles.top = -3333;
                computedStyles.left = -3333;
                this._span = $('<span style=\'white-space: pre\'/>').css(computedStyles).insertAfter(this.element);
            },
            _tooltip: function () {
                this._cellTooltip = $('<div class="k-widget k-tooltip" style="position:absolute; display:none">A1</div>').insertAfter(this.element);
            },
            tooltip: function (value) {
                this._cellTooltip.text(value);
            },
            toggleTooltip: function (show) {
                this._cellTooltip.toggle(show);
            },
            isActive: function () {
                return this.element[0] === kendo._activeElement();
            },
            filter: function (value) {
                if (!value || value.length < this.options.minLength) {
                    return;
                }
                this._mute = true;
                this.list.select(-1);
                this._mute = false;
                this.formulaSource.filter({
                    field: this.list.options.dataValueField,
                    operator: this.options.filterOperator,
                    value: value
                });
            },
            hide: function () {
                this.enable(false);
                this.element.hide();
                this._cellTooltip.hide();
            },
            show: function () {
                this.enable(true);
                this.element.show();
            },
            row: function () {
                if (this.activeCell) {
                    return this.activeCell.row;
                }
            },
            col: function () {
                if (this.activeCell) {
                    return this.activeCell.col;
                }
            },
            position: function (rectangle) {
                if (!rectangle) {
                    return;
                }
                this.show();
                this.element.css({
                    'top': rectangle.top + 1 + 'px',
                    'left': rectangle.left + 1 + 'px'
                });
                this._cellTooltip.css({
                    'top': rectangle.top - this._cellTooltip.height() - 10 + 'px',
                    'left': rectangle.left
                });
            },
            resize: function (rectangle) {
                if (!rectangle) {
                    return;
                }
                this.element.css({
                    width: rectangle.width - 1,
                    height: rectangle.height - 1
                });
            },
            canInsertRef: function (isKeyboardAction) {
                var result = this._canInsertRef(isKeyboardAction);
                var token = result && result.token;
                var idx;
                if (token) {
                    for (idx = 0; idx < this._staticTokens.length; idx++) {
                        if (isEqualToken(token, this._staticTokens[idx])) {
                            return null;
                        }
                    }
                }
                return result;
            },
            _canInsertRef: function (isKeyboardAction) {
                if (this.popup.visible()) {
                    return null;
                }
                var strictMode = isKeyboardAction;
                var point = this.getPos();
                var tokens, tok;
                if (point && this._isFormula()) {
                    if (point.begin === 0) {
                        return null;
                    }
                    tokens = kendo.spreadsheet.calc.tokenize(this.value(), this.row(), this.col());
                    for (var i = 0; i < tokens.length; ++i) {
                        tok = tokens[i];
                        if (touches(tok, point)) {
                            return canReplace(tok);
                        }
                        if (afterPoint(tok)) {
                            return canInsertBetween(tokens[i - 1], tok);
                        }
                    }
                    return canInsertBetween(tok, null);
                }
                return null;
                function afterPoint(tok) {
                    return tok.begin > point.begin;
                }
                function canReplace(tok) {
                    if (tok) {
                        if (/^(?:num|str|bool|sym|ref)$/.test(tok.type)) {
                            return {
                                replace: true,
                                token: tok,
                                end: tok.end
                            };
                        }
                        if (/^(?:op|punc|startexp)$/.test(tok.type)) {
                            if (tok.end == point.end) {
                                return canInsertBetween(tok, tokens[i + 1]);
                            }
                            return canInsertBetween(tokens[i - 1], tok);
                        }
                    }
                }
                function canInsertBetween(left, right) {
                    if (left == null) {
                        return null;
                    }
                    if (right == null) {
                        if (/^(?:op|startexp)$/.test(left.type) || isOpenParen(left.value)) {
                            return {
                                token: left,
                                end: point.end
                            };
                        }
                        return null;
                    }
                    if (strictMode) {
                        if (left.type == 'op' && /^(?:punc|op)$/.test(right.type)) {
                            return {
                                token: left,
                                end: point.end
                            };
                        }
                    } else {
                        if (left.type == 'startexp') {
                            return {
                                token: left,
                                end: point.end
                            };
                        }
                        if (/^(?: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;
                    return txt.replace(/\n$/, '');
                }
                this._value(value);
                this._syntaxHighlight();
            },
            highlightedRefs: function () {
                return this._highlightedRefs.slice();
            },
            _syntaxHighlight: function () {
                var pos = this.getPos();
                var value = this.value();
                var refClasses = kendo.spreadsheet.Pane.classNames.series;
                var highlightedRefs = [];
                var refIndex = 0;
                var parens = [];
                var tokens = [];
                var activeToken;
                if (pos && !pos.collapsed) {
                    return;
                }
                if (!/^=/.test(value)) {
                    if (this._staticTokens.length || this._highlightedRefs.length) {
                        this._staticTokens = [];
                        this._highlightedRefs = [];
                        this.element.text(value);
                    }
                    if (this.popup) {
                        this.popup.close();
                    }
                    return;
                } else {
                    tokens = kendo.spreadsheet.calc.tokenize(value, this.row(), this.col());
                    tokens.forEach(function (tok) {
                        tok.active = false;
                        tok.cls = ['k-syntax-' + tok.type];
                        if (tok.type == 'ref') {
                            tok.colorClass = refClasses[refIndex++ % refClasses.length];
                            tok.cls.push(tok.colorClass);
                            highlightedRefs.push(tok);
                        }
                        if (pos && tok.type == 'punc') {
                            if (isOpenParen(tok.value)) {
                                parens.unshift(tok);
                            } else if (isCloseParen(tok.value)) {
                                var open = parens.shift();
                                if (open) {
                                    if (isMatchingParen(tok.value, open.value)) {
                                        if (touches(tok, pos) || touches(open, pos)) {
                                            tok.cls.push('k-syntax-paren-match');
                                            open.cls.push('k-syntax-paren-match');
                                        }
                                    } else {
                                        tok.cls.push('k-syntax-error');
                                        open.cls.push('k-syntax-error');
                                    }
                                } else {
                                    tok.cls.push('k-syntax-error');
                                }
                            }
                        }
                        if (pos && touches(tok, pos)) {
                            tok.cls.push('k-syntax-at-point');
                            tok.active = true;
                            activeToken = tok;
                        }
                        if (tok.type == 'func' && !knownFunction(tok.value) && (!pos || !touches(tok, pos))) {
                            tok.cls.push('k-syntax-error');
                        }
                    });
                    tokens.reverse().forEach(function (tok) {
                        var begin = tok.begin, end = tok.end;
                        var text = kendo.htmlEncode(value.substring(begin, end));
                        value = value.substr(0, begin) + '<span class=\'' + tok.cls.join(' ') + '\'>' + text + '</span>' + value.substr(end);
                    });
                    this.element.html(value);
                }
                if (pos) {
                    this.setPos(pos.begin, pos.end);
                }
                if (activeToken && /^(?:startexp|op|punc)$/.test(activeToken.type)) {
                    this._setStaticTokens(tokens);
                }
                this._highlightedRefs = highlightedRefs;
            },
            _setStaticTokens: function (tokens) {
                var idx, tok;
                this._staticTokens = [];
                for (idx = 0; idx < tokens.length; idx++) {
                    tok = tokens[idx];
                    if (/^(?:num|str|bool|sym|ref)$/.test(tok.type)) {
                        this._staticTokens.push(tok);
                    }
                }
            },
            destroy: function () {
                this._editorToSync = null;
                this.element.off(ns);
                clearTimeout(this._focusTimeout);
                clearTimeout(this._keyDownTimeout);
                this._cellTooltip = null;
                this._span = null;
                this.popup.destroy();
                this.popup = null;
                Widget.fn.destroy.call(this);
            },
            insertNewline: function () {
                var val = this.value();
                var pos = this.getPos();
                var eof = pos.end == val.length;
                val = val.substr(0, pos.begin) + (eof ? '\n\n' : '\n' + val.substr(pos.end));
                this.value(val);
                this.setPos(pos.begin + 1);
            }
        });
        function isOpenParen(ch) {
            return ch == '(' || ch == '[' || ch == '{';
        }
        function isCloseParen(ch) {
            return ch == ')' || ch == ']' || ch == '}';
        }
        function isMatchingParen(close, open) {
            return open == '(' ? close == ')' : open == '[' ? close == ']' : open == '{' ? close == '}' : false;
        }
        function touches(pos, target) {
            return pos.begin <= target.begin && pos.end >= target.end;
        }
        function knownFunction(name) {
            return kendo.spreadsheet.calc.runtime.FUNCS[name.toLowerCase()];
        }
        function isEqualToken(tok1, tok2) {
            if (!tok1 || !tok2) {
                return false;
            }
            if (tok1.type == 'ref' && tok2.type == 'ref') {
                return tok1.ref.eq(tok2.ref);
            } else {
                return tok1.value === tok2.value;
            }
        }
        kendo.spreadsheet.FormulaInput = FormulaInput;
        $.extend(true, FormulaInput, { classNames: classNames });
    }(kendo, window));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/eventlistener', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var KEY_NAMES = {
            8: 'backspace',
            9: 'tab',
            13: 'enter',
            27: 'esc',
            37: 'left',
            38: 'up',
            39: 'right',
            40: 'down',
            35: 'end',
            36: 'home',
            32: 'spacebar',
            33: 'pageup',
            34: 'pagedown',
            46: 'delete',
            113: ':edit'
        };
        var Mac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
        var isAlphaNum = function (keyCode) {
            if (keyCode > 47 && keyCode < 58 || keyCode > 64 && keyCode < 91 || keyCode > 95 && keyCode < 112 || keyCode > 185 && keyCode < 193 || keyCode > 218 && keyCode < 223) {
                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) {
                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 Property = kendo.Class.extend({
            init: function (list) {
                this.list = list;
            },
            get: function (index) {
                return this.parse(this.list.value(index, index));
            },
            set: function (start, end, value) {
                if (value === undefined) {
                    value = end;
                    end = start;
                }
                this.list.value(start, end, value);
            },
            parse: function (value) {
                return value;
            },
            copy: function (start, end, dst) {
                this.list.copy(start, end, dst);
            },
            iterator: function (start, end) {
                return this.list.iterator(start, end);
            }
        });
        var JsonProperty = Property.extend({
            set: function (start, end, value) {
                this.list.value(start, end, JSON.stringify(value));
            },
            parse: function (value) {
                return JSON.parse(value);
            }
        });
        var ValueProperty = Property.extend({
            init: function (values, formats) {
                Property.prototype.init.call(this, values);
                this.formats = formats;
            },
            set: function (start, end, value) {
                if (value instanceof Date) {
                    value = kendo.spreadsheet.dateToNumber(value);
                    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: Property,
                    name: 'format',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: ValueProperty,
                    name: 'value',
                    value: null,
                    sortable: true,
                    serializable: true,
                    depends: 'format'
                },
                {
                    property: Property,
                    name: 'formula',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'background',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: JsonProperty,
                    name: 'vBorders',
                    value: null,
                    sortable: false,
                    serializable: false
                },
                {
                    property: JsonProperty,
                    name: 'hBorders',
                    value: null,
                    sortable: false,
                    serializable: false
                },
                {
                    property: Property,
                    name: 'color',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'fontFamily',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'underline',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'fontSize',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'italic',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'bold',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: 'textAlign',
                    value: null,
                    sortable: true,
                    serializable: true
                },
                {
                    property: Property,
                    name: '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 (rowCount, columnCount, defaultValues) {
                defaultValues = defaultValues || {};
                var cellCount = rowCount * columnCount - 1;
                this.rowCount = rowCount;
                this.columnCount = columnCount;
                this.cellCount = cellCount;
                this.properties = {};
                this.lists = {};
                this.specs.forEach(function (spec) {
                    var name = spec.name;
                    var value = defaultValues[name];
                    if (value === undefined) {
                        value = spec.value;
                    }
                    this.lists[name] = new kendo.spreadsheet.SparseRangeList(0, cellCount, value);
                    this.properties[name] = new spec.property(this.lists[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];
                }
                switch (name) {
                case 'borderRight':
                    index += this.rowCount;
                case 'borderLeft':
                    name = 'vBorders';
                    break;
                case 'borderBottom':
                    index++;
                case 'borderTop':
                    name = 'hBorders';
                    break;
                }
                return index > this.cellCount ? null : this.properties[name].get(index);
            },
            set: function (name, start, end, value) {
                switch (name) {
                case 'borderRight':
                    start += this.rowCount;
                    end += this.rowCount;
                case 'borderLeft':
                    name = 'vBorders';
                    break;
                case 'borderBottom':
                    start++;
                    end++;
                case 'borderTop':
                    name = 'hBorders';
                    break;
                }
                if (start <= end && end <= this.cellCount) {
                    this.properties[name].set(start, end, value);
                }
            },
            fromJSON: function (index, value) {
                for (var si = 0; si < this.specs.length; si++) {
                    var spec = this.specs[si];
                    if (spec.serializable) {
                        if (value[spec.name] !== undefined) {
                            this.set(spec.name, index, index, value[spec.name], false);
                        }
                    }
                }
                [
                    'borderLeft',
                    'borderRight',
                    'borderTop',
                    'borderBottom'
                ].forEach(function (b) {
                    if (value[b] !== undefined) {
                        this.set(b, index, index, value[b]);
                    }
                }, this);
            },
            copy: function (sourceStart, sourceEnd, targetStart) {
                this.specs.forEach(function (spec) {
                    this.properties[spec.name].copy(sourceStart, sourceEnd, targetStart);
                }, this);
            },
            iterator: function (name, start, end) {
                var prop = this.properties[name];
                var iter = prop.iterator(start, end), at = iter.at;
                var cellCount = this.cellCount;
                iter.at = function (index) {
                    return index > cellCount ? null : prop.parse(at.call(iter, index));
                };
                iter.name = name;
                iter.value = prop.list.range.value;
                return iter;
            },
            sortable: function () {
                return this.specs.filter(function (spec) {
                    return spec.sortable;
                }).map(function (spec) {
                    return this.lists[spec.name];
                }, this);
            },
            iterators: function (start, end) {
                return this.specs.reduce(function (ret, spec) {
                    if (spec.serializable) {
                        ret.push(this.iterator(spec.name, start, end));
                    }
                    return ret;
                }.bind(this), []);
            },
            forEach: function (start, end, callback) {
                var iterators = this.iterators(start, end);
                var hBorders = this.iterator('hBorders', start, end + 1);
                var leftBorders = this.iterator('vBorders', start, end);
                var rightBorders = this.iterator('vBorders', start + this.rowCount, end + this.rowCount);
                var values, index;
                function addBorder(name, iterator, index) {
                    var val = iterator.at(index);
                    if (val !== iterator.value) {
                        values[name] = val;
                    }
                }
                for (index = start; index <= end; index++) {
                    values = {};
                    for (var i = 0; i < iterators.length; i++) {
                        var iterator = iterators[i];
                        var value = iterator.at(index);
                        if (value !== iterator.value) {
                            values[iterator.name] = value;
                        }
                    }
                    addBorder('borderLeft', leftBorders, index);
                    addBorder('borderRight', rightBorders, index + this.rowCount);
                    addBorder('borderTop', hBorders, index);
                    if ((index + 1) % this.rowCount) {
                        addBorder('borderBottom', hBorders, index + 1);
                    }
                    callback(values);
                }
            },
            forEachProperty: function (callback) {
                for (var name in this.properties) {
                    callback(this.properties[name]);
                }
            }
        });
        kendo.spreadsheet.ALL_PROPERTIES = kendo.spreadsheet.PropertyBag.prototype.specs.reduce(function (a, spec) {
            if (spec.serializable) {
                a.push(spec.name);
            }
            return a;
        }, [
            'borderTop',
            'borderRight',
            'borderBottom',
            'borderLeft'
        ]);
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/references', ['kendo.core'], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var spreadsheet = kendo.spreadsheet;
    var Class = kendo.Class;
    function columnName(colIndex) {
        var letter = Math.floor(colIndex / 26) - 1;
        return (letter >= 0 ? columnName(letter) : '') + String.fromCharCode(65 + colIndex % 26);
    }
    function displaySheet(sheet) {
        if (/^[a-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(function (ref) {
                if (ref instanceof UnionRef) {
                    ref.forEach(callback, obj);
                } else {
                    callback.call(obj, ref);
                }
            }, obj);
        },
        toRangeRef: function () {
            return this.refs[0].toRangeRef();
        },
        contains: function (theRef) {
            return this.refs.some(function (ref) {
                return ref.contains(theRef);
            });
        },
        map: function (callback, obj) {
            var refs = [];
            this.forEach(function (ref) {
                refs.push(callback.call(obj, ref));
            });
            return new UnionRef(refs);
        },
        first: function () {
            return this.refs[0].first();
        },
        lastRange: function () {
            return this.refs[this.length - 1];
        },
        size: function () {
            return this.length;
        },
        single: function () {
            return this.length == 1;
        },
        empty: function () {
            return this.length === 0;
        },
        isCell: function () {
            return this.single() && this.refs[0].isCell();
        },
        rangeAt: function (index) {
            return this.refs[index];
        },
        nextRangeIndex: function (index) {
            if (index === this.length - 1) {
                return 0;
            } else {
                return index + 1;
            }
        },
        previousRangeIndex: function (index) {
            if (index === 0) {
                return this.length - 1;
            } else {
                return index - 1;
            }
        },
        concat: function (ref) {
            return new UnionRef(this.refs.concat([ref]));
        },
        print: function (row, col, mod) {
            return this.refs.map(function (ref) {
                return ref.print(row, col, mod);
            }).join(',');
        },
        replaceAt: function (index, ref) {
            var newRefs = this.refs.slice();
            newRefs.splice(index, 1, ref);
            return new UnionRef(newRefs);
        },
        leftColumn: function () {
            return this.map(function (ref) {
                return ref.leftColumn();
            });
        },
        rightColumn: function () {
            return this.map(function (ref) {
                return ref.rightColumn();
            });
        },
        topRow: function () {
            return this.map(function (ref) {
                return ref.topRow();
            });
        },
        bottomRow: function () {
            return this.map(function (ref) {
                return ref.bottomRow();
            });
        },
        forEachRow: function (callback) {
            this.forEach(function (ref) {
                ref.forEachRow(callback);
            });
        },
        forEachColumn: function (callback) {
            this.forEach(function (ref) {
                ref.forEachColumn(callback);
            });
        },
        adjust: function (row, col, trow, tcol, forRow, start, delta) {
            return this.map(function (ref) {
                return ref.adjust(row, col, trow, tcol, forRow, start, delta);
            }).simplify();
        },
        toString: function () {
            return this.refs.map(function (ref) {
                return ref.toString();
            }).join(', ');
        },
        valid: function () {
            for (var i = this.refs.length; --i >= 0;) {
                if (this.refs[i].valid()) {
                    return false;
                }
            }
            return true;
        },
        renameSheet: function (oldSheetName, newSheetName) {
            this.refs.forEach(function (ref) {
                ref.renameSheet(oldSheetName, newSheetName);
            });
        }
    });
    spreadsheet.NULLREF = NULL;
    spreadsheet.SHEETREF = new RangeRef(new CellRef(0, 0), new CellRef(Infinity, Infinity));
    spreadsheet.FIRSTREF = new CellRef(0, 0);
    spreadsheet.Ref = Ref;
    spreadsheet.NameRef = NameRef;
    spreadsheet.CellRef = CellRef;
    spreadsheet.RangeRef = RangeRef;
    spreadsheet.UnionRef = UnionRef;
    spreadsheet.SHEETREF.print = function () {
        return '#SHEET';
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/autofillcalculator', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var RangeRef = kendo.spreadsheet.RangeRef;
        var CellRef = kendo.spreadsheet.CellRef;
        var AutoFillCalculator = kendo.Class.extend({
            init: function (grid) {
                this._grid = grid;
            },
            rectIsVertical: function (start, end, x, y) {
                var startRect = this._grid.rectangle(start.toRangeRef());
                var endRect = this._grid.rectangle(end.toRangeRef());
                return Math.abs(endRect[y] - startRect[y]) > Math.abs(startRect[x] - endRect[x]);
            },
            autoFillDest: function (selection, cursor) {
                var topLeft = selection.topLeft;
                var bottomRight = selection.bottomRight;
                var quadrant;
                var lower = cursor.row >= topLeft.row;
                var further = cursor.col >= topLeft.col;
                if (lower) {
                    quadrant = further ? 4 : 3;
                } else {
                    quadrant = further ? 2 : 1;
                }
                var pivot, opposite, cornerResult, expanding;
                if (quadrant === 4) {
                    pivot = topLeft;
                    opposite = bottomRight;
                    expanding = cursor.row > opposite.row || cursor.col > opposite.col;
                    if (expanding) {
                        cursor = new CellRef(Math.max(cursor.row, opposite.row), Math.max(cursor.col, opposite.col));
                    }
                    if (this.rectIsVertical(opposite, cursor, 'right', 'bottom')) {
                        cornerResult = new CellRef(cursor.row, opposite.col);
                    } else {
                        cornerResult = new CellRef(opposite.row, cursor.col);
                    }
                } else if (quadrant === 3) {
                    var bottomLeft = new CellRef(topLeft.col, bottomRight.row);
                    if (cursor.row > bottomRight.row && this.rectIsVertical(bottomLeft, cursor, 'left', 'bottom')) {
                        pivot = topLeft;
                        cornerResult = new CellRef(cursor.row, bottomRight.col);
                    } else {
                        pivot = bottomRight;
                        cornerResult = new CellRef(topLeft.row, cursor.col);
                    }
                } else if (quadrant === 2) {
                    var topRight = new CellRef(topLeft.row, bottomRight.col);
                    if (cursor.col > bottomRight.col && !this.rectIsVertical(topRight, cursor, 'right', 'top')) {
                        pivot = topLeft;
                        cornerResult = new CellRef(bottomRight.row, cursor.col);
                    } else {
                        pivot = bottomRight;
                        cornerResult = new CellRef(cursor.row, topLeft.col);
                    }
                } else {
                    pivot = bottomRight;
                    if (this.rectIsVertical(topLeft, cursor, 'left', 'top')) {
                        cornerResult = new CellRef(cursor.row, topLeft.col);
                    } else {
                        cornerResult = new CellRef(topLeft.row, cursor.col);
                    }
                }
                return this._grid.normalize(new RangeRef(pivot, cornerResult));
            }
        });
        kendo.spreadsheet.AutoFillCalculator = AutoFillCalculator;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/navigator', [
        'kendo.core',
        'spreadsheet/autofillcalculator'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var RangeRef = kendo.spreadsheet.RangeRef;
        var CellRef = kendo.spreadsheet.CellRef;
        var EdgeNavigator = kendo.Class.extend({
            init: function (field, axis, rangeGetter, union) {
                this.rangeGetter = rangeGetter;
                this.prevLeft = function (index) {
                    var current = union(this.range(index));
                    var range = this.range(axis.prevVisible(current.topLeft[field]));
                    return union(range).topLeft[field];
                };
                this.nextRight = function (index) {
                    var current = union(this.range(index));
                    var range = this.range(axis.nextVisible(current.bottomRight[field]));
                    return union(range).bottomRight[field];
                };
                this.nextLeft = function (index) {
                    var range = union(this.range(index));
                    return axis.nextVisible(range.bottomRight[field]);
                };
                this.prevRight = function (index) {
                    var range = union(this.range(index));
                    return axis.prevVisible(range.topLeft[field]);
                };
            },
            boundary: function (top, bottom) {
                this.top = top;
                this.bottom = bottom;
            },
            range: function (index) {
                return this.rangeGetter(index, this.top, this.bottom);
            }
        });
        var SheetNavigator = kendo.Class.extend({
            init: function (sheet) {
                this._sheet = sheet;
                this.columns = this._sheet._grid._columns;
                this.autoFillCalculator = new kendo.spreadsheet.AutoFillCalculator(sheet._grid);
                this.colEdge = new EdgeNavigator('col', this._sheet._grid._columns, this.columnRange.bind(this), this.union.bind(this));
                this.rowEdge = new EdgeNavigator('row', this._sheet._grid._rows, this.rowRange.bind(this), this.union.bind(this));
            },
            height: function (height) {
                this._viewPortHeight = height;
            },
            union: function (ref) {
                return this._sheet.unionWithMerged(ref);
            },
            columnRange: function (col, topRow, bottomRow) {
                return this._sheet._ref(topRow, col, bottomRow - topRow, 1);
            },
            rowRange: function (row, leftCol, rightCol) {
                return this._sheet._ref(row, leftCol, 1, rightCol - leftCol);
            },
            selectionIncludesMergedCells: function () {
                return this._sheet.select().contains(this._sheet._mergedCells);
            },
            setSelectionValue: function (value) {
                var selection = this._sheet.selection();
                setTimeout(function () {
                    selection.value(value());
                });
            },
            selectAll: function () {
                this._sheet.select(this._sheet._sheetRef);
            },
            select: function (ref, mode, addToExisting) {
                ref = this.refForMode(ref, mode);
                if (addToExisting) {
                    ref = this._sheet.select().concat(ref);
                }
                this._sheet.select(ref);
            },
            refForMode: function (ref, mode) {
                var grid = this._sheet._grid;
                switch (mode) {
                case 'range':
                    ref = grid.normalize(ref);
                    break;
                case 'row':
                    ref = grid.rowRef(ref.row);
                    break;
                case 'column':
                    ref = grid.colRef(ref.col);
                    break;
                case 'sheet':
                    ref = this._sheet._sheetRef;
                    break;
                }
                return ref;
            },
            startSelection: function (ref, mode, addToExisting, shiftKey) {
                if (mode == 'autofill') {
                    this._sheet.startAutoFill();
                } else if (shiftKey && mode == 'range') {
                    var range = new RangeRef(this._sheet.activeCell().first(), ref);
                    this._sheet.select(range, false, false);
                    this._sheet.startSelection();
                } else {
                    this._sheet.startSelection();
                    this.select(ref, mode, addToExisting);
                }
            },
            completeSelection: function () {
                this._sheet.completeSelection();
            },
            selectForContextMenu: function (ref, mode) {
                var sheet = this._sheet;
                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));
                });
            },
            preventAddRow: function () {
                var range = this._sheet.select().toRangeRef();
                var rowCount = range.height();
                return this._sheet.preventInsertRow(0, rowCount);
            },
            preventAddColumn: function () {
                var range = this._sheet.select().toRangeRef();
                var columnCount = range.width();
                return this._sheet.preventInsertColumn(0, columnCount);
            },
            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._content = {};
                this._externalContent = {};
                this._internalContent = {};
                this.workbook = workbook;
                this.origin = kendo.spreadsheet.NULLREF;
                this.iframe = document.createElement('iframe');
                this.iframe.className = 'k-spreadsheet-clipboard-paste';
                this.menuInvoked = true;
                this._uid = kendo.guid();
                document.body.appendChild(this.iframe);
            },
            destroy: function () {
                document.body.removeChild(this.iframe);
            },
            canCopy: function () {
                var status = { canCopy: true };
                var selection = this.workbook.activeSheet().select();
                if (selection === kendo.spreadsheet.NULLREF) {
                    status.canCopy = false;
                }
                if (selection instanceof kendo.spreadsheet.UnionRef) {
                    status.canCopy = false;
                    status.multiSelection = true;
                }
                if (this.menuInvoked) {
                    status.canCopy = false;
                    status.menuInvoked = true;
                }
                return status;
            },
            canPaste: function () {
                var sheet = this.workbook.activeSheet();
                var ref = this.pasteRef();
                var range = sheet.range(ref);
                var status = {
                    canPaste: true,
                    pasteOnMerged: false,
                    pasteOnDisabled: false
                };
                if (!range.enable()) {
                    status.canPaste = false;
                    status.pasteOnDisabled = true;
                }
                if (!ref.eq(sheet.unionWithMerged(ref))) {
                    status.canPaste = false;
                    status.pasteOnMerged = true;
                }
                if (this.menuInvoked) {
                    status.canPaste = false;
                    status.menuInvoked = true;
                }
                if (ref.bottomRight.row >= sheet._rows._count || ref.bottomRight.col >= sheet._columns._count) {
                    status.canPaste = false;
                    status.overflow = true;
                }
                return status;
            },
            intersectsMerged: function () {
                var sheet = this.workbook.activeSheet();
                this.parse();
                this.origin = this._content.origRef;
                var ref = this.pasteRef();
                return !ref.eq(sheet.unionWithMerged(ref));
            },
            copy: function () {
                var sheet = this.workbook.activeSheet();
                this.origin = sheet.select();
                this._internalContent = sheet.selection().getState();
                delete this._externalContent.html;
                delete this._externalContent.plain;
            },
            cut: function () {
                var sheet = this.workbook.activeSheet();
                this.copy();
                sheet.range(sheet.select()).clear();
            },
            pasteRef: function () {
                var sheet = this.workbook.activeSheet();
                var destination = sheet.activeCell().first();
                var originActiveCell = this.origin.first();
                var rowDelta = originActiveCell.row - destination.row;
                var colDelta = originActiveCell.col - destination.col;
                return this.origin.relative(rowDelta, colDelta, 3);
            },
            paste: function () {
                var sheet = this.workbook.activeSheet();
                var pasteRef = this.pasteRef();
                sheet.range(pasteRef).setState(this._content, this);
                sheet.triggerChange({
                    recalc: true,
                    ref: pasteRef
                });
            },
            external: function (data) {
                if (data && (data.html || data.plain)) {
                    this._externalContent = data;
                } else {
                    return this._externalContent;
                }
            },
            isExternal: function () {
                return !this._isInternal();
            },
            parse: function () {
                var state = newState();
                if (this._isInternal()) {
                    state = this._internalContent;
                } else {
                    var data = this._externalContent;
                    if (data.html) {
                        var doc = this.iframe.contentWindow.document;
                        doc.open();
                        doc.write(data.html);
                        doc.close();
                        var table = $(doc).find('table:first');
                        if (table.length) {
                            state = parseHTML(table);
                        } else {
                            state = parseTSV(data.plain);
                        }
                    } else {
                        state = parseTSV(data.plain);
                    }
                    this.origin = state.origRef;
                }
                this._content = state;
            },
            _isInternal: function () {
                if (this._externalContent.html === undefined) {
                    return true;
                }
                var internalHTML = $('<div/>').html(this._externalContent.html).find('table.kendo-clipboard-' + this._uid).length ? true : false;
                var internalPlain = $('<div/>').html(this._externalContent.plain).find('table.kendo-clipboard-' + this._uid).length ? true : false;
                return internalHTML || internalPlain;
            }
        });
        kendo.spreadsheet.Clipboard = Clipboard;
        function newState() {
            var ref = new CellRef(0, 0, 0);
            return {
                ref: ref,
                mergedCells: [],
                data: [],
                foreign: true,
                origRef: ref.toRangeRef()
            };
        }
        function setStateData(state, row, col, value) {
            var data = state.data || (state.data = []);
            if (!data[row]) {
                data[row] = [];
            }
            data[row][col] = value;
            var br = state.origRef.bottomRight;
            br.row = Math.max(br.row, row);
            br.col = Math.max(br.col, col);
        }
        function stripStyle(style) {
            return style.replace(/^-(?:ms|moz|webkit)-/, '');
        }
        function borderObject(styles) {
            var obj = {};
            [
                'borderBottom',
                'borderRight',
                'borderLeft',
                'borderTop'
            ].forEach(function (key) {
                obj[key] = styles[key + 'Style'] == 'none' ? null : {
                    size: 1,
                    color: styles[key + 'Color']
                };
            });
            return obj;
        }
        function cellState(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',
            'borderTop',
            'borderRight',
            'borderBottom',
            'borderLeft'
        ];
        var Range = kendo.Class.extend({
            init: function (ref, sheet) {
                this._sheet = sheet;
                this._ref = ref;
            },
            clone: function () {
                return new Range(this._ref.clone(), this._sheet);
            },
            skipHiddenCells: function () {
                var refs = [];
                var self = this, sheet = self._sheet;
                var skipHiddenRows = sheet.isHiddenRow.bind(sheet);
                var skipHiddenCols = sheet.isHiddenColumn.bind(sheet);
                self._ref.forEach(function (ref) {
                    ref = self._normalize(ref.toRangeRef());
                    var tl = ref.topLeft, br = ref.bottomRight;
                    var rows = partition(tl.row, br.row, skipHiddenRows);
                    var cols = partition(tl.col, br.col, skipHiddenCols);
                    for (var i = 0; i < rows.length; ++i) {
                        for (var j = 0; j < cols.length; ++j) {
                            refs.push(new RangeRef(new CellRef(rows[i].begin, cols[j].begin), new CellRef(rows[i].end, cols[j].end)));
                        }
                    }
                });
                return sheet.range(refs.length > 1 ? new UnionRef(refs) : refs[0]);
            },
            _normalize: function (ref) {
                return this._sheet._grid.normalize(ref);
            },
            _set: function (name, value, noTrigger) {
                var self = this;
                var sheet = self._sheet;
                self._ref.forEach(function (ref) {
                    sheet._set(ref.toRangeRef(), name, value);
                });
                if (!noTrigger) {
                    sheet.triggerChange({
                        recalc: name == 'formula' || name == 'value' || name == 'validation',
                        value: value,
                        range: self,
                        ref: self._ref
                    });
                }
                return self;
            },
            _get: function (name) {
                return this._sheet._get(this._ref.toRangeRef(), name);
            },
            _property: function (name, value) {
                if (value === undefined) {
                    return this._get(name);
                } else {
                    return this._set(name, value);
                }
            },
            value: function (value) {
                if (value !== undefined) {
                    this._set('formula', null, true);
                }
                return this._property('value', value);
            },
            resize: function (direction) {
                var ref = this._resizedRef(direction);
                return new Range(ref, this._sheet);
            },
            _resizedRef: function (direction) {
                return this._ref.map(function (ref) {
                    return ref.toRangeRef().resize(direction);
                });
            },
            input: function (value) {
                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 != '@') {
                            var existingFormatType = existingFormat && kendo.spreadsheet.formatting.type(x.value, existingFormat);
                            if (x.type == 'date' && existingFormatType != 'date') {
                                this.format(x.format || toExcelFormat(kendo.culture().calendar.patterns.d));
                            } else if (x.type == 'percent' && existingFormatType != 'percent') {
                                this.format(x.value * 100 == (x.value * 100 | 0) ? '0%' : '0.00%');
                            } else if (x.format && !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++) {
                        if (sheet.isHiddenColumn(ci)) {
                            continue;
                        }
                        for (ri = topLeftRow; ri <= bottomRightRow; ri++) {
                            var row = props[ri - topLeftRow];
                            if (row && !sheet.isHiddenRow(ri)) {
                                data = row[ci - topLeftCol];
                                if (data) {
                                    Object.keys(data).forEach(setProp);
                                }
                            }
                        }
                    }
                    sheet.triggerChange({
                        recalc: true,
                        ref: this._ref
                    });
                    return this;
                }
            },
            clear: function (options) {
                options = options || {};
                var clearAll = options.clearAll || !Object.keys(options).length;
                var sheet = this._sheet;
                var reason = {
                    recalc: clearAll || options.contentsOnly,
                    ref: this._ref
                };
                sheet.batch(function () {
                    if (reason.recalc) {
                        this.formula(null);
                    }
                    if (clearAll) {
                        this.validation(null);
                    }
                    if (clearAll || options.formatOnly) {
                        PROPERTIES.forEach(function (x) {
                            if (!(options.keepBorders && /^border/i.test(x))) {
                                this[x](null);
                            }
                        }.bind(this));
                        this.unmerge();
                    }
                }.bind(this), reason);
                return this;
            },
            clearContent: function () {
                return this.clear({ contentsOnly: true });
            },
            clearFormat: function () {
                return this.clear({ formatOnly: true });
            },
            isSortable: function () {
                return !this.cantSort();
            },
            cantSort: function () {
                if (this._ref instanceof UnionRef) {
                    return {
                        code: 'cantSortMultipleSelection',
                        message: 'Unsupported for multiple ranges.'
                    };
                }
                if (this._ref === kendo.spreadsheet.NULLREF) {
                    return {
                        code: 'cantSortNullRef',
                        message: 'Unsupported for NULLREF.'
                    };
                }
                var mc = this._sheet._getMergedCells(this._ref.toRangeRef());
                var primary = mc.primary;
                var secondary = mc.secondary;
                var width = null, height = null;
                var cant = {};
                try {
                    this._sheet.forEach(this, function (row, col) {
                        var id = new CellRef(row, col).print();
                        var merged = primary[id];
                        if (merged) {
                            if (width === null) {
                                width = merged.width();
                                height = merged.height();
                            } else if (!(width == merged.width() && height == merged.height())) {
                                throw cant;
                            }
                        } else if (!secondary[id] && mc.hasMerged) {
                            throw cant;
                        }
                    });
                } catch (ex) {
                    if (ex !== cant) {
                        throw ex;
                    }
                    return {
                        code: 'cantSortMixedCells',
                        message: 'Unsupported for range containing cells of different shapes.'
                    };
                }
                return false;
            },
            sort: function (spec) {
                var reason = this.cantSort();
                if (reason) {
                    throw new Error(reason.message);
                }
                if (spec === undefined) {
                    spec = { column: 0 };
                }
                spec = spec instanceof Array ? spec : [spec];
                this._sheet._sortBy(this._ref.toRangeRef(), spec.map(function (spec, index) {
                    if (typeof spec === 'number') {
                        spec = { column: spec };
                    }
                    return {
                        index: spec.column === undefined ? index : spec.column,
                        ascending: spec.ascending === undefined ? true : spec.ascending
                    };
                }));
                return this;
            },
            isFilterable: function () {
                return !(this._ref instanceof UnionRef);
            },
            filter: function (spec) {
                if (this._ref instanceof UnionRef) {
                    throw new Error('Unsupported for multiple ranges.');
                }
                if (spec === false) {
                    this.clearFilters();
                } else {
                    spec = spec === true ? [] : spec instanceof Array ? spec : [spec];
                    this._sheet._filterBy(this._ref.toRangeRef(), spec.map(function (spec, index) {
                        return {
                            index: spec.column === undefined ? index : spec.column,
                            filter: spec.filter
                        };
                    }));
                }
                return this;
            },
            clearFilter: function (spec) {
                this._sheet.clearFilter(spec);
            },
            clearFilters: function () {
                var filter = this._sheet.filter();
                var spec = [];
                if (filter) {
                    for (var i = 0; i < filter.columns.length; i++) {
                        spec.push(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;
                    var hasFilter = this.hasFilter();
                    state.data.forEach(function (data, dr) {
                        if (hasFilter && clipboard && !clipboard.isExternal() && sheet.isHiddenRow(state.ref.row + dr)) {
                            return;
                        }
                        var col = origin.col;
                        data.forEach(function (cellState, dc) {
                            if (hasFilter && 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 yesItHas = {};
                var defStyle = this._sheet._defaultCellStyle;
                try {
                    this.forEachCell(function (row, col, cell) {
                        for (var key in cell) {
                            var val = cell[key];
                            if (val !== undefined && val !== null && val !== defStyle[key]) {
                                throw yesItHas;
                            }
                        }
                    });
                } catch (ex) {
                    if (ex === yesItHas) {
                        return true;
                    } else {
                        throw ex;
                    }
                }
                return false;
            },
            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);
            },
            insideBorders: function (value) {
                return this.insideVerticalBorders(value).insideHorizontalBorders(value);
            },
            insideVerticalBorders: function (value) {
                this._ref.forEach(function (ref) {
                    if (ref instanceof RangeRef && ref.width() > 1) {
                        ref = ref.clone();
                        ref.topLeft.col++;
                        this._sheet.range(ref)._set('vBorders', value);
                    }
                }, this);
                return this;
            },
            insideHorizontalBorders: function (value) {
                this._ref.forEach(function (ref) {
                    if (ref instanceof RangeRef && ref.height() > 1) {
                        ref = ref.clone();
                        ref.topLeft.row++;
                        this._sheet.range(ref)._set('hBorders', value);
                    }
                }, this);
                return this;
            }
        });
        function partition(begin, end, predicate) {
            while (begin <= end && predicate(begin)) {
                begin++;
            }
            if (begin > end) {
                return [];
            }
            for (var i = begin + 1; i <= end; ++i) {
                if (predicate(i)) {
                    return [{
                            begin: begin,
                            end: i - 1
                        }].concat(partition(i + 1, end, predicate));
                }
            }
            return [{
                    begin: begin,
                    end: end
                }];
        }
        $.each(PROPERTIES, function (i, property) {
            Range.prototype[property] = function (value) {
                return this._property(property, value);
            };
        });
        function toExcelFormat(format) {
            return format.replace(/M/g, 'm').replace(/'/g, '"').replace(/tt/, 'am/pm');
        }
        function looksLikeANumber(str) {
            return !/^=/.test(str) && /number|percent/.test(kendo.spreadsheet.calc.parse(null, 0, 0, str).type);
        }
        var measureBox = $('<div style="position: absolute !important; top: -4000px !important; height: auto !important;' + 'padding: 1px !important; margin: 0 !important; border: 1px solid black !important;' + 'line-height: normal !important; visibility: hidden !important;' + 'white-space: pre-wrap; word-break: break-all;" />')[0];
        function getTextHeight(text, width, fontSize, wrap) {
            var styles = {
                'baselineMarkerSize': 0,
                'width': wrap === true ? width + 'px' : 'auto',
                '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);
                var level = 0;
                while (parentContext) {
                    if (parentContext.formula === this) {
                        this.pending = false;
                        ctx.resolve(new CalcError('CIRCULAR'));
                        return;
                    }
                    parentContext = parentContext.parent;
                    ++level;
                }
                if (this.pending) {
                    return;
                }
                this.pending = true;
                var next = function () {
                    if (!this.absrefs) {
                        this.absrefs = this.refs.map(function (ref) {
                            return ref.absolute(this.row, this.col);
                        }, this);
                    }
                    this.handler.call(ctx);
                }.bind(this);
                if (level < 20) {
                    next();
                } else {
                    setTimeout(next, 0);
                }
            }
        },
        reset: function () {
            this.onReady = [];
            this.pending = false;
            delete this.value;
        },
        renameSheet: function (oldSheetName, newSheetName) {
            oldSheetName = oldSheetName.toLowerCase();
            this.absrefs = null;
            if (this.sheet.toLowerCase() == oldSheetName) {
                this.sheet = newSheetName;
            }
            this.refs.forEach(function (ref) {
                ref.renameSheet(oldSheetName, newSheetName);
            });
        },
        adjust: function (affectedSheet, operation, start, delta) {
            affectedSheet = affectedSheet.toLowerCase();
            var formulaRow = this.row;
            var formulaCol = this.col;
            var formulaSheet = this.sheet.toLowerCase();
            var formulaMoves = false;
            if (formulaSheet == affectedSheet) {
                if (operation == 'row' && formulaRow >= start) {
                    this.row += delta;
                    formulaMoves = true;
                }
                if (operation == 'col' && formulaCol >= start) {
                    this.col += delta;
                    formulaMoves = true;
                }
            }
            var newFormulaRow = this.row;
            var newFormulaCol = this.col;
            this.absrefs = null;
            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) {
        var integer = Math.floor(num);
        var decimal = num - integer;
        return integer + Math.round(decimal * 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) {
        if (typeof m == 'string') {
            m = this.asMatrix([m.split(/\s*,\s*/)]);
        }
        return m;
    }).args([[
            'm',
            [
                'or',
                'matrix',
                'string'
            ]
        ]]);
    function compileValidation(sheet, row, col, validation) {
        var validationHandler;
        var comparer;
        var parsedFromDate;
        var parsedToDate;
        if (typeof validation === 'string') {
            validation = JSON.parse(validation);
        }
        if (validation.from) {
            if (validation.dataType === 'list' && !validation.fromIsListValue) {
                validation.from = kendo.format(TRANSPOSE_FORMAT, validation.from);
                validation.fromIsListValue = true;
            }
            if (validation.dataType === 'date') {
                parsedFromDate = calc.runtime.parseDate(validation.from);
                if (parsedFromDate) {
                    validation.from = kendo.format(DATE_FORMAT, validation.from);
                    validation.fromIsDateValue = true;
                }
            }
            validation.from = calc.compile(calc.parseFormula(sheet, row, col, validation.from));
        }
        if (validation.to) {
            if (validation.dataType === 'date') {
                parsedToDate = calc.runtime.parseDate(validation.to);
                if (parsedToDate) {
                    validation.to = kendo.format(DATE_FORMAT, validation.to);
                    validation.toIsDateValue = true;
                }
            }
            validation.to = calc.compile(calc.parseFormula(sheet, row, col, validation.to));
        }
        if (validation.dataType == 'custom') {
            comparer = exports.validationComparers.custom;
        } else if (validation.dataType == 'list') {
            comparer = exports.validationComparers.list;
        } else {
            comparer = exports.validationComparers[validation.comparerType];
        }
        if (!comparer) {
            throw kendo.format('\'{0}\' comparer is not implemented.', validation.comparerType);
        }
        validationHandler = function (valueToCompare) {
            var toValue = this.to && this.to_value ? this.to_value : 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._sheet.triggerSelect(new Range(ref, this._sheet));
                    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);
            },
            events: [
                'commandRequest',
                'afterInsertRow',
                'afterDeleteRow',
                'insertRow',
                'insertColumn',
                'deleteRow',
                'deleteColumn',
                'hideRow',
                'hideColumn',
                'unhideRow',
                'unhideColumn',
                'select'
            ],
            _reinit: function (rowCount, columnCount, rowHeight, columnWidth, headerHeight, headerWidth, defaultCellStyle) {
                defaultCellStyle = defaultCellStyle || {};
                this._defaultCellStyle = {
                    background: defaultCellStyle.background,
                    color: defaultCellStyle.color,
                    fontFamily: defaultCellStyle.fontFamily,
                    fontSize: defaultCellStyle.fontSize,
                    italic: defaultCellStyle.italic,
                    bold: defaultCellStyle.bold,
                    underline: defaultCellStyle.underline,
                    wrap: defaultCellStyle.wrap
                };
                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(rowCount, columnCount, this._defaultCellStyle);
                this._sorter = new kendo.spreadsheet.Sorter(this._grid, this._properties.sortable());
                this._viewSelection = new Selection(this);
                this._editSelection = new Selection(this);
                this._formulaSelections = [];
            },
            _selectionState: function () {
                return this._inEdit ? this._editSelection : this._viewSelection;
            },
            navigator: function () {
                if (!this._navigator) {
                    this._navigator = new kendo.spreadsheet.SheetNavigator(this);
                }
                return this._navigator;
            },
            axisManager: function () {
                if (!this._axisManager) {
                    this._axisManager = new kendo.spreadsheet.AxisManager(this);
                }
                return this._axisManager;
            },
            _name: function (value) {
                if (!value) {
                    return this._sheetName;
                }
                this._sheetName = value;
                return this;
            },
            name: function () {
                return this._name();
            },
            _property: function (accessor, value, reason) {
                if (value === undefined) {
                    return accessor();
                } else {
                    accessor(value);
                    return this.triggerChange(reason);
                }
            },
            _field: function (name, value, reason) {
                if (value === undefined) {
                    return this[name];
                } else {
                    this[name] = value;
                    return this.triggerChange(reason);
                }
            },
            suspendChanges: function (value) {
                if (value === undefined) {
                    return this._suspendChanges;
                }
                this._suspendChanges = value;
                return this;
            },
            triggerChange: function (reason) {
                if (!this._suspendChanges) {
                    this.trigger('change', reason);
                }
                return this;
            },
            triggerSelect: function (range) {
                this.trigger('select', { range: range });
            },
            setDataSource: function (dataSource, columns) {
                if (this.dataSourceBinder) {
                    this.dataSourceBinder.destroy();
                }
                this.dataSourceBinder = new kendo.spreadsheet.SheetDataSourceBinder({
                    dataSource: dataSource,
                    sheet: this,
                    columns: columns
                });
                this.dataSource = this.dataSourceBinder.dataSource;
            },
            hideColumn: function (columnIndex) {
                if (this.trigger('hideColumn', { index: columnIndex })) {
                    return;
                }
                return this._property(this._columns.hide.bind(this._columns), columnIndex, { layout: true });
            },
            unhideColumn: function (columnIndex) {
                if (this.trigger('unhideColumn', { index: columnIndex })) {
                    return;
                }
                return this._property(this._columns.unhide.bind(this._columns), columnIndex, { layout: true });
            },
            isHiddenColumn: function (columnIndex) {
                return this._grid._columns.hidden(columnIndex);
            },
            _copyRange: function (sourceRangeRef, targetRef) {
                var grid = this._grid;
                var rowCount = grid.rowCount;
                var nextRefTopLeft = grid.normalize(sourceRangeRef.topLeft);
                var nextRefBottomRight = grid.normalize(sourceRangeRef.bottomRight);
                var nextIndex = nextRefTopLeft.col * rowCount + nextRefTopLeft.row;
                var nextBottomIndex = nextRefBottomRight.col * rowCount + nextRefBottomRight.row;
                var targetIndex = targetRef.col * rowCount + targetRef.row;
                this._properties.copy(nextIndex, nextBottomIndex, targetIndex);
            },
            _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);
            },
            preventInsertRow: function (rowIndex, count) {
                if (this.selectedHeaders().allRows) {
                    return {
                        reason: 'error',
                        type: 'insertRowWhenColumnIsSelected'
                    };
                }
                count = count || 1;
                var grid = this._grid;
                var range = this.range(grid.rowCount - count, 0, count, grid.columnCount);
                if (range.hasValue()) {
                    return {
                        reason: 'error',
                        type: 'shiftingNonblankCells'
                    };
                }
                return false;
            },
            preventInsertColumn: function (colIndex, count) {
                if (this.selectedHeaders().allCols) {
                    return {
                        reason: 'error',
                        type: 'insertColumnWhenRowIsSelected'
                    };
                }
                count = count || 1;
                var grid = this._grid;
                var range = this.range(0, grid.columnCount - count, grid.rowCount, count);
                if (range.hasValue()) {
                    return {
                        reason: 'error',
                        type: 'shiftingNonblankCells'
                    };
                }
                return false;
            },
            insertRow: function (rowIndex) {
                var result = this.preventInsertRow(rowIndex);
                if (result) {
                    throw new Error('Shifting nonblank cells off the worksheet is not supported!');
                }
                if (this.trigger('insertRow', { index: rowIndex })) {
                    return;
                }
                this.batch(function () {
                    var grid = this._grid;
                    var columnCount = grid.columnCount;
                    var rowCount = grid.rowCount;
                    var frozenRows = this.frozenRows();
                    if (rowIndex < frozenRows) {
                        this.frozenRows(frozenRows + 1);
                    }
                    var mergedCells = this._mergedCells.slice();
                    for (var ci = 0; ci < columnCount; ci++) {
                        var ref = new RangeRef(new CellRef(rowIndex, ci), new CellRef(rowIndex, ci));
                        var topLeft = grid.normalize(ref.topLeft);
                        var bottomRight = grid.normalize(ref.bottomRight);
                        var nextRef = new RangeRef(new CellRef(topLeft.row, topLeft.col), new CellRef(rowCount - 2, bottomRight.col));
                        this._copyRange(nextRef, new CellRef(topLeft.row + 1, topLeft.col));
                        new Range(ref, this).clear({
                            clearAll: true,
                            keepBorders: true
                        });
                    }
                    this._adjustReferences('row', rowIndex, 1, mergedCells);
                }, {
                    recalc: true,
                    layout: true,
                    insertRow: { index: rowIndex },
                    ref: new RangeRef(new CellRef(rowIndex, 0), new CellRef(Infinity, Infinity))
                });
                this.trigger('afterInsertRow', { index: rowIndex });
                return this;
            },
            isEnabledRow: function (rowIndex) {
                var ref = new RangeRef(new CellRef(rowIndex, 0), new CellRef(rowIndex, this._grid.columnCount));
                return new Range(ref, this).enable();
            },
            deleteRow: function (rowIndex) {
                if (!this.isEnabledRow(rowIndex)) {
                    return this;
                }
                if (this.trigger('deleteRow', { index: rowIndex })) {
                    return;
                }
                this.batch(function () {
                    var grid = this._grid;
                    var columnCount = grid.columnCount;
                    var frozenRows = this.frozenRows();
                    if (rowIndex < frozenRows) {
                        this.frozenRows(frozenRows - 1);
                    }
                    var mergedCells = this._mergedCells.slice();
                    for (var ci = 0; ci < columnCount; ci++) {
                        var ref = new RangeRef(new CellRef(rowIndex, ci), new CellRef(rowIndex, ci));
                        new Range(ref, this).clear({
                            clearAll: true,
                            keepBorders: true
                        });
                        var topLeft = grid.normalize(ref.topLeft);
                        var bottomRight = grid.normalize(ref.bottomRight);
                        var nextRef = new RangeRef(new CellRef(topLeft.row + 1, topLeft.col), new CellRef(Infinity, bottomRight.col));
                        this._copyRange(nextRef, topLeft);
                        var nextRefBottomRight = grid.normalize(nextRef.bottomRight);
                        new Range(new RangeRef(nextRefBottomRight, nextRefBottomRight), this).clear();
                    }
                    this._adjustReferences('row', rowIndex, -1, mergedCells);
                }, {
                    recalc: true,
                    layout: true,
                    deleteRow: { index: rowIndex },
                    ref: new RangeRef(new CellRef(rowIndex, 0), new CellRef(Infinity, Infinity))
                });
                this.trigger('afterDeleteRow', { index: rowIndex });
                return this;
            },
            insertColumn: function (columnIndex) {
                if (this.trigger('insertColumn', { index: columnIndex })) {
                    return;
                }
                this.batch(function () {
                    var grid = this._grid;
                    var columnCount = grid.columnCount;
                    var frozenColumns = this.frozenColumns();
                    if (columnIndex < frozenColumns) {
                        this.frozenColumns(frozenColumns + 1);
                    }
                    var mergedCells = this._mergedCells.slice();
                    for (var ci = columnCount; ci >= columnIndex; ci--) {
                        var ref = new RangeRef(new CellRef(0, ci), new CellRef(Infinity, ci));
                        new Range(ref, this).clear({
                            clearAll: true,
                            keepBorders: true
                        });
                        if (ci == columnIndex) {
                            break;
                        }
                        var topLeft = grid.normalize(ref.topLeft);
                        var bottomRight = grid.normalize(ref.bottomRight);
                        var nextRef = new RangeRef(new CellRef(topLeft.row, topLeft.col - 1), new CellRef(bottomRight.row, bottomRight.col - 1));
                        this._copyRange(nextRef, topLeft);
                    }
                    this._adjustReferences('col', columnIndex, 1, mergedCells);
                }, {
                    recalc: true,
                    layout: true,
                    insertColumn: { index: columnIndex },
                    ref: new RangeRef(new CellRef(0, columnIndex), new CellRef(Infinity, Infinity))
                });
                return this;
            },
            isEnabledColumn: function (columnIndex) {
                var ref = new RangeRef(new CellRef(0, columnIndex), new CellRef(Infinity, columnIndex));
                return new Range(ref, this).enable();
            },
            deleteColumn: function (columnIndex) {
                if (!this.isEnabledColumn(columnIndex)) {
                    return this;
                }
                if (this.trigger('deleteColumn', { index: columnIndex })) {
                    return;
                }
                this.batch(function () {
                    var grid = this._grid;
                    var columnCount = grid.columnCount;
                    var frozenColumns = this.frozenColumns();
                    if (columnIndex < frozenColumns) {
                        this.frozenColumns(frozenColumns - 1);
                    }
                    var mergedCells = this._mergedCells.slice();
                    for (var ci = columnIndex; ci < columnCount; ci++) {
                        var ref = new RangeRef(new CellRef(0, ci), new CellRef(Infinity, ci));
                        new Range(ref, this).clear({
                            clearAll: true,
                            keepBorders: true
                        });
                        if (ci == columnCount - 1) {
                            break;
                        }
                        var topLeft = grid.normalize(ref.topLeft);
                        var bottomRight = grid.normalize(ref.bottomRight);
                        var nextRef = new RangeRef(new CellRef(topLeft.row, topLeft.col + 1), new CellRef(bottomRight.row, bottomRight.col + 1));
                        this._copyRange(nextRef, topLeft);
                    }
                    this._adjustReferences('col', columnIndex, -1, mergedCells);
                }, {
                    recalc: true,
                    layout: true,
                    deleteColumn: { index: columnIndex },
                    ref: new RangeRef(new CellRef(0, columnIndex), new CellRef(Infinity, Infinity))
                });
                return this;
            },
            hideRow: function (rowIndex) {
                if (this.trigger('hideRow', { index: rowIndex })) {
                    return;
                }
                return this._property(this._rows.hide.bind(this._rows), rowIndex, { layout: true });
            },
            unhideRow: function (rowIndex) {
                if (this.trigger('unhideRow', { index: rowIndex })) {
                    return;
                }
                return this._property(this._rows.unhide.bind(this._rows), rowIndex, { layout: true });
            },
            isHiddenRow: function (rowIndex) {
                return this._grid._rows.hidden(rowIndex);
            },
            columnWidth: function (columnIndex, width) {
                return this._property(this._columns.value.bind(this._columns, columnIndex, columnIndex), width, { layout: true });
            },
            rowHeight: function (rowIndex, height) {
                return this._property(this._rows.value.bind(this._rows, rowIndex, rowIndex), height, { layout: true });
            },
            frozenRows: function (value) {
                return this._field('_frozenRows', value, { layout: true });
            },
            frozenColumns: function (value) {
                return this._field('_frozenColumns', value, { layout: true });
            },
            showGridLines: function (value) {
                return this._field('_showGridLines', value, { layout: true });
            },
            gridLinesColor: function (value) {
                return this._field('_gridLinesColor', value, { layout: true });
            },
            _ref: function (row, column, numRows, numColumns) {
                var ref = null;
                if (row instanceof kendo.spreadsheet.Ref) {
                    return row;
                }
                if (row instanceof kendo.spreadsheet.Range) {
                    return row._ref.toRangeRef();
                }
                if (typeof row === 'string') {
                    ref = kendo.spreadsheet.calc.parseReference(row);
                } else {
                    if (!numRows) {
                        numRows = 1;
                    }
                    if (!numColumns) {
                        numColumns = 1;
                    }
                    ref = new RangeRef(new CellRef(row, column), new CellRef(row + numRows - 1, column + numColumns - 1));
                }
                return ref;
            },
            range: function (row, column, numRows, numColumns) {
                return new Range(this._ref(row, column, numRows, numColumns), this);
            },
            _getMergedCells: function (range) {
                var grid = this._grid;
                var primary = {};
                var secondary = {};
                var hasMerged = false;
                this.forEachMergedCell(range, function (ref) {
                    var topLeft = ref.topLeft;
                    grid.forEach(ref, function (cellRef) {
                        if (topLeft.eq(cellRef)) {
                            primary[cellRef.print()] = ref;
                            hasMerged = true;
                        } else if (range.contains(cellRef)) {
                            secondary[cellRef.print()] = topLeft;
                            hasMerged = true;
                        }
                    });
                });
                return {
                    primary: primary,
                    secondary: secondary,
                    hasMerged: hasMerged
                };
            },
            forEachMergedCell: function (ref, callback) {
                var selectAll = false;
                if (typeof callback === 'undefined') {
                    callback = ref;
                    selectAll = true;
                }
                this._mergedCells.forEach(function (merged) {
                    if (selectAll || merged.intersects(ref)) {
                        callback(merged);
                    }
                });
            },
            forEachFilterHeader: function (ref, callback) {
                var selectAll = false;
                if (typeof callback === 'undefined') {
                    callback = ref;
                    selectAll = true;
                }
                if (this._filter) {
                    var refs = [];
                    this._filter.ref.forEachColumn(function (columnRef) {
                        if (selectAll || columnRef.intersects(ref)) {
                            refs.push(columnRef.topLeft);
                        }
                    });
                    this._mergedCells.forEach(function (merged) {
                        refs = refs.map(function (ref) {
                            if (merged.intersects(ref)) {
                                return merged;
                            }
                            return ref;
                        });
                    });
                    refs.reduce(function unique(result, element) {
                        if (result.indexOf(element) < 0) {
                            result.push(element);
                        }
                        return result;
                    }, []).forEach(callback);
                }
            },
            forEach: function (ref, callback) {
                if (!(ref instanceof RangeRef)) {
                    ref = this._ref(ref);
                }
                var topLeft = this._grid.normalize(ref.topLeft);
                var bottomRight = this._grid.normalize(ref.bottomRight);
                function doIt(value) {
                    callback(ri++, ci, value);
                }
                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, doIt);
                }
            },
            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 topLeft = ref.topLeft;
                    var rowSelection = topLeft.col <= 0 && bottomRight.col >= maxCol;
                    var colSelection = topLeft.row <= 0 && bottomRight.row >= maxRow;
                    if (colSelection) {
                        allRows = true;
                        colState = 'full';
                    }
                    if (rowSelection) {
                        allCols = true;
                        rowState = 'full';
                    }
                    if (!colSelection) {
                        for (i = topLeft.row; i <= bottomRight.row; i++) {
                            if (rows[i] !== 'full') {
                                rows[i] = rowState;
                            }
                        }
                    }
                    if (!rowSelection) {
                        for (i = topLeft.col; i <= bottomRight.col; i++) {
                            if (cols[i] !== 'full') {
                                cols[i] = colState;
                            }
                        }
                    }
                });
                return {
                    rows: rows,
                    cols: cols,
                    allRows: allRows,
                    allCols: allCols,
                    all: allRows && allCols
                };
            },
            isInEditMode: function (isInEdit) {
                if (isInEdit === undefined) {
                    return this._inEdit;
                }
                this._inEdit = isInEdit;
                if (isInEdit) {
                    this._editSelection.selection = this._viewSelection.selection.clone();
                    this._editSelection.originalSelection = this._viewSelection.originalSelection.clone();
                    this._editSelection._activeCell = this._viewSelection._activeCell.clone();
                    this._editSelection.originalActiveCell = this._viewSelection.originalActiveCell.clone();
                }
            },
            _setFormulaSelections: function (selection) {
                this._formulaSelections = (selection || []).slice();
                this.triggerChange({ selection: true });
            },
            _viewActiveCell: function () {
                return this._viewSelection._activeCell.toRangeRef();
            },
            toJSON: function () {
                var positions = {};
                var rows = this._rows.toJSON('height', positions);
                var columns = this._columns.toJSON('width', {});
                var viewSelection = this._viewSelection;
                var hyperlinks = [];
                var defaultCellStyle = this._defaultCellStyle || {};
                function clearDefaultStyle(cell) {
                    Object.keys(defaultCellStyle).forEach(function (key) {
                        if (cell[key] === defaultCellStyle[key]) {
                            delete cell[key];
                        }
                    });
                }
                this.forEach(kendo.spreadsheet.SHEETREF, function (row, col, cell) {
                    clearDefaultStyle(cell);
                    if (Object.keys(cell).length === 0) {
                        return;
                    }
                    if (cell.link) {
                        hyperlinks.push({
                            ref: kendo.spreadsheet.Ref.display(null, row, col),
                            target: cell.link
                        });
                    }
                    var position = positions[row];
                    if (position === undefined) {
                        position = rows.length;
                        rows.push({ index: row });
                        positions[row] = position;
                    }
                    row = rows[position];
                    cell.index = col;
                    if (row.cells === undefined) {
                        row.cells = [];
                    }
                    if (cell.formula) {
                        cell.formula = cell.formula.toString();
                    }
                    if (cell.validation) {
                        cell.validation = cell.validation.toJSON();
                    }
                    if (cell.color) {
                        cell.color = kendo.parseColor(cell.color).toCss();
                    }
                    if (cell.background) {
                        cell.background = kendo.parseColor(cell.background).toCss();
                    }
                    if (cell.borderTop && cell.borderTop.color) {
                        cell.borderTop.color = kendo.parseColor(cell.borderTop.color).toCss();
                    }
                    if (cell.borderBottom && cell.borderBottom.color) {
                        cell.borderBottom.color = kendo.parseColor(cell.borderBottom.color).toCss();
                    }
                    if (cell.borderRight && cell.borderRight.color) {
                        cell.borderRight.color = kendo.parseColor(cell.borderRight.color).toCss();
                    }
                    if (cell.borderLeft && cell.borderLeft.color) {
                        cell.borderLeft.color = kendo.parseColor(cell.borderLeft.color).toCss();
                    }
                    row.cells.push(cell);
                });
                var json = {
                    name: this._name(),
                    rows: rows,
                    columns: columns,
                    selection: viewSelection.selection.toString(),
                    activeCell: viewSelection.activeCell().toString(),
                    frozenRows: this.frozenRows(),
                    frozenColumns: this.frozenColumns(),
                    showGridLines: this.showGridLines(),
                    gridLinesColor: this.gridLinesColor(),
                    mergedCells: this._mergedCells.map(function (ref) {
                        return ref.toString();
                    }),
                    hyperlinks: hyperlinks,
                    defaultCellStyle: defaultCellStyle
                };
                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-icon',
            sheetsBarKButton: 'k-button k-button-icon',
            sheetsBarKButtonBare: 'k-bare',
            sheetsBarKArrowW: 'k-i-arrow-60-left',
            sheetsBarKArrowE: 'k-i-arrow-60-right',
            sheetsBarKReset: 'k-reset k-tabstrip-items',
            sheetsBarKIconX: 'k-i-close',
            sheetsBarKSprite: 'k-sprite',
            sheetsBarKIconPlus: 'k-i-plus',
            sheetsBarHintWrapper: 'k-widget k-tabstrip k-tabstrip-bottom k-spreadsheet-sheets-items-hint',
            sheetsBarKResetItems: 'k-reset k-tabstrip-items'
        };
        var SheetsBar = kendo.ui.Widget.extend({
            init: function (element, options) {
                var classNames = SheetsBar.classNames;
                kendo.ui.Widget.call(this, element, options);
                element = this.element;
                element.addClass(classNames.sheetsBarWrapper);
                this._openDialog = options.openDialog;
                this._tree = new kendo.dom.Tree(element[0]);
                this._tree.render([
                    this._addButton(),
                    this._createSheetsWrapper([])
                ]);
                this._toggleScrollEvents(true);
                this._createSortable();
                this._sortable.bind('start', this._onSheetReorderStart.bind(this));
                this._sortable.bind('end', this._onSheetReorderEnd.bind(this));
                element.on('click', DOT + classNames.sheetsBarRemove, this._onSheetRemove.bind(this));
                element.on('click', 'li', this._onSheetSelect.bind(this));
                element.on('dblclick', 'li' + DOT + classNames.sheetsBarActive, this._createEditor.bind(this));
                element.on('click', DOT + classNames.sheetsBarAdd, this._onAddSelect.bind(this));
            },
            options: {
                name: 'SheetsBar',
                scrollable: { distance: 200 }
            },
            events: [
                'select',
                'reorder',
                'rename'
            ],
            _createEditor: function () {
                if (this._editor) {
                    return;
                }
                this._renderSheets(this._sheets, this._selectedIndex, true);
                this._editor = this.element.find(kendo.format('input{0}{1}', DOT, SheetsBar.classNames.sheetsBarEditor)).focus().on('keydown', this._onEditorKeydown.bind(this)).on('blur', this._onEditorBlur.bind(this));
            },
            _destroyEditor: function (canceled) {
                var newSheetName = canceled ? null : this._editor.val();
                this._editor.off();
                this._editor = null;
                this._renderSheets(this._sheets, this._selectedIndex, false);
                this._onSheetRename(newSheetName);
            },
            renderSheets: function (sheets, selectedIndex) {
                if (!sheets || selectedIndex < 0) {
                    return;
                }
                this._renderSheets(sheets, selectedIndex, false);
            },
            _renderSheets: function (sheets, selectedIndex, isInEditMode) {
                var that = this;
                var wrapperOffsetWidth;
                var sheetsGroupScrollWidth;
                var classNames = SheetsBar.classNames;
                that._isRtl = kendo.support.isRtl(that.element);
                that._sheets = sheets;
                that._selectedIndex = selectedIndex;
                that._renderHtml(isInEditMode, true);
                if (!that._scrollableAllowed()) {
                    return;
                }
                var sheetsWrapper = that._sheetsWrapper();
                var scrollPrevButton = sheetsWrapper.children(DOT + classNames.sheetsBarPrev);
                var scrollNextButton = sheetsWrapper.children(DOT + classNames.sheetsBarNext);
                var gapWidth = 2;
                var addButton = that.element.find(DOT + classNames.sheetsBarAdd);
                var addButtonWidth = outerWidth(addButton) + addButton.position().left + gapWidth;
                var scrollPrevButtonWidth = outerWidth(scrollPrevButton) + gapWidth;
                var sheetsGroup = that._sheetsGroup();
                scrollPrevButton.css({ left: addButtonWidth });
                sheetsWrapper.addClass(classNames.sheetsBarScrollable + EMPTYCHAR + classNames.sheetsBarSheetsWrapper);
                sheetsGroup.css({ marginLeft: addButtonWidth });
                wrapperOffsetWidth = sheetsWrapper[0].offsetWidth;
                sheetsGroupScrollWidth = sheetsGroup[0].scrollWidth;
                if (sheetsGroupScrollWidth + addButtonWidth > wrapperOffsetWidth) {
                    var scrollNextButtonRight = Math.ceil(kendo.parseFloat(scrollNextButton.css('right')));
                    if (!that._scrollableModeActive) {
                        that._nowScrollingSheets = false;
                        that._scrollableModeActive = true;
                    }
                    sheetsGroup.css({
                        marginLeft: scrollPrevButtonWidth + addButtonWidth,
                        marginRight: outerWidth(scrollNextButton) + scrollNextButtonRight + gapWidth
                    });
                } else {
                    if (that._scrollableModeActive && sheetsGroupScrollWidth <= wrapperOffsetWidth) {
                        that._scrollableModeActive = false;
                        sheetsGroup.css({
                            marginLeft: addButtonWidth,
                            marginRight: ''
                        });
                    } else {
                        sheetsGroup.css({ marginLeft: addButtonWidth });
                    }
                }
                that._toggleScrollButtons();
            },
            _toggleScrollButtons: function (toggle) {
                var that = this;
                var ul = that._sheetsGroup();
                var wrapper = that._sheetsWrapper();
                var scrollLeft = ul.scrollLeft();
                var prev = wrapper.find(DOT + SheetsBar.classNames.sheetsBarPrev);
                var next = wrapper.find(DOT + SheetsBar.classNames.sheetsBarNext);
                if (toggle === false) {
                    prev.toggle(false);
                    next.toggle(false);
                } else {
                    prev.toggle(that._isRtl ? scrollLeft < ul[0].scrollWidth - ul[0].offsetWidth - 1 : scrollLeft !== 0);
                    next.toggle(that._isRtl ? scrollLeft !== 0 : scrollLeft < ul[0].scrollWidth - ul[0].offsetWidth - 1);
                }
            },
            _toggleScrollEvents: function (toggle) {
                var that = this;
                var classNames = SheetsBar.classNames;
                var options = that.options;
                var scrollPrevButton;
                var scrollNextButton;
                var sheetsWrapper = that._sheetsWrapper();
                scrollPrevButton = sheetsWrapper.children(DOT + classNames.sheetsBarPrev);
                scrollNextButton = sheetsWrapper.children(DOT + classNames.sheetsBarNext);
                if (toggle) {
                    scrollPrevButton.on('mousedown', function () {
                        that._nowScrollingSheets = true;
                        that._scrollSheetsByDelta(options.scrollable.distance * (that._isRtl ? 1 : -1));
                    });
                    scrollNextButton.on('mousedown', function () {
                        that._nowScrollingSheets = true;
                        that._scrollSheetsByDelta(options.scrollable.distance * (that._isRtl ? -1 : 1));
                    });
                    scrollPrevButton.add(scrollNextButton).on('mouseup', function () {
                        that._nowScrollingSheets = false;
                    });
                } else {
                    scrollPrevButton.off();
                    scrollNextButton.off();
                }
            },
            _renderHtml: function (isInEditMode, renderScrollButtons) {
                var idx;
                var sheetElements = [];
                var dom = kendo.dom;
                var element = dom.element;
                var sheets = this._sheets;
                var selectedIndex = this._selectedIndex;
                var classNames = SheetsBar.classNames;
                for (idx = 0; idx < sheets.length; idx++) {
                    var sheet = sheets[idx];
                    var isSelectedSheet = idx === selectedIndex;
                    var attr = { className: classNames.sheetsBarKItem + EMPTYCHAR };
                    var elementContent = [];
                    if (isSelectedSheet) {
                        attr.className += classNames.sheetsBarKActive + EMPTYCHAR + classNames.sheetsBarActive;
                    } else {
                        attr.className += classNames.sheetsBarInactive;
                    }
                    if (isSelectedSheet && isInEditMode) {
                        elementContent.push(element('input', {
                            type: 'text',
                            value: sheet.name(),
                            className: classNames.sheetsBarKTextbox + EMPTYCHAR + classNames.sheetsBarEditor,
                            maxlength: 50
                        }, []));
                    } else {
                        elementContent.push(element('span', {
                            className: classNames.sheetsBarKLink,
                            title: sheet.name()
                        }, [dom.text(sheet.name())]));
                        if (sheets.length > 1) {
                            var deleteIcon = element('span', { className: classNames.sheetsBarKIcon + EMPTYCHAR + classNames.sheetsBarKFontIcon + EMPTYCHAR + classNames.sheetsBarKIconX }, []);
                            elementContent.push(element('span', { className: classNames.sheetsBarKLink + EMPTYCHAR + classNames.sheetsBarRemove }, [deleteIcon]));
                        }
                    }
                    sheetElements.push(element('li', attr, elementContent));
                }
                this._tree.render([
                    this._addButton(),
                    this._createSheetsWrapper(sheetElements, renderScrollButtons)
                ]);
            },
            _createSheetsWrapper: function (sheetElements, renderScrollButtons) {
                var element = kendo.dom.element;
                var classNames = SheetsBar.classNames;
                var childrenElements = [element('ul', { className: classNames.sheetsBarKReset }, sheetElements)];
                renderScrollButtons = true;
                if (renderScrollButtons) {
                    var baseButtonClass = classNames.sheetsBarKButton + EMPTYCHAR + classNames.sheetsBarKButtonBare + EMPTYCHAR;
                    childrenElements.push(element('span', { className: baseButtonClass + classNames.sheetsBarPrev }, [element('span', { className: classNames.sheetsBarKIcon + EMPTYCHAR + classNames.sheetsBarKArrowW }, [])]));
                    childrenElements.push(element('span', { className: baseButtonClass + classNames.sheetsBarNext }, [element('span', { className: classNames.sheetsBarKIcon + EMPTYCHAR + classNames.sheetsBarKArrowE }, [])]));
                }
                return element('div', { className: classNames.sheetsBarItems }, childrenElements);
            },
            _createSortable: function () {
                var classNames = SheetsBar.classNames;
                this._sortable = new kendo.ui.Sortable(this.element, {
                    filter: kendo.format('ul li.{0},ul li.{1}', classNames.sheetsBarActive, classNames.sheetsBarInactive),
                    container: DOT + classNames.sheetsBarItems,
                    axis: 'x',
                    animation: false,
                    ignore: 'input',
                    end: function () {
                        if (this.draggable.hint) {
                            this.draggable.hint.remove();
                        }
                    },
                    hint: function (element) {
                        var hint = $(element).clone();
                        return hint.wrap('<div class=\'' + classNames.sheetsBarHintWrapper + '\'><ul class=\'' + classNames.sheetsBarKResetItems + '\'></ul></div>').closest('div');
                    }
                });
            },
            _onEditorKeydown: function (e) {
                if (this._editor) {
                    if (e.which === 13) {
                        this._destroyEditor();
                    }
                    if (e.which === 27) {
                        this._destroyEditor(true);
                    }
                }
            },
            _onEditorBlur: function () {
                if (this._editor) {
                    this._destroyEditor();
                }
            },
            _onSheetReorderEnd: function (e) {
                e.preventDefault();
                this.trigger('reorder', {
                    oldIndex: e.oldIndex,
                    newIndex: e.newIndex
                });
            },
            _onSheetReorderStart: function (e) {
                if (this._editor) {
                    e.preventDefault();
                }
            },
            _onSheetRemove: function (e) {
                var removedSheetName = $(e.target).closest('li').text();
                if (this._editor) {
                    this._destroyEditor();
                }
                var closeCallback = function (e) {
                    var dlg = e.sender;
                    if (dlg.isConfirmed()) {
                        this.trigger('remove', {
                            name: removedSheetName,
                            confirmation: true
                        });
                    }
                }.bind(this);
                this._openDialog('confirmation', { close: closeCallback });
            },
            _onSheetSelect: function (e) {
                var selectedSheetText = $(e.target).text();
                if ($(e.target).is(DOT + SheetsBar.classNames.sheetsBarEditor) || !selectedSheetText) {
                    e.preventDefault();
                    return;
                }
                if (this._editor) {
                    this._destroyEditor();
                }
                this._scrollSheetsToItem($(e.target).closest('li'));
                this.trigger('select', {
                    name: selectedSheetText,
                    isAddButton: false
                });
            },
            _onSheetRename: function (newSheetName) {
                if (this._sheets[this._selectedIndex].name() === newSheetName || newSheetName === null) {
                    return;
                }
                this.trigger('rename', {
                    name: newSheetName,
                    sheetIndex: this._selectedIndex
                });
            },
            _onAddSelect: function () {
                this.trigger('select', { isAddButton: true });
            },
            _addButton: function () {
                var element = kendo.dom.element;
                var classNames = SheetsBar.classNames;
                return element('a', { className: classNames.sheetsBarAdd + EMPTYCHAR + classNames.sheetsBarKButton }, [element('span', { className: classNames.sheetsBarKIcon + EMPTYCHAR + classNames.sheetsBarKFontIcon + EMPTYCHAR + classNames.sheetsBarKIconPlus }, [])]);
            },
            destroy: function () {
                this._sortable.destroy();
            },
            _scrollableAllowed: function () {
                var options = this.options;
                return options.scrollable && !isNaN(options.scrollable.distance);
            },
            _scrollSheetsToItem: function (item) {
                var that = this;
                if (!that._scrollableModeActive) {
                    return;
                }
                var sheetsGroup = that._sheetsGroup();
                var currentScrollOffset = sheetsGroup.scrollLeft();
                var itemWidth = outerWidth(item);
                var itemOffset = that._isRtl ? item.position().left : item.position().left - sheetsGroup.children().first().position().left;
                var sheetsGroupWidth = sheetsGroup[0].offsetWidth;
                var sheetsGroupPadding = Math.ceil(parseFloat(sheetsGroup.css('padding-left')));
                var itemPosition;
                if (that._isRtl) {
                    if (itemOffset < 0) {
                        itemPosition = currentScrollOffset + itemOffset - (sheetsGroupWidth - currentScrollOffset) - sheetsGroupPadding;
                    } else if (itemOffset + itemWidth > sheetsGroupWidth) {
                        itemPosition = currentScrollOffset + itemOffset - itemWidth + sheetsGroupPadding * 2;
                    }
                } else {
                    if (currentScrollOffset + sheetsGroupWidth < itemOffset + itemWidth) {
                        itemPosition = itemOffset + itemWidth - sheetsGroupWidth + sheetsGroupPadding * 2;
                    } else if (currentScrollOffset > itemOffset) {
                        itemPosition = itemOffset - sheetsGroupPadding;
                    }
                }
                sheetsGroup.finish().animate({ 'scrollLeft': itemPosition }, 'fast', 'linear', function () {
                    that._toggleScrollButtons();
                });
            },
            _sheetsGroup: function () {
                return this._sheetsWrapper().children('ul');
            },
            _sheetsWrapper: function () {
                return this.element.find(DOT + SheetsBar.classNames.sheetsBarItems);
            },
            _scrollSheetsByDelta: function (delta) {
                var that = this;
                var sheetsGroup = that._sheetsGroup();
                var scrLeft = sheetsGroup.scrollLeft();
                sheetsGroup.finish().animate({ 'scrollLeft': scrLeft + delta }, 'fast', 'linear', function () {
                    if (that._nowScrollingSheets) {
                        that._scrollSheetsByDelta(delta);
                    } else {
                        that._toggleScrollButtons();
                    }
                });
            }
        });
        kendo.spreadsheet.SheetsBar = SheetsBar;
        $.extend(true, SheetsBar, { classNames: sheetsBarClassNames });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/calc', ['spreadsheet/runtime'], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var util = kendo.util;
    var spreadsheet = kendo.spreadsheet;
    var Ref = spreadsheet.Ref;
    var RangeRef = spreadsheet.RangeRef;
    var CellRef = spreadsheet.CellRef;
    var NameRef = spreadsheet.NameRef;
    var exports = spreadsheet.calc;
    var runtime = exports.runtime;
    var OPERATORS = 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 if (is('punc', '[')) {
                input.croak('External reference not supported');
            } else {
                input.croak('Parse error');
            }
            return maybePercent(exp);
        }
        function parseArray() {
            var row = [], value = [row], first = true;
            while (!input.eof() && !is('punc', '}')) {
                if (first) {
                    first = false;
                } else if (is('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 == 'prefix' && prec == OPERATORS[op] && parent.op == '-' || parent.type == 'binary' && prec == OPERATORS[op] && node === parent.right;
                return parenthesize(f(), needParens);
            }
        }
        function parenthesize(code, cond) {
            return cond ? '\'(\' + ' + code + ' + \')\'' : code;
        }
    }
    function toCPS(ast, k) {
        var GENSYM = 0;
        return cps(ast, k);
        function cps(node, k) {
            switch (node.type) {
            case 'ref':
                return cpsRef(node, k);
            case 'num':
            case 'str':
            case 'null':
            case 'error':
            case 'bool':
                return cpsAtom(node, k);
            case 'prefix':
            case 'postfix':
                return cpsUnary(node, k);
            case 'binary':
                return cpsBinary(node, k);
            case 'func':
                return cpsFunc(node, k);
            case 'lambda':
                return cpsLambda(node, k);
            case 'matrix':
                return cpsMatrix(node.value, k, true);
            }
            throw new Error('Cannot CPS ' + node.type);
        }
        function cpsRef(node, k) {
            return node.ref == 'name' ? cpsNameRef(node, k) : cpsAtom(node, k);
        }
        function cpsAtom(node, k) {
            return k(node);
        }
        function cpsNameRef(node, k) {
            return {
                type: 'func',
                func: ',getname',
                args: [
                    makeContinuation(k),
                    node
                ]
            };
        }
        function cpsUnary(node, k) {
            return cps({
                type: 'func',
                func: 'unary' + node.op,
                args: [node.exp]
            }, k);
        }
        function cpsBinary(node, k) {
            return cps({
                type: 'func',
                func: 'binary' + node.op,
                args: [
                    node.left,
                    node.right
                ]
            }, k);
        }
        function cpsIf(co, th, el, k) {
            return cps(co, function (co) {
                var rest = makeContinuation(k);
                var thenK = gensym('T');
                var elseK = gensym('E');
                return {
                    type: 'func',
                    func: 'if',
                    args: [
                        rest,
                        co,
                        {
                            type: 'lambda',
                            vars: [thenK],
                            body: cps(th || TRUE, function (th) {
                                return {
                                    type: 'call',
                                    func: {
                                        type: 'var',
                                        name: thenK
                                    },
                                    args: [th]
                                };
                            })
                        },
                        {
                            type: 'lambda',
                            vars: [elseK],
                            body: cps(el || FALSE, function (el) {
                                return {
                                    type: 'call',
                                    func: {
                                        type: 'var',
                                        name: elseK
                                    },
                                    args: [el]
                                };
                            })
                        }
                    ]
                };
            });
        }
        function cpsAnd(args, k) {
            if (args.length === 0) {
                return cpsAtom(TRUE, k);
            }
            return cps({
                type: 'func',
                func: 'IF',
                args: [
                    args[0],
                    {
                        type: 'func',
                        func: 'AND',
                        args: args.slice(1)
                    },
                    FALSE
                ]
            }, k);
        }
        function cpsOr(args, k) {
            if (args.length === 0) {
                return cpsAtom(FALSE, k);
            }
            return cps({
                type: 'func',
                func: 'IF',
                args: [
                    args[0],
                    TRUE,
                    {
                        type: 'func',
                        func: 'OR',
                        args: args.slice(1)
                    }
                ]
            }, k);
        }
        function cpsFunc(node, k) {
            switch (node.func.toLowerCase()) {
            case 'if':
                return cpsIf(node.args[0], node.args[1], node.args[2], k);
            case 'and':
                return cpsAnd(node.args, k);
            case 'or':
                return cpsOr(node.args, k);
            case 'true':
                return k(TRUE);
            case 'false':
                return k(FALSE);
            }
            return function loop(args, i) {
                if (i == node.args.length) {
                    return {
                        type: 'func',
                        func: node.func,
                        args: args
                    };
                } else {
                    return cps(node.args[i], function (value) {
                        return loop(args.concat([value]), i + 1);
                    });
                }
            }([makeContinuation(k)], 0);
        }
        function cpsLambda(node, k) {
            var cont = gensym('K');
            var body = cps(node.body, function (body) {
                return {
                    type: 'call',
                    func: {
                        type: 'var',
                        value: cont
                    },
                    args: [body]
                };
            });
            return k({
                type: 'lambda',
                vars: [cont].concat(node.vars),
                body: body
            });
        }
        function cpsMatrix(elements, k, isMatrix) {
            var a = [];
            return function loop(i) {
                if (i == elements.length) {
                    return k({
                        type: 'matrix',
                        value: a
                    });
                } else {
                    return (isMatrix ? cpsMatrix : cps)(elements[i], function (val) {
                        a[i] = val;
                        return loop(i + 1);
                    });
                }
            }(0);
        }
        function makeContinuation(k) {
            var cont = gensym('R');
            return {
                type: 'lambda',
                vars: [cont],
                body: k({
                    type: 'var',
                    name: cont
                })
            };
        }
        function gensym(name) {
            if (!name) {
                name = '';
            }
            name = '_' + name;
            return name + ++GENSYM;
        }
    }
    var 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) || util.isUnicodeLetter(ch);
        }
        function isId(ch) {
            return isIdStart(ch) || isDigit(ch) || ch == '.';
        }
        function isOpChar(ch) {
            return ch in OPERATORS;
        }
        function isPunc(ch) {
            return '!;(){}[]'.indexOf(ch) >= 0;
        }
        function readNumber() {
            var has_dot = false;
            var number = readWhile(function (ch) {
                if (ch == '.') {
                    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 null;
            }
            if (!a && !c || a && c) {
                var num = b ? parseInt(b, 10) : 0;
                return a ? num : num - 1;
            }
        }
        function readSymbol() {
            var m = input.lookingAt(/^R(\[)?(-?[0-9]+)?(\])?C(\[)?(-?[0-9]+)?(\])?/i);
            if (m) {
                var row = getRC(m[1], m[2], m[3]);
                var col = getRC(m[4], m[5], m[6]);
                if (row != null && col != null) {
                    input.skip(m);
                    return {
                        type: 'rc',
                        row: row,
                        col: col,
                        rel: (m[4] || !(m[4] || m[5] || m[6]) ? 1 : 0) | (m[1] || !(m[1] || m[2] || m[3]) ? 2 : 0)
                    };
                }
            }
            return symbol(readWhile(isId));
        }
        function readString() {
            input.next();
            return {
                type: 'str',
                value: input.readEscaped('"')
            };
        }
        function readSheetName() {
            input.next();
            return symbol(input.readEscaped('\''), true);
        }
        function readOperator() {
            return {
                type: 'op',
                value: readWhile(function (ch, op) {
                    return op + ch in OPERATORS;
                })
            };
        }
        function readPunc() {
            return {
                type: 'punc',
                value: input.next()
            };
        }
        function readNext() {
            if (input.eof()) {
                return null;
            }
            var ch = input.peek(), m;
            if (ch == '"') {
                return readString();
            }
            if (ch == '\'') {
                return readSheetName();
            }
            if (isDigit(ch) || ch == '.') {
                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;
        }
    }
    function parseSqref(input, row, col) {
        row = row || 0;
        col = col || 0;
        input = TokenStream(input, {
            row: row,
            col: col
        });
        var refs = [];
        while (!input.eof()) {
            var ref = input.next();
            if (ref.type != 'ref') {
                throw new ParseError('Expecting a reference but got: ' + JSON.stringify(ref));
            }
            refs.push(ref.absolute(row, col));
        }
        return refs;
    }
    exports.parseNameDefinition = parseNameDefinition;
    exports.parseFormula = parseFormula;
    exports.parseReference = parseReference;
    exports.compile = makeFormula;
    exports.parseSqref = parseSqref;
    exports.InputStream = InputStream;
    exports.ParseError = ParseError;
    exports.tokenize = tokenize;
    registerFormatParser(function (input) {
        var m;
        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;
    var MAP_EXCEL_OPERATOR = {
        greaterThanOrEqual: 'greaterThanOrEqualTo',
        lessThanOrEqual: 'lessThanOrEqualTo'
    };
    var ERROR_LOG = null;
    function readExcel(file, workbook, deferred) {
        var reader = new FileReader();
        reader.onload = function (e) {
            var zip = new JSZip(e.target.result);
            readWorkbook(zip, workbook, deferred);
        };
        reader.readAsArrayBuffer(file);
    }
    var SEL_CELL = [
        'sheetData',
        'row',
        'c'
    ];
    var SEL_COL = [
        'cols',
        'col'
    ];
    var SEL_DEFINED_NAME = [
        'definedNames',
        'definedName'
    ];
    var SEL_FORMULA = [
        'sheetData',
        'row',
        'c',
        'f'
    ];
    var SEL_MERGE = [
        'mergeCells',
        'mergeCell'
    ];
    var SEL_PANE = [
        'sheetViews',
        'sheetView',
        'pane'
    ];
    var SEL_ROW = [
        'sheetData',
        'row'
    ];
    var SEL_SELECTION = [
        'sheetViews',
        'sheetView',
        'selection'
    ];
    var SEL_SHEET = [
        'sheets',
        'sheet'
    ];
    var SEL_STRING = [
        'sheetData',
        'row',
        'c',
        'is'
    ];
    var SEL_TEXT = ['t'];
    var SEL_SHARED_STRING = ['si'];
    var SEL_VALUE = [
        'sheetData',
        'row',
        'c',
        'v'
    ];
    var SEL_VIEW = [
        'bookViews',
        'workbookView'
    ];
    var SEL_SHEET_VIEW = [
        'sheetViews',
        'sheetView'
    ];
    var SEL_HYPERLINK = [
        'hyperlinks',
        'hyperlink'
    ];
    var SEL_VALIDATION = [
        'dataValidations',
        'dataValidation'
    ];
    var SEL_VALIDATION_FORMULA1 = [
        'dataValidations',
        'dataValidation',
        'formula1'
    ];
    var SEL_VALIDATION_FORMULA2 = [
        'dataValidations',
        'dataValidation',
        'formula2'
    ];
    function xl(file) {
        if (!/^\//.test(file)) {
            file = 'xl/' + file;
        } else {
            file = file.substr(1);
        }
        return file;
    }
    function readWorkbook(zip, workbook, progress) {
        ERROR_LOG = workbook.excelImportErrors = [];
        var strings = readStrings(zip);
        var relationships = readRelationships(zip, '_rels/workbook.xml');
        var theme = readTheme(zip, relationships.byType.theme[0]);
        var styles = readStyles(zip, theme);
        var items = [];
        var activeSheet = 0;
        parse(zip, 'xl/workbook.xml', {
            enter: function (tag, attrs) {
                if (this.is(SEL_SHEET)) {
                    var relId = attrs['r:id'];
                    var file = relationships.byId[relId];
                    var name = attrs.name;
                    var dim = sheetDimensions(zip, file);
                    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;
                    }
                    withErrorLog(sheet, null, function () {
                        workbook.defineName(name, text, bool(attrs.hidden));
                    }, 'reading user-defined name: ' + name);
                }
            }
        });
        var loading = new $.Deferred();
        loading.progress(function (args) {
            if (progress) {
                progress.notify(args);
            }
        }).then(function () {
            var sheets = workbook.sheets();
            recalcSheets(sheets);
            workbook.activeSheet(sheets[activeSheet]);
            if (progress) {
                progress.resolve();
            }
        });
        loadSheets(items, workbook, loading);
    }
    function loadSheets(items, workbook, progress) {
        var ready = new $.Deferred().resolve();
        for (var i = 0; i < items.length; i++) {
            (function (entry, i) {
                ready = ready.then(function () {
                    var sheet = workbook.insertSheet(entry.options);
                    sheet.suspendChanges(true);
                    var promise = queueSheet(sheet, entry);
                    var args = {
                        sheet: sheet,
                        progress: i / (items.length - 1)
                    };
                    promise.then(function () {
                        progress.notify(args);
                    });
                    return promise;
                });
            }(items[i], i));
        }
        ready.then(function () {
            progress.resolve();
        });
    }
    function queueSheet(sheet, ctx) {
        var deferred = new $.Deferred();
        setTimeout(function () {
            readSheet(ctx.zip, ctx.file, sheet, ctx.strings, ctx.styles);
            deferred.resolve();
        }, 0);
        return deferred;
    }
    function recalcSheets(sheets) {
        for (var i = 0; i < sheets.length; i++) {
            sheets[i].suspendChanges(false).triggerChange({ recalc: true });
        }
    }
    function sheetDimensions(zip, file) {
        var dim = {
            rows: 0,
            cols: 0
        };
        parse(zip, xl(file), {
            enter: function (tag, attrs) {
                if (tag == 'dimension') {
                    var ref = parseReference(attrs.ref);
                    if (ref.bottomRight) {
                        dim.cols = ref.bottomRight.col + 1;
                        dim.rows = ref.bottomRight.row + 1;
                    }
                } else if (tag === 'sheetFormatPr') {
                    if (attrs.defaultColWidth) {
                        dim.columnWidth = toColWidth(parseFloat(attrs.defaultColWidth));
                    }
                    if (attrs.defaultRowHeight) {
                        dim.rowHeight = toRowHeight(parseFloat(attrs.defaultRowHeight));
                    }
                } else if (this.is(SEL_ROW)) {
                    this.exit();
                }
            }
        });
        return dim;
    }
    function toColWidth(size) {
        var maximumDigitWidth = 7;
        var fraction = (256 * size + Math.floor(128 / maximumDigitWidth)) / 256;
        return 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);
        var formula1, formula2;
        var filterRef;
        var filterColumn;
        var customFilterLogic;
        var customFilterCriteria;
        var valueFilterBlanks;
        var valueFilterValues;
        var filters = [];
        ERROR_LOG = sheet._workbook.excelImportErrors;
        parse(zip, xl(file), {
            enter: function (tag, attrs) {
                var tmp;
                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);
                        }
                    }
                    if (attrs.style != null) {
                        applyStyle(sheet, new kendo.spreadsheet.RangeRef(new kendo.spreadsheet.CellRef(-Infinity, start), new kendo.spreadsheet.CellRef(+Infinity, stop)), styles, attrs.style);
                    }
                } else if (this.is(SEL_ROW)) {
                    var row = integer(attrs.r) - 1;
                    var height;
                    if (attrs.ht) {
                        height = toRowHeight(parseFloat(attrs.ht));
                        if (height !== 0) {
                            sheet._rows.values.value(row, row, height);
                        }
                    }
                    if (attrs.hidden === '1' || height === 0) {
                        sheet.hideRow(row);
                    }
                } else if (this.is(SEL_SELECTION)) {
                    if (attrs.activeCell) {
                        var acRef = parseReference(attrs.activeCell);
                        sheet.select(acRef, true);
                    }
                } else if (this.is(SEL_PANE)) {
                    if (attrs.state == 'frozen') {
                        if (attrs.xSplit) {
                            sheet.frozenColumns(integer(attrs.xSplit));
                        }
                        if (attrs.ySplit) {
                            sheet.frozenRows(integer(attrs.ySplit));
                        }
                    }
                } else if (this.is(SEL_SHEET_VIEW)) {
                    sheet.showGridLines(bool(attrs.showGridLines, true));
                } else if (this.is(SEL_HYPERLINK)) {
                    var relId = attrs['r:id'];
                    var target = relationships.byId[relId];
                    if (target) {
                        sheet.range(attrs.ref).link(target);
                    }
                } else if (this.is(['autoFilter'])) {
                    filterRef = attrs.ref;
                } else if (filterRef) {
                    if (this.is(['filterColumn'])) {
                        filterColumn = parseInt(attrs.colId, 10);
                    } else if (this.is(['customFilters'])) {
                        customFilterLogic = bool(attrs.and) ? 'and' : 'or';
                        customFilterCriteria = [];
                    } else if (this.is(['customFilter'])) {
                        tmp = getCustomFilter(attrs.operator, attrs.val);
                        if (tmp) {
                            customFilterCriteria.push({
                                operator: tmp.operator,
                                value: tmp.value
                            });
                        }
                    } else if (this.is(['dynamicFilter'])) {
                        filters.push({
                            column: filterColumn,
                            filter: new kendo.spreadsheet.DynamicFilter({ type: dynamicFilterType(attrs.type) })
                        });
                    } else if (this.is(['top10'])) {
                        filters.push({
                            column: filterColumn,
                            filter: new kendo.spreadsheet.TopFilter({
                                value: getFilterVal(attrs.val),
                                type: function (percent, top) {
                                    return percent && top ? 'topPercent' : top ? 'topNumber' : percent ? 'bottomPercent' : 'bottomNumber';
                                }(bool(attrs.percent), bool(attrs.top))
                            })
                        });
                    } else if (this.is(['filters'])) {
                        valueFilterBlanks = bool(attrs.blank);
                        valueFilterValues = [];
                    } else if (this.is(['filter'])) {
                        valueFilterValues.push(getFilterVal(attrs.val));
                    }
                }
            },
            leave: function (tag, attrs) {
                if (this.is(SEL_CELL)) {
                    if (formula != null) {
                        var failed = withErrorLog(sheet, formulaRange || ref, function () {
                            sheet.range(formulaRange || ref).formula(formula);
                        }, 'parsing formula');
                        if (failed) {
                            sheet.range(formulaRange || ref).value(formula).background('#ffaaaa');
                        }
                    } else if (value != null) {
                        var range = sheet.range(ref);
                        if (!range._get('formula')) {
                            if (!type || type == 'n') {
                                value = parseFloat(value);
                            } else if (type == 's') {
                                value = strings[integer(value)];
                            } else if (type == 'b') {
                                value = value === '1';
                            } else if (type == 'd') {
                                value = kendo.parseDate(value);
                            }
                            if (value != null) {
                                range.value(value);
                            }
                        }
                    }
                } else if (this.is(SEL_VALIDATION)) {
                    (function () {
                        var refs = kendo.spreadsheet.calc.parseSqref(attrs.sqref);
                        var type = attrs.type.toLowerCase();
                        var operator = attrs.operator;
                        if (/^(?:whole|decimal)$/.test(type)) {
                            type = 'number';
                        } else if (type == 'list') {
                            operator = 'list';
                        }
                        if (!operator && /^(?:number|date)$/.test(type)) {
                            operator = 'between';
                        }
                        refs.forEach(function (ref) {
                            withErrorLog(sheet, ref, function () {
                                sheet.range(ref).validation({
                                    type: bool(attrs.showErrorMessage, true) ? 'reject' : 'warning',
                                    from: formula1,
                                    to: formula2,
                                    dataType: type,
                                    comparerType: MAP_EXCEL_OPERATOR[operator] || operator,
                                    allowNulls: bool(attrs.allowBlank),
                                    showButton: bool(attrs.showDropDown) || type == 'date' || type == 'list',
                                    messageTemplate: attrs.error,
                                    titleTemplate: attrs.errorTitle
                                });
                            }, 'parsing validation');
                        });
                    }());
                } else if (tag == 'cols') {
                    sheet._columns._refresh();
                } else if (tag == 'sheetData') {
                    sheet._rows._refresh();
                } else if (tag == 'autoFilter') {
                    sheet.range(filterRef).filter(filters);
                    filterRef = null;
                } else if (filterRef) {
                    if (tag == 'customFilters') {
                        filters.push({
                            column: filterColumn,
                            filter: new kendo.spreadsheet.CustomFilter({
                                logic: customFilterLogic,
                                criteria: customFilterCriteria
                            })
                        });
                    } else if (tag == 'filters') {
                        filters.push({
                            column: filterColumn,
                            filter: new kendo.spreadsheet.ValueFilter({
                                values: valueFilterValues,
                                blanks: valueFilterBlanks
                            })
                        });
                    }
                }
            },
            text: function (text) {
                var attrs;
                if (this.is(SEL_VALUE) || this.is(SEL_STRING)) {
                    value = text;
                } else if (attrs = this.is(SEL_FORMULA)) {
                    formula = text;
                    if (attrs.t == 'shared') {
                        formulaRange = attrs.ref;
                    }
                } else if (this.is(SEL_VALIDATION_FORMULA1)) {
                    formula1 = text;
                } else if (this.is(SEL_VALIDATION_FORMULA2)) {
                    formula2 = text;
                }
            }
        });
    }
    function getCustomFilter(op, value) {
        var ourOp = {
            equal: 'eq',
            notEqual: 'ne',
            greaterThan: 'gt',
            greaterThanOrEqual: 'gte',
            lessThan: 'lt',
            lessThanOrEqual: 'lte'
        }[op];
        value = getFilterVal(value);
        if (ourOp && typeof value == 'number') {
            return {
                operator: ourOp,
                value: value
            };
        }
        if ((op == 'notEqual' || !op) && typeof value == 'string') {
            return {
                operator: op ? 'doesnotmatch' : 'matches',
                value: value
            };
        }
    }
    function dynamicFilterType(type) {
        return {
            Q1: 'quarter1',
            Q2: 'quarter2',
            Q3: 'quarter3',
            Q4: 'quarter4',
            M1: 'january',
            M2: 'february',
            M3: 'march',
            M4: 'april',
            M5: 'may',
            M6: 'june',
            M7: 'july',
            M8: 'august',
            M9: 'september',
            M10: 'october',
            M11: 'november',
            M12: 'december'
        }[type.toUpperCase()] || type;
    }
    function getFilterVal(val) {
        var tmp = parseFloat(val);
        if (!isNaN(tmp) && tmp == val) {
            return tmp;
        }
        return val;
    }
    function withErrorLog(sheet, ref, func, context) {
        try {
            func();
            return false;
        } catch (ex) {
            var err = {
                context: context,
                error: String(ex)
            };
            if (sheet) {
                err.sheet = sheet.name();
            }
            if (ref) {
                err.location = String(ref);
            }
            ERROR_LOG.push(err);
            return true;
        }
    }
    var BORDER_WIDTHS = {
        'none': 0,
        'thin': 1,
        'medium': 2,
        'dashed': 1,
        'dotted': 1,
        'thick': 3,
        'double': 3,
        'hair': 1,
        'mediumDashed': 2,
        'dashDot': 1,
        'mediumDashDot': 2,
        'dashDotDot': 1,
        'mediumDashDotDot': 2,
        'slantDashDot': 1
    };
    var DEFAULT_FORMATS = {
        0: 'General',
        1: '0',
        2: '0.00',
        3: '#,##0',
        4: '#,##0.00',
        9: '0%',
        10: '0.00%',
        11: '0.00E+00',
        12: '# ?/?',
        13: '# ??/??',
        14: 'mm-dd-yy',
        15: 'd-mmm-yy',
        16: 'd-mmm',
        17: 'mmm-yy',
        18: 'h:mm AM/PM',
        19: 'h:mm:ss AM/PM',
        20: 'h:mm',
        21: 'h:mm:ss',
        22: 'm/d/yy h:mm',
        37: '#,##0 ;(#,##0)',
        38: '#,##0 ;[Red](#,##0)',
        39: '#,##0.00;(#,##0.00)',
        40: '#,##0.00;[Red](#,##0.00)',
        45: 'mm:ss',
        46: '[h]:mm:ss',
        47: 'mmss.0',
        48: '##0.0E+0',
        49: '@'
    };
    function applyStyle(sheet, ref, styles, styleIndex) {
        var range = sheet.range(ref);
        var xf = styles.inlineStyles[styleIndex], base, value;
        if (xf.xfId) {
            base = styles.namedStyles[xf.xfId];
        }
        if (shouldSet('applyBorder', 'borderId')) {
            setBorder(styles.borders[value]);
        }
        if (shouldSet('applyFont', 'fontId')) {
            setFont(styles.fonts[value]);
        }
        if (shouldSet('applyAlignment', 'textAlign')) {
            range.textAlign(value);
        }
        if (shouldSet('applyAlignment', 'verticalAlign')) {
            range.verticalAlign(value);
        }
        if (shouldSet('applyAlignment', '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: [
                'cut',
                'copy',
                'paste',
                'change',
                'excelImport',
                'excelExport',
                'insertSheet',
                'removeSheet',
                'selectSheet',
                'renameSheet',
                'insertRow',
                'insertColumn',
                'deleteRow',
                'deleteColumn',
                'hideRow',
                'hideColumn',
                'unhideRow',
                'unhideColumn',
                'select',
                'changeFormat'
            ],
            _sheetChange: function (e) {
                this.trigger('change', e);
            },
            _sheetInsertRow: function (e) {
                if (this.trigger('insertRow', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetInsertColumn: function (e) {
                if (this.trigger('insertColumn', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetDeleteRow: function (e) {
                if (this.trigger('deleteRow', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetDeleteColumn: function (e) {
                if (this.trigger('deleteColumn', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetHideRow: function (e) {
                if (this.trigger('hideRow', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetHideColumn: function (e) {
                if (this.trigger('hideColumn', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetUnhideRow: function (e) {
                if (this.trigger('unhideRow', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetUnhideColumn: function (e) {
                if (this.trigger('unhideColumn', {
                        sheet: e.sender,
                        index: e.index
                    })) {
                    e.preventDefault();
                }
            },
            _sheetSelect: function (e) {
                this.trigger('select', e);
            },
            _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, options.defaultCellStyle || this.options.defaultCellStyle);
                sheet._workbook = this;
                sheet._name(sheetName);
                this._bindSheetEvents(sheet);
                sheets.splice(insertIndex, 0, sheet);
                if (options.data) {
                    sheet.fromJSON(options.data);
                }
                if (options.dataSource) {
                    sheet.setDataSource(options.dataSource);
                }
                this.trigger('change', { sheetSelection: true });
                return sheet;
            },
            _bindSheetEvents: function (sheet) {
                sheet.bind('change', this._sheetChange.bind(this));
                sheet.bind('insertRow', this._sheetInsertRow.bind(this));
                sheet.bind('insertColumn', this._sheetInsertColumn.bind(this));
                sheet.bind('deleteRow', this._sheetDeleteRow.bind(this));
                sheet.bind('deleteColumn', this._sheetDeleteColumn.bind(this));
                sheet.bind('hideRow', this._sheetHideRow.bind(this));
                sheet.bind('hideColumn', this._sheetHideColumn.bind(this));
                sheet.bind('unhideRow', this._sheetUnhideRow.bind(this));
                sheet.bind('unhideColumn', this._sheetUnhideColumn.bind(this));
                sheet.bind('select', this._sheetSelect.bind(this));
                sheet.bind('commandRequest', this._sheetCommandRequest.bind(this));
            },
            sheets: function () {
                return this._sheets.slice();
            },
            sheetByName: function (sheetName) {
                return this._sheets[this.sheetIndex(sheetName)];
            },
            sheetByIndex: function (index) {
                return this._sheets[index];
            },
            sheetIndex: function (sheet) {
                var sheets = this._sheets;
                var sheetName = (typeof sheet == 'string' ? sheet : sheet.name()).toLowerCase();
                var idx = this._sheetsSearchCache[sheetName];
                if (idx >= 0) {
                    return idx;
                }
                for (idx = 0; idx < sheets.length; idx++) {
                    var name = sheets[idx].name().toLowerCase();
                    this._sheetsSearchCache[name] = idx;
                    if (name === sheetName) {
                        return idx;
                    }
                }
                return -1;
            },
            renameSheet: function (sheet, newSheetName) {
                var oldSheetName = sheet.name().toLowerCase();
                if (!newSheetName || oldSheetName === newSheetName.toLowerCase() || this.sheetByName(newSheetName)) {
                    return;
                }
                sheet = this.sheetByName(oldSheetName);
                if (!sheet) {
                    return;
                }
                this._sheetsSearchCache = {};
                if (this.trigger('renameSheet', {
                        sheet: sheet,
                        newSheetName: newSheetName
                    })) {
                    return;
                }
                this._sheets.forEach(function (sheet) {
                    sheet._forFormulas(function (formula) {
                        formula.renameSheet(oldSheetName, newSheetName);
                    });
                });
                this.forEachName(function (def, name) {
                    if (def.nameref.renameSheet(oldSheetName, newSheetName)) {
                        this.undefineName(name);
                        def.name = def.nameref.print();
                        this.nameDefinition(def.name, def);
                    }
                    if (def.value instanceof Ref || def.value instanceof Formula) {
                        def.value.renameSheet(oldSheetName, newSheetName);
                    }
                }.bind(this));
                sheet._name(newSheetName);
                this.trigger('change', { sheetSelection: true });
                return sheet;
            },
            removeSheet: function (sheet) {
                var that = this;
                var sheets = that._sheets;
                var name = sheet.name();
                var index = that.sheetIndex(sheet);
                if (sheets.length === 1) {
                    return;
                }
                if (this.trigger('removeSheet', { sheet: sheet })) {
                    return;
                }
                this._sheetsSearchCache = {};
                if (index > -1) {
                    sheet.unbind();
                    sheets.splice(index, 1);
                    if (that.activeSheet().name() === name) {
                        var newSheet = sheets[index === sheets.length ? index - 1 : index];
                        that.activeSheet(newSheet);
                    } else {
                        this.trigger('change', {
                            recalc: true,
                            sheetSelection: true
                        });
                    }
                }
            },
            _clearSheets: function () {
                for (var i = 0; i < this._sheets.length; i++) {
                    this._sheets[i].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,
                    columnWidth: this.options.columnWidth,
                    rowHeight: this.options.rowHeight
                };
            },
            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) {
                    this._preventNavigation = true;
                    if (result.reason === 'error') {
                        this.view.showError(result, function () {
                            this.activateEditor();
                            this.editor.value(this._lastEditorValue);
                            this.editor._value = this._workbook._inputForRef(this._workbook.activeSheet()._viewActiveCell());
                            this.editor.select();
                        }.bind(this));
                    } else {
                        this.view.openDialog(result.reason);
                    }
                }
                return result;
            },
            _activeTooltip: function () {
                return this._workbook.activeSheet().activeCell().simplify().toString();
            },
            onContextMenuSelect: function (e) {
                var action = $(e.item).data('action');
                var command;
                switch (action) {
                case 'cut':
                    command = {
                        command: 'ToolbarCutCommand',
                        options: { workbook: this._workbook }
                    };
                    break;
                case 'copy':
                    command = {
                        command: 'ToolbarCopyCommand',
                        options: { workbook: this._workbook }
                    };
                    break;
                case 'paste':
                    command = {
                        command: 'ToolbarPasteCommand',
                        options: { workbook: this._workbook }
                    };
                    break;
                case 'unmerge':
                    command = {
                        command: 'MergeCellCommand',
                        options: { value: 'unmerge' }
                    };
                    break;
                case 'merge':
                    this.view.openDialog('merge');
                    break;
                case 'hide-row':
                    command = {
                        command: 'HideLineCommand',
                        options: { axis: 'row' }
                    };
                    break;
                case 'hide-column':
                    command = {
                        command: 'HideLineCommand',
                        options: { axis: 'column' }
                    };
                    break;
                case 'unhide-row':
                    command = {
                        command: 'UnHideLineCommand',
                        options: { axis: 'row' }
                    };
                    break;
                case 'unhide-column':
                    command = {
                        command: 'UnHideLineCommand',
                        options: { axis: 'column' }
                    };
                    break;
                case 'delete-row':
                    command = { command: 'DeleteRowCommand' };
                    break;
                case 'delete-column':
                    command = { command: 'DeleteColumnCommand' };
                    break;
                }
                if (command) {
                    this._execute(command);
                }
            },
            onSheetBarRemove: function (e) {
                var sheet = this._workbook.sheetByName(e.name);
                if (!sheet) {
                    return;
                }
                this._workbook.removeSheet(sheet);
            },
            destroy: function () {
                this.listener.destroy();
                this._enableEditorEvents(false);
                this.keyListener.destroy();
                this.inputKeyListener.destroy();
            },
            onSheetBarSelect: function (e) {
                var sheet;
                var workbook = this._workbook;
                if (e.isAddButton) {
                    if (this._workbook.trigger('insertSheet')) {
                        return;
                    }
                    sheet = workbook.insertSheet();
                } else {
                    sheet = workbook.sheetByName(e.name);
                }
                if (workbook.activeSheet().name() !== sheet.name()) {
                    if (this._workbook.trigger('selectSheet', { sheet: sheet })) {
                        return;
                    }
                    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.activateEditor();
                    } 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._preventNavigation = false;
                    this.editor.deactivate();
                    if (this._preventNavigation) {
                        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 object = this.objectAt(event);
                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 = {
                    clientX: event.clientX,
                    clientY: event.clientY
                };
                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,
                        event: e.originalEvent || e
                    }
                });
            },
            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,
                                    event: e.originalEvent || e
                                }
                            });
                            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,
                        event: e.originalEvent || e
                    }
                });
            },
            onCopy: function (e) {
                this.clipboard.menuInvoked = e === undefined;
                this._execute({
                    command: 'CopyCommand',
                    options: {
                        workbook: this.view._workbook,
                        event: e.originalEvent || e
                    }
                });
            },
            scrollTop: function () {
                this.scroller.scrollTop = 0;
            },
            scrollLeft: function () {
                this.scroller.scrollLeft = 0;
            },
            scrollDown: function (value) {
                this.scroller.scrollTop += value;
            },
            scrollRight: function (value) {
                this.scroller.scrollLeft += value;
            },
            scrollWith: function (right, down) {
                this.scroller.scrollTop += down;
                this.scroller.scrollLeft += right;
            },
            objectAt: function (location) {
                var box = this.container[0].getBoundingClientRect();
                return this.view.objectAt(location.clientX - box.left, location.clientY - box.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);
                this._lastEditorValue = e.value;
                this._execute({
                    command: 'EditCommand',
                    options: {
                        editActiveCell: true,
                        value: e.value
                    }
                });
            },
            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._preventNavigation = false;
                this.editor.deactivate();
                if (!this._preventNavigation) {
                    this.clipboardElement.focus();
                    this.navigator.navigateInSelection(ENTRY_ACTIONS[action]);
                }
            },
            onEditorAction: function (event, action) {
                var editor = this.editor;
                var sheet = this._workbook.activeSheet();
                if (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()));
            },
            activateEditor: function () {
                this.editor.activate({
                    range: this._workbook.activeSheet()._viewActiveCell(),
                    rect: this.view.activeCellRectangle(),
                    tooltip: this._activeTooltip()
                }).focus();
            },
            deactivateEditor: function () {
                this.view.editor.deactivate();
            },
            onCommandRequest: function (e) {
                if (e.command) {
                    this._execute(e);
                } else {
                    this._workbook.undoRedoStack[e.action]();
                }
            },
            onDialogRequest: function (e) {
                var additionalOptions = {
                    pdfExport: this._workbook.options.pdf,
                    excelExport: this._workbook.options.excel
                };
                if (e.options) {
                    $.extend(true, e.options, additionalOptions);
                } else {
                    e.options = additionalOptions;
                }
                this.view.openDialog(e.name, e.options);
            },
            onNameEditorEnter: function () {
                var ref;
                var workbook = this._workbook;
                var sheet = workbook.activeSheet();
                var name = this.view.nameEditor.value();
                ref = kendo.spreadsheet.calc.parseReference(name, true) || workbook.nameValue(name);
                if (ref instanceof kendo.spreadsheet.Ref) {
                    if (ref.sheet && ref.sheet.toLowerCase() != sheet.name().toLowerCase()) {
                        var tmp = workbook.sheetByName(ref.sheet);
                        if (tmp) {
                            workbook.activeSheet(tmp);
                            sheet = tmp;
                        }
                    }
                    sheet.range(ref).select();
                    return;
                }
                ref = sheet.selection()._ref.clone().simplify().setSheet(sheet.name(), true);
                this._execute({
                    command: 'DefineNameCommand',
                    options: {
                        name: name,
                        value: ref
                    }
                });
                this.clipboardElement.focus();
            },
            onNameEditorCancel: function () {
                this.clipboardElement.focus();
            },
            onNameEditorSelect: function (ev) {
                var name = ev.name;
                var workbook = this._workbook;
                var sheet = workbook.activeSheet();
                var ref = workbook.nameValue(name);
                if (ref instanceof kendo.spreadsheet.Ref) {
                    if (ref.sheet && ref.sheet.toLowerCase() != sheet.name().toLowerCase()) {
                        var tmp = workbook.sheetByName(ref.sheet);
                        if (tmp) {
                            workbook.activeSheet(tmp);
                            sheet = tmp;
                        }
                    }
                    sheet.range(ref).select();
                    return;
                }
                this.clipboardElement.focus();
            },
            onNameEditorDelete: function (ev) {
                this._execute({
                    command: 'DeleteNameCommand',
                    options: { name: ev.name }
                });
                this.clipboardElement.focus();
            }
        });
        kendo.spreadsheet.Controller = Controller;
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/view', [
        'kendo.core',
        'kendo.menu',
        'spreadsheet/sheetsbar'
    ], 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',
            iconFilterDefault: 'k-i-arrow-60-down',
            sheetsBar: 'k-spreadsheet-sheets-bar',
            sheetsBarActive: 'k-spreadsheet-sheets-bar-active',
            sheetsBarInactive: 'k-spreadsheet-sheets-bar-inactive',
            cellContextMenu: 'k-spreadsheet-cell-context-menu',
            rowHeaderContextMenu: 'k-spreadsheet-row-header-context-menu',
            colHeaderContextMenu: 'k-spreadsheet-col-header-context-menu'
        };
        kendo.spreadsheet.messages.view = {
            nameBox: 'Name Box',
            errors: {
                openUnsupported: 'Unsupported format. Please select an .xlsx file.',
                shiftingNonblankCells: 'Cannot insert cells due to data loss possibility. Select another insert location or delete the data from the end of your worksheet.',
                insertColumnWhenRowIsSelected: 'Cannot insert column when all columns are selected.',
                insertRowWhenColumnIsSelected: 'Cannot insert row when all rows are selected.',
                filterRangeContainingMerges: 'Cannot create a filter within a range containing merges',
                sortRangeContainingMerges: 'Cannot sort a range containing merges',
                cantSortMultipleSelection: 'Cannot sort multiple selection',
                cantSortNullRef: 'Cannot sort empty selection',
                cantSortMixedCells: 'Cannot sort range containing cells of mixed shapes',
                validationError: 'The value that you entered violates the validation rules set on the cell.',
                cannotModifyDisabled: 'Cannot modify disabled cells.'
            },
            tabs: {
                home: 'Home',
                insert: 'Insert',
                data: 'Data'
            }
        };
        function selectElementContents(el) {
            var sel = window.getSelection();
            sel.removeAllRanges();
            var range = document.createRange();
            range.selectNodeContents(el);
            sel.addRange(range);
        }
        function cellBefore(table, row) {
            var cells = table.trs[row].children;
            return cells[cells.length - 2];
        }
        function cellAbove(table, row) {
            var prevRow = table.trs[row - 1];
            var index = table.trs[row].children.length - 1;
            if (prevRow && index >= 0) {
                return prevRow.children[index];
            }
        }
        function cellBorder(value) {
            return (value.size || 1) + 'px solid ' + (value.color || '#000');
        }
        function asURL(link) {
            if (!/:\/\//.test(link)) {
                link = 'http://' + link;
            }
            return link;
        }
        function drawCell(collection, cell, cls, showGrid) {
            function maybeLink(el) {
                var link = cell.link;
                if (!link) {
                    if (typeof cell.value == 'object') {
                        link = cell.value.link;
                    }
                }
                if (link) {
                    var style = { textDecoration: 'none' };
                    if (cell.color) {
                        style.color = cell.color;
                    }
                    if (cell.underline) {
                        style.textDecoration = 'underline';
                    }
                    return kendo.dom.element('a', {
                        href: asURL(link),
                        style: style,
                        target: '_blank'
                    }, el ? [el] : []);
                }
                return el;
            }
            var shouldDraw = cell.value != null || cell.validation != null && !cell.validation.value || cell.background || cell.merged;
            if (!cls && !shouldDraw) {
                return;
            }
            var style = {};
            var background = cell.background;
            if (background) {
                var defaultBorder = background;
                if (showGrid) {
                    defaultBorder = kendo.parseColor(defaultBorder).toHSV();
                    defaultBorder.v *= 0.9;
                    defaultBorder = defaultBorder.toCssRgba();
                }
                defaultBorder = cellBorder({ color: defaultBorder });
                style.outline = defaultBorder;
            }
            if (background) {
                style.backgroundColor = background;
            }
            if (cell.color) {
                style.color = cell.color;
            }
            if (cell.fontFamily) {
                style.fontFamily = cell.fontFamily;
            }
            if (cell.underline) {
                style.textDecoration = 'underline';
            }
            if (cell.italic) {
                style.fontStyle = 'italic';
            }
            if (cell.textAlign) {
                style.textAlign = cell.textAlign;
            }
            if (cell.bold) {
                style.fontWeight = 'bold';
            }
            if (cell.fontSize) {
                style.fontSize = cell.fontSize + 'px';
            }
            if (cell.wrap === true) {
                style.whiteSpace = 'pre-wrap';
                style.overflowWrap = 'break-word';
                style.wordWrap = 'break-word';
            }
            style.left = cell.left + 1 + 'px';
            style.top = cell.top + 1 + 'px';
            style.width = cell.width - 1 + 'px';
            style.height = cell.height - 1 + 'px';
            var data = cell.value, type = typeof data;
            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.message;
            }
            properties.className = classNames.join(' ');
            var div = kendo.dom.element('div', properties, children);
            collection.push(div);
            return div;
        }
        function addCell(table, row, cell) {
            var style = {};
            if (cell.background) {
                style.backgroundColor = cell.background;
            }
            if (cell.color) {
                style.color = cell.color;
            }
            if (cell.fontFamily) {
                style.fontFamily = cell.fontFamily;
            }
            if (cell.underline) {
                style.textDecoration = 'underline';
            }
            if (cell.italic) {
                style.fontStyle = 'italic';
            }
            if (cell.textAlign) {
                style.textAlign = cell.textAlign;
            }
            if (cell.verticalAlign) {
                style.verticalAlign = cell.verticalAlign === 'center' ? 'middle' : cell.verticalAlign;
            }
            if (cell.bold) {
                style.fontWeight = 'bold';
            }
            if (cell.fontSize) {
                style.fontSize = cell.fontSize + 'px';
            }
            if (cell.wrap === true) {
                style.whiteSpace = 'pre-wrap';
                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.message;
                }
                if (className) {
                    properties.className = className;
                }
                var td = kendo.dom.element('td', properties, children);
                this.trs[rowIndex].children.push(td);
                return td;
            },
            toDomTree: function (x, y, className) {
                this.trs = this.trs.filter(function (tr) {
                    return tr.visible;
                });
                var offset = 0;
                this.cols = this.cols.filter(function (col, ci) {
                    if (!col.visible) {
                        this.trs.forEach(function (tr) {
                            tr.children.splice(ci - offset, 1);
                        });
                        offset++;
                    }
                    return col.visible;
                }, this);
                return kendo.dom.element('table', {
                    style: {
                        left: x + 'px',
                        top: y + 'px',
                        height: this._height + 'px',
                        width: this._width + 'px'
                    },
                    className: className
                }, [
                    kendo.dom.element('colgroup', null, this.cols),
                    kendo.dom.element('tbody', null, this.trs)
                ]);
            }
        });
        var CELL_CONTEXT_MENU = '<ul class="#=classNames.cellContextMenu#">' + '<li data-action=cut>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, this.options);
                var formulaBar = $('<div />').appendTo(wrapper);
                this.formulaBar = new kendo.spreadsheet.FormulaBar(formulaBar);
                if (this.options.toolbar) {
                    this._tabstrip();
                }
            },
            _formulaInput: function () {
                var editor = this.element.find(DOT + View.classNames.cellEditor);
                this.formulaInput = new kendo.spreadsheet.FormulaInput(editor, { autoScale: true });
            },
            _sheetsbar: function () {
                if (this.options.sheetsbar) {
                    var options = $.extend(true, { openDialog: this.openDialog.bind(this) }, this.options.sheetsbar);
                    this.sheetsbar = new kendo.spreadsheet.SheetsBar(this.element.find(DOT + View.classNames.sheetsBar), options);
                }
            },
            _tabstrip: function () {
                var messages = this.options.messages.tabs;
                var options = $.extend(true, {
                    home: true,
                    insert: true,
                    data: true
                }, this.options.toolbar);
                var tabs = [];
                if (this.tabstrip) {
                    this.tabstrip.destroy();
                    this.element.children('.k-tabstrip').remove();
                }
                for (var name in options) {
                    if (options[name] === true || options[name] instanceof Array) {
                        tabs.push({
                            id: name,
                            text: messages[name],
                            content: ''
                        });
                    }
                }
                this.tabstrip = new kendo.spreadsheet.TabStrip($('<div />').prependTo(this.element), {
                    animation: false,
                    dataTextField: 'text',
                    dataContentField: 'content',
                    dataSource: tabs,
                    toolbarOptions: options,
                    view: this
                });
                this.tabstrip.select(0);
            },
            _executeCommand: function (e) {
                this._sheet.trigger('commandRequest', e);
            },
            workbook: function (workbook) {
                this._workbook = workbook;
                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.indexVisible(y, this.scroller.scrollTop);
                        var column = pane._grid.columns.indexVisible(x, this.scroller.scrollLeft);
                        var type = 'cell';
                        var ref = new CellRef(row, column);
                        var selecting = this._sheet.selectionInProgress();
                        if (this.isAutoFill(x, y, pane)) {
                            type = 'autofill';
                        } else if (this.isFilterIcon(x, y, pane, ref)) {
                            type = 'filtericon';
                        } else if (!selecting && x < grid._headerWidth) {
                            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: {
                                operatingRange: range,
                                property: parse ? 'input' : 'value',
                                value: value
                            }
                        });
                    }
                });
            },
            openDialog: function (name, options) {
                var dialog = kendo.spreadsheet.dialogs.create(name, options);
                if (dialog) {
                    dialog.bind('action', this._executeCommand.bind(this));
                    dialog.bind('deactivate', this._destroyDialog.bind(this));
                    this._dialogs.push(dialog);
                    var sheet = this._sheet;
                    var ref = sheet.activeCell();
                    var range = new kendo.spreadsheet.Range(ref, sheet);
                    dialog.open(range);
                    return dialog;
                }
            },
            showError: function (options, reopenEditor) {
                var errorMessages = this.options.messages.errors;
                var focusButton = function (e) {
                    var cont = e.sender.dialog().element;
                    cont.find('.k-button:first').focus();
                    cont.find('.k-button, input').on('keydown', function (ev) {
                        if (ev.keyCode == kendo.keys.ESC) {
                            e.sender.close();
                        }
                    });
                };
                var onClose = function (e) {
                    var dlg = e.sender;
                    this.selectClipBoardContents();
                    if (dlg._retry && reopenEditor) {
                        reopenEditor();
                    }
                }.bind(this);
                if (kendo.spreadsheet.dialogs.registered(options.type)) {
                    var dialogOptions = { close: onClose };
                    if (options.type === 'validationError') {
                        dialogOptions = $.extend(dialogOptions, {
                            title: options.title || 'Error',
                            text: options.body ? options.body : errorMessages[options.type],
                            activate: focusButton
                        });
                    }
                    this.openDialog(options.type, dialogOptions);
                } else {
                    this.openDialog('message', {
                        title: options.title || 'Error',
                        text: options.body ? options.body : errorMessages[options.type],
                        activate: focusButton,
                        close: onClose
                    });
                }
            },
            destroy: function () {
                this._dialogs.forEach(function (dialog) {
                    dialog.destroy();
                });
                this.cellContextMenu.destroy();
                this.rowHeaderContextMenu.destroy();
                this.colHeaderContextMenu.destroy();
                if (this.tabstrip) {
                    this.tabstrip.destroy();
                }
                this._destroyFilterMenu();
            },
            _destroyFilterMenu: function () {
                if (this._filterMenu) {
                    this._filterMenu.destroy();
                    this._filterMenu = undefined;
                    this._filterMenuColumn = undefined;
                }
            },
            render: function () {
                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);
                });
                var topCorner = kendo.dom.element('div', {
                    style: {
                        width: grid._headerWidth + 'px',
                        height: grid._headerHeight + 'px'
                    },
                    className: View.classNames.topCorner
                });
                result.push(topCorner);
                if (sheet.resizeHandlePosition() && sheet.resizeHintPosition()) {
                    result.push(this.renderResizeHint());
                }
                this.tree.render(result);
                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 tmp = sheet._getMergedCells(selection);
                var primaryMergedCells = tmp.primary;
                var secondaryMergedCells = tmp.secondary;
                sheet.forEach(selection, function (row, col, cell) {
                    var location = new CellRef(row, col).print();
                    if (!secondaryMergedCells[location]) {
                        var td = addCell(table, row - selection.topLeft.row, cell);
                        var mergedCell = primaryMergedCells[location];
                        if (mergedCell) {
                            td.attr.colspan = mergedCell.width();
                            td.attr.rowspan = mergedCell.height();
                        }
                    }
                });
                this.clipboardContents.render([table.toDomTree(0, 0, 'kendo-clipboard-' + this._workbook.clipboard()._uid)]);
                this.selectClipBoardContents();
            },
            _pane: function (row, column, rowCount, columnCount) {
                var pane = new Pane(this._sheet, this._sheet._grid.pane({
                    row: row,
                    column: column,
                    rowCount: rowCount,
                    columnCount: columnCount
                }));
                pane.refresh(this.scroller.clientWidth, this.scroller.clientHeight);
                return pane;
            }
        });
        var paneClassNames = {
            cell: 'k-spreadsheet-cell',
            vaxis: 'k-spreadsheet-vaxis',
            haxis: 'k-spreadsheet-haxis',
            vborder: 'k-spreadsheet-vborder',
            hborder: 'k-spreadsheet-hborder',
            rowHeader: 'k-spreadsheet-row-header',
            columnHeader: 'k-spreadsheet-column-header',
            pane: 'k-spreadsheet-pane',
            data: 'k-spreadsheet-data',
            mergedCell: 'k-spreadsheet-merged-cell',
            mergedCellsWrapper: 'k-merged-cells-wrapper',
            activeCell: 'k-spreadsheet-active-cell',
            selection: 'k-spreadsheet-selection',
            selectionWrapper: 'k-selection-wrapper',
            autoFillWrapper: 'k-auto-fill-wrapper',
            single: 'k-single',
            top: 'k-top',
            right: 'k-right',
            bottom: 'k-bottom',
            left: 'k-left',
            resizeHandle: 'k-resize-handle',
            columnResizeHandle: 'k-column-resize-handle',
            rowResizeHandle: 'k-row-resize-handle',
            resizeHint: 'k-resize-hint',
            resizeHintHandle: 'k-resize-hint-handle',
            resizeHintMarker: 'k-resize-hint-marker',
            resizeHintVertical: 'k-resize-hint-vertical',
            selectionHighlight: 'k-spreadsheet-selection-highlight',
            series: [
                'k-series-a',
                'k-series-b',
                'k-series-c',
                'k-series-d',
                'k-series-e',
                'k-series-f'
            ]
        };
        var Pane = kendo.Class.extend({
            init: function (sheet, grid) {
                this._sheet = sheet;
                this._grid = grid;
            },
            refresh: function (width, height) {
                this._grid.refresh(width, height);
            },
            isVisible: function (scrollLeft, scrollTop, ref) {
                return this._grid.view(scrollLeft, scrollTop).ref.intersects(ref);
            },
            render: function (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 borders = kendo.spreadsheet.draw.Borders();
                layout.cells.forEach(function (cell) {
                    borders.add(cell);
                    drawCell(cont.children, cell, null, showGridLines);
                });
                borders.vert.forEach(function (a) {
                    a.forEach(function (b) {
                        if (!b.rendered) {
                            b.rendered = true;
                            var style = {
                                left: b.x + 'px',
                                top: b.top + 'px',
                                height: b.bottom - b.top + 1 + 'px',
                                borderWidth: b.size + 'px',
                                borderColor: b.color
                            };
                            if (b.size != 1) {
                                style.transform = 'translateX(-' + (b.size - 1) / 2 + 'px)';
                            }
                            cont.children.push(kendo.dom.element('div', {
                                className: paneClassNames.vborder,
                                style: style
                            }));
                        }
                    });
                });
                borders.horiz.forEach(function (a) {
                    a.forEach(function (b) {
                        if (!b.rendered) {
                            b.rendered = true;
                            var style = {
                                top: b.y + 'px',
                                left: b.left + 'px',
                                width: b.right - b.left + 'px',
                                borderWidth: b.size + 'px',
                                borderColor: b.color
                            };
                            if (b.size != 1) {
                                style.transform = 'translateY(-' + (b.size - 1) / 2 + 'px)';
                            }
                            cont.children.push(kendo.dom.element('div', {
                                className: paneClassNames.hborder,
                                style: style
                            }));
                        }
                    });
                });
                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, 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));
                } else {
                    calendar.value(null);
                }
                var val = context.validation;
                if (val) {
                    var min = kendo.ui.Calendar.fn.options.min;
                    var max = kendo.ui.Calendar.fn.options.max;
                    if (/^(?:greaterThan|between)/.test(val.comparerType)) {
                        min = kendo.spreadsheet.numberToDate(val.from.value);
                    }
                    if (val.comparerType == 'between') {
                        max = kendo.spreadsheet.numberToDate(val.to.value);
                    }
                    if (val.comparerType == 'lessThan') {
                        max = kendo.spreadsheet.numberToDate(val.from.value);
                    }
                    calendar.setOptions({
                        disableDates: function (date) {
                            var from = val.from ? val.from.value | 0 : 0;
                            var to = val.to ? val.to.value | 0 : 0;
                            date = kendo.spreadsheet.dateToNumber(date) | 0;
                            return !kendo.spreadsheet.validation.validationComparers[val.comparerType](date, from, to);
                        },
                        min: min,
                        max: max
                    });
                } else {
                    calendar.setOptions({
                        disableDates: null,
                        min: null,
                        max: null
                    });
                }
                popup.open();
            }
            return {
                edit: function (options) {
                    context = options;
                    open();
                },
                icon: 'k-i-calendar'
            };
        });
        registerEditor('_validation_list', function () {
            var context, list, popup;
            function create() {
                if (!list) {
                    list = $('<ul class=\'k-list k-reset\'/>').kendoStaticList({
                        template: '#:value#',
                        selectable: true,
                        autoBind: false
                    });
                    popup = $('<div>').kendoPopup();
                    list.appendTo(popup);
                    popup = popup.getKendoPopup();
                    list = list.getKendoStaticList();
                    list.bind('change', function () {
                        popup.close();
                        var item = list.value()[0];
                        if (item) {
                            context.callback(item.value);
                        }
                    });
                }
                popup.setOptions({ anchor: context.view.element.find('.k-spreadsheet-editor-button') });
            }
            function open() {
                create();
                var 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-60-down'
            };
        });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/grid', [
        'kendo.core',
        'spreadsheet/references'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var CellRef = kendo.spreadsheet.CellRef;
        var RangeRef = kendo.spreadsheet.RangeRef;
        var UnionRef = kendo.spreadsheet.UnionRef;
        var Rectangle = kendo.Class.extend({
            init: function (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);
                }
                this._refresh();
            },
            toJSON: function (field, positions) {
                var values = [];
                var iterator = this.values.iterator(0, this._count - 1);
                for (var idx = 0; idx < this._count; idx++) {
                    var value = iterator.at(idx);
                    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;
            },
            indexVisible: function (value) {
                var index = this.index(value);
                if (this.hidden(index)) {
                    index = this.prevVisible(index);
                }
                return index;
            },
            _refresh: function () {
                var current = 0;
                this._pixelValues = this.values.map(function (range) {
                    var start = current;
                    current += (range.end - range.start + 1) * range.value;
                    var end = current - 1;
                    return new kendo.spreadsheet.ValueRange(start, end, range);
                });
                this.total = current;
            },
            getState: function () {
                return {
                    values: this.values.getState(),
                    hidden: this._hidden.getState()
                };
            },
            setState: function (state) {
                this.values.setState(state.values);
                this._hidden.setState(state.hidden);
                this._refresh();
            }
        });
        var PaneAxis = kendo.Class.extend({
            init: function (axis, start, count, headerSize) {
                this._axis = axis;
                this._start = start;
                this._count = count;
                this.hasHeader = start === 0;
                this.headerSize = headerSize;
                this.defaultValue = axis._value;
                this.frozen = count > 0;
            },
            viewSize: function (viewSize) {
                this._viewSize = viewSize;
            },
            sum: function (start, end) {
                return this._axis.sum(start, end - 1);
            },
            start: function () {
                return this.sum(0, this._start);
            },
            size: function () {
                return this.sum(this._start, this._start + this._count);
            },
            index: function (value, offset) {
                return this._axis.index(value + (this.frozen ? 0 : offset) - this.headerSize);
            },
            indexVisible: function (value, offset) {
                return this._axis.indexVisible(value + (this.frozen ? 0 : offset) - this.headerSize);
            },
            paneSegment: function () {
                var offset = this.start();
                var length;
                if (!this.hasHeader) {
                    offset += this.headerSize;
                }
                if (this.frozen) {
                    length = this.size();
                    if (this.hasHeader) {
                        length += this.headerSize;
                    } else {
                        length -= this.headerSize;
                    }
                } else {
                    length = this._viewSize - offset;
                }
                return {
                    offset: offset,
                    length: length
                };
            },
            visible: function (offset) {
                var start = this.start();
                var size;
                if (this.frozen) {
                    size = this.size();
                    if (!this.hasHeader) {
                        size -= this.headerSize;
                    }
                } else {
                    size = this._viewSize - start - this.headerSize;
                    start += offset;
                }
                var result = this._axis.visible(start, start + size - 1);
                if (this.frozen) {
                    result.offset = 0;
                }
                result.start = start;
                if (this.hasHeader) {
                    result.offset += this.headerSize;
                    result.start -= this.headerSize;
                }
                return result;
            },
            contains: function (start, end) {
                if (this.frozen) {
                    if (start > this._start + this._count) {
                        return false;
                    }
                    if (end < this._start) {
                        return false;
                    }
                    return true;
                } else {
                    return end >= this._start;
                }
            }
        });
        kendo.spreadsheet.Axis = Axis;
        kendo.spreadsheet.PaneAxis = PaneAxis;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/filter', [
        'kendo.core',
        'kendo.data'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var Filter = kendo.spreadsheet.Filter = kendo.Class.extend({
            prepare: function () {
            },
            value: function (cell) {
                return cell.value;
            },
            matches: function () {
                throw new Error('The \'matches\' method is not implemented.');
            },
            toJSON: function () {
                throw new Error('The \'toJSON\' method is not implemented.');
            }
        });
        Filter.create = function (options) {
            var filter = options.filter;
            if (!filter) {
                throw new Error('Filter type not specified.');
            }
            var constructor = kendo.spreadsheet[filter.charAt(0).toUpperCase() + filter.substring(1) + 'Filter'];
            if (!constructor) {
                throw new Error('Filter type not recognized.');
            }
            return new constructor(options);
        };
        kendo.spreadsheet.ValueFilter = Filter.extend({
            _values: [],
            _dates: [],
            _blanks: false,
            init: function ValueFilter(options) {
                if (options.values !== undefined) {
                    this._values = options.values;
                }
                if (options.blanks !== undefined) {
                    this._blanks = options.blanks;
                }
                if (options.dates !== undefined) {
                    this._dates = options.dates;
                }
            },
            value: function (cell) {
                var value = cell.value;
                if (this._dates.length > 0 && cell.format && typeof value === 'number') {
                    var type = kendo.spreadsheet.formatting.type(value, cell.format);
                    if (type === 'date') {
                        value = kendo.spreadsheet.numberToDate(value);
                    }
                }
                return value;
            },
            matches: function (value) {
                if (value === null || value === undefined) {
                    return this._blanks;
                }
                if (value instanceof Date) {
                    return this._dates.some(function (date) {
                        return date.year === value.getFullYear() && (date.month === undefined || date.month === value.getMonth()) && (date.day === undefined || date.day === value.getDate()) && (date.hours === undefined || date.hours === value.getHours()) && (date.minutes === undefined || date.minutes === value.getMinutes()) && (date.seconds === undefined || date.seconds === value.getSeconds());
                    });
                }
                return this._values.indexOf(value) >= 0;
            },
            toJSON: function () {
                return {
                    filter: 'value',
                    blanks: this._blanks,
                    values: this._values.slice(0)
                };
            }
        });
        kendo.spreadsheet.CustomFilter = Filter.extend({
            _logic: 'and',
            init: function CustomFilter(options) {
                if (options.logic !== undefined) {
                    this._logic = options.logic;
                }
                if (options.criteria === undefined) {
                    throw new Error('Must specify criteria.');
                }
                this._criteria = options.criteria;
                var expression = kendo.data.Query.filterExpr({
                    logic: this._logic,
                    filters: this._criteria
                }).expression;
                this._matches = new Function('d', 'return ' + expression);
            },
            matches: function (value) {
                if (value === null) {
                    return false;
                }
                return this._matches(value);
            },
            value: function (cell) {
                var value = cell.value;
                var criterionValue = this._criteria[0].value;
                var criterionType = criterionValue instanceof Date ? 'date' : typeof criterionValue;
                var valueType = typeof value;
                if (cell.format) {
                    valueType = kendo.spreadsheet.formatting.type(value, cell.format);
                }
                if (valueType != criterionType) {
                    if (criterionType == 'string') {
                        if (cell.format) {
                            value = kendo.spreadsheet.formatting.text(value, cell.format);
                        }
                        value = value + '';
                    }
                } else if (valueType == 'date') {
                    value = kendo.spreadsheet.numberToDate(value);
                }
                return value;
            },
            toJSON: function () {
                return {
                    filter: 'custom',
                    logic: this._logic,
                    criteria: this._criteria
                };
            }
        });
        kendo.spreadsheet.TopFilter = Filter.extend({
            init: function TopFilter(options) {
                this._type = options.type;
                this._value = options.value;
                this._values = [];
            },
            prepare: function (cells) {
                var values = cells.map(this.value).sort().filter(function (value, index, array) {
                    return index === 0 || value !== array[index - 1];
                });
                if (this._type === 'topNumber' || this._type == 'topPercent') {
                    values.sort(function (x, y) {
                        return y - x;
                    });
                } else {
                    values.sort(function (x, y) {
                        return x - y;
                    });
                }
                var count = this._value;
                if (this._type === 'topPercent' || this._type === 'bottomPercent') {
                    count = values.length * count / 100 >> 0;
                }
                this._values = values.slice(0, count);
            },
            matches: function (value) {
                return this._values.indexOf(value) >= 0;
            },
            toJSON: function () {
                return {
                    filter: 'top',
                    type: this._type,
                    value: this._value
                };
            }
        });
        kendo.spreadsheet.DynamicFilter = Filter.extend({
            init: function DynamicFilter(options) {
                this._type = options.type;
                this._predicate = this[options.type];
                if (typeof this._predicate !== 'function') {
                    throw new Error('DynamicFilter type \'' + options.type + '\' not recognized.');
                }
            },
            value: function (cell) {
                var value = cell.value;
                if (cell.format) {
                    var type = kendo.spreadsheet.formatting.type(value, cell.format);
                    if (type === 'date') {
                        value = kendo.spreadsheet.numberToDate(value);
                    }
                }
                return value;
            },
            prepare: function (cells) {
                var sum = 0;
                var count = 0;
                for (var ci = 0; ci < cells.length; ci++) {
                    var value = this.value(cells[ci]);
                    if (typeof value === 'number') {
                        sum += value;
                        count++;
                    }
                }
                if (count > 0) {
                    this._average = sum / count;
                } else {
                    this._average = 0;
                }
            },
            matches: function (value) {
                return this._predicate(value);
            },
            aboveAverage: function (value) {
                if (value instanceof Date) {
                    value = kendo.spreadsheet.dateToNumber(value);
                }
                if (typeof value !== 'number') {
                    return false;
                }
                return value > this._average;
            },
            belowAverage: function (value) {
                if (value instanceof Date) {
                    value = kendo.spreadsheet.dateToNumber(value);
                }
                if (typeof value !== 'number') {
                    return false;
                }
                return value < this._average;
            },
            tomorrow: function (value) {
                if (value instanceof Date) {
                    var tomorrow = kendo.date.addDays(kendo.date.today(), 1);
                    return kendo.date.getDate(value).getTime() === tomorrow.getTime();
                }
                return false;
            },
            today: function (value) {
                if (value instanceof Date) {
                    return kendo.date.isToday(value);
                }
                return false;
            },
            yesterday: function (value) {
                if (value instanceof Date) {
                    var yesterday = kendo.date.addDays(kendo.date.today(), -1);
                    return kendo.date.getDate(value).getTime() === yesterday.getTime();
                }
                return false;
            },
            nextWeek: function (value) {
                return sameWeek(kendo.date.addDays(kendo.date.today(), 7), value);
            },
            thisWeek: function (value) {
                return sameWeek(kendo.date.today(), value);
            },
            lastWeek: function (value) {
                return sameWeek(kendo.date.addDays(kendo.date.today(), -7), value);
            },
            nextMonth: function (value) {
                return sameMonth(value, 1);
            },
            thisMonth: function (value) {
                return sameMonth(value, 0);
            },
            lastMonth: function (value) {
                return sameMonth(value, -1);
            },
            nextQuarter: function (value) {
                if (value instanceof Date) {
                    var today = kendo.date.today();
                    var diff = quarter(value) - quarter(today);
                    return diff === 1 && today.getFullYear() === value.getFullYear() || diff == -3 && today.getFullYear() + 1 === value.getFullYear();
                }
                return false;
            },
            thisQuarter: function (value) {
                if (value instanceof Date) {
                    var today = kendo.date.today();
                    var diff = quarter(value) - quarter(today);
                    return diff === 0 && today.getFullYear() === value.getFullYear();
                }
                return false;
            },
            lastQuarter: function (value) {
                if (value instanceof Date) {
                    var today = kendo.date.today();
                    var diff = quarter(today) - quarter(value);
                    return diff === 1 && today.getFullYear() === value.getFullYear() || diff == -3 && today.getFullYear() - 1 === value.getFullYear();
                }
                return false;
            },
            nextYear: function (value) {
                return sameYear(value, 1);
            },
            thisYear: function (value) {
                return sameYear(value, 0);
            },
            lastYear: function (value) {
                return sameYear(value, -1);
            },
            yearToDate: function (value) {
                if (value instanceof Date) {
                    var today = kendo.date.today();
                    return value.getFullYear() === today.getFullYear() && value <= today;
                }
                return false;
            },
            toJSON: function () {
                return {
                    filter: 'dynamic',
                    type: this._type
                };
            }
        });
        [
            1,
            2,
            3,
            4
        ].forEach(function (target) {
            kendo.spreadsheet.DynamicFilter.prototype['quarter' + target] = function (value) {
                if (value instanceof Date) {
                    return quarter(value) === target;
                }
                return false;
            };
        });
        kendo.cultures['en-US'].calendar.months.names.forEach(function (month, index) {
            kendo.spreadsheet.DynamicFilter.prototype[month.toLowerCase()] = function (value) {
                if (value instanceof Date) {
                    return value.getMonth() === index;
                }
                return false;
            };
        });
        function quarter(value) {
            var month = value.getMonth() + 1;
            if (month >= 1 && month <= 3) {
                return 1;
            } else if (month >= 4 && month <= 6) {
                return 2;
            } else if (month >= 7 && month <= 9) {
                return 3;
            } else {
                return 4;
            }
        }
        function sameYear(value, offset) {
            if (value instanceof Date) {
                var today = kendo.date.today();
                today.setFullYear(today.getFullYear() + offset);
                return today.getFullYear() === value.getFullYear();
            }
            return false;
        }
        function sameMonth(value, offset) {
            if (value instanceof Date) {
                var today = kendo.date.firstDayOfMonth(kendo.date.today());
                today.setMonth(today.getMonth() + offset, 1);
                return today.getTime() === kendo.date.firstDayOfMonth(value).getTime();
            }
            return false;
        }
        function sameWeek(a, b) {
            if (b instanceof Date) {
                var firstWeek = kendo.date.dayOfWeek(kendo.date.getDate(a), 1);
                var secondWeek = kendo.date.dayOfWeek(kendo.date.getDate(b), 1);
                return firstWeek.getTime() === secondWeek.getTime();
            }
            return false;
        }
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/sorter', ['kendo.core'], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var Sorter = kendo.Class.extend({
            init: function (grid, lists) {
                this._grid = grid;
                this._lists = lists;
            },
            indices: function (rangeRef, list, ascending, indices) {
                var comparer = Sorter.ascendingComparer;
                if (ascending === false) {
                    comparer = Sorter.descendingComparer;
                }
                return list.sortedIndices(this._grid.cellRefIndex(rangeRef.topLeft), this._grid.cellRefIndex(rangeRef.bottomRight), comparer, indices);
            },
            sortBy: function (ref, column, list, ascending, indices) {
                var sortedIndices = this.indices(ref.toColumn(column), list, ascending, indices);
                for (var ci = ref.topLeft.col; ci <= ref.bottomRight.col; ci++) {
                    var start = this._grid.index(ref.topLeft.row, ci);
                    var end = this._grid.index(ref.bottomRight.row, ci);
                    for (var li = 0; li < this._lists.length; li++) {
                        if (start < this._lists[li].lastRangeStart()) {
                            this._lists[li].sort(start, end, sortedIndices);
                        }
                    }
                }
                return sortedIndices;
            }
        });
        Sorter.ascendingComparer = function (a, b) {
            if (a === null && b === null) {
                return 0;
            }
            if (a === null) {
                return 1;
            }
            if (b === null) {
                return -1;
            }
            var typeA = typeof a;
            var typeB = typeof b;
            if (typeA === 'number') {
                if (typeB === 'number') {
                    return a - b;
                } else {
                    return -1;
                }
            }
            if (typeA === 'string') {
                switch (typeB) {
                case 'number':
                    return 1;
                case 'string':
                    return a.localeCompare(b);
                default:
                    return -1;
                }
            }
            if (typeA === 'boolean') {
                switch (typeB) {
                case 'number':
                    return 1;
                case 'string':
                    return 1;
                case 'boolean':
                    return a - b;
                default:
                    return -1;
                }
            }
            if (a instanceof kendo.spreadsheet.calc.runtime.CalcError) {
                if (b instanceof kendo.spreadsheet.calc.runtime.CalcError) {
                    return 0;
                } else {
                    return 1;
                }
            }
            throw new Error('Cannot compare ' + a + ' and ' + b);
        };
        Sorter.descendingComparer = function (a, b) {
            if (a === null && b === null) {
                return 0;
            }
            if (a === null) {
                return 1;
            }
            if (b === null) {
                return -1;
            }
            return Sorter.ascendingComparer(b, a);
        };
        kendo.spreadsheet.Sorter = Sorter;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/numformat', [
        'spreadsheet/calc',
        'kendo.dom'
    ], 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) {
        return packDate(year, month - 1, date);
    }).args([
        [
            '*year',
            'integer'
        ],
        [
            '*month',
            'integer'
        ],
        [
            '*date',
            'integer'
        ]
    ]);
    defineFunction('day', function (date) {
        return unpackDate(date).date;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('month', function (date) {
        return unpackDate(date).month + 1;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('year', function (date) {
        return unpackDate(date).year;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('weekday', function (date) {
        return unpackDate(date).day + 1;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('weeknum', function (date, type) {
        var fw = packDate(unpackDate(date).year, 0, 1);
        var sy = unpackDate(fw);
        var diff;
        if (type == 21) {
            diff = 3 - (sy.day + 6) % 7;
            if (diff < 0) {
                diff += 7;
            }
            fw += diff;
            sy.date += diff;
            sy.day = 4;
            type = 1;
        } else {
            if (type == 1) {
                type = 0;
            } else if (type == 2) {
                type = 1;
            } else {
                type = (type - 10) % 7;
            }
        }
        diff = sy.day - type;
        if (diff < 0) {
            diff += 7;
        }
        fw -= diff;
        return Math.ceil((date + 1 - fw) / 7);
    }).args([
        [
            '*date',
            'date'
        ],
        [
            '*type',
            [
                'or',
                [
                    'null',
                    1
                ],
                [
                    'values',
                    1,
                    2,
                    11,
                    12,
                    13,
                    14,
                    15,
                    16,
                    17,
                    21
                ]
            ]
        ]
    ]);
    function weeksInYear(year) {
        var d = unpackDate(packDate(year, 0, 1));
        if (d.day == 4 || d.day == 3 && runtime.isLeapYear(year)) {
            return 53;
        }
        return 52;
    }
    defineFunction('isoweeknum', function isoweeknum(date) {
        var d = unpackDate(date);
        var dow = d.day || 7;
        var wk = Math.floor((d.ord - dow + 10) / 7);
        if (wk < 1) {
            return weeksInYear(d.year - 1);
        } else if (wk == 53 && wk > weeksInYear(d.year)) {
            return 1;
        }
        return wk;
    }).args([[
            '*date',
            'date'
        ]]);
    defineFunction('now', function () {
        return runtime.dateToSerial(new Date());
    }).args([]);
    defineFunction('today', function () {
        return runtime.dateToSerial(new Date()) | 0;
    }).args([]);
    defineFunction('time', function (hh, mm, ss) {
        return runtime.packTime(hh, mm, ss, 0);
    }).args([
        [
            '*hours',
            'integer'
        ],
        [
            '*minutes',
            'integer'
        ],
        [
            '*seconds',
            'integer'
        ]
    ]);
    defineFunction('hour', function (time) {
        return runtime.unpackTime(time).hours;
    }).args([[
            '*time',
            'datetime'
        ]]);
    defineFunction('minute', function (time) {
        return runtime.unpackTime(time).minutes;
    }).args([[
            '*time',
            'datetime'
        ]]);
    defineFunction('second', function (time) {
        return runtime.unpackTime(time).seconds;
    }).args([[
            '*time',
            'datetime'
        ]]);
    defineFunction('edate', function (base, months) {
        var d = unpackDate(base);
        var m = d.month + months;
        var y = d.year + Math.floor(m / 12);
        m %= 12;
        if (m < 0) {
            m += 12;
        }
        d = Math.min(d.date, daysInMonth(y, m));
        return packDate(y, m, d);
    }).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*months',
            'integer'
        ]
    ]);
    defineFunction('eomonth', function (base, months) {
        var d = unpackDate(base);
        var m = d.month + months;
        var y = d.year + Math.floor(m / 12);
        m %= 12;
        if (m < 0) {
            m += 12;
        }
        d = daysInMonth(y, m);
        return packDate(y, m, d);
    }).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*months',
            'integer'
        ]
    ]);
    defineFunction('workday', function (date, n, holidays) {
        var inc = n > 0 ? 1 : -1;
        n = Math.abs(n);
        var dow = unpackDate(date).day;
        while (n > 0) {
            date += inc;
            dow = (dow + inc) % 7;
            if (dow > 0 && dow < 6 && holidays.indexOf(date) < 0) {
                --n;
            }
        }
        return date;
    }).args([
        [
            'start_date',
            'date'
        ],
        [
            'days',
            'integer'
        ],
        [
            'holidays',
            [
                'collect',
                'date'
            ]
        ]
    ]);
    defineFunction('networkdays', function (date, end, holidays) {
        if (date > end) {
            var tmp = date;
            date = end;
            end = tmp;
        }
        var count = 0;
        var dow = unpackDate(date).day;
        while (date <= end) {
            if (dow > 0 && dow < 6 && holidays.indexOf(date) < 0) {
                count++;
            }
            date++;
            dow = (dow + 1) % 7;
        }
        return count;
    }).args([
        [
            'start_date',
            'date'
        ],
        [
            'end_date',
            'date'
        ],
        [
            'holidays',
            [
                'collect',
                'date'
            ]
        ]
    ]);
    defineFunction('days', function (start, end) {
        return end - start;
    }).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*end_date',
            'date'
        ]
    ]);
    function _days_360(start, end, method) {
        var d1 = unpackDate(start);
        var d2 = unpackDate(end);
        if (method) {
            if (d1.date == 31) {
                d1.date = 30;
            }
            if (d2.date == 31) {
                d2.date = 30;
            }
        } else {
            if (d1.month == 1 && d2.month == 1 && d1.date == daysInMonth(d1.year, 1) && d2.date == daysInMonth(d2.year, 1)) {
                d2.date = 30;
            }
            if (d1.date == daysInMonth(d1.year, d1.month)) {
                d1.date = 30;
                if (d2.date == 31) {
                    d2.date = 30;
                }
            } else {
                if (d1.date == 30 && d2.date == 31) {
                    d2.date = 30;
                }
            }
        }
        return 360 * (d2.year - d1.year) + 30 * (d2.month - d1.month) + (d2.date - d1.date);
    }
    runtime._days_360 = _days_360;
    defineFunction('days360', _days_360).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*end_date',
            'date'
        ],
        [
            '*method',
            [
                'or',
                'logical',
                [
                    'null',
                    false
                ]
            ]
        ]
    ]);
    defineFunction('yearfrac', function (start, end, method) {
        switch (method) {
        case 0:
            return _days_360(start, end, false) / 360;
        case 1:
            return (end - start) / daysInYear(unpackDate(start).year);
        case 2:
            return (end - start) / 360;
        case 3:
            return (end - start) / 365;
        case 4:
            return _days_360(start, end, true) / 360;
        }
    }).args([
        [
            '*start_date',
            'date'
        ],
        [
            '*end_date',
            'date'
        ],
        [
            '*method',
            [
                'or',
                [
                    'null',
                    0
                ],
                [
                    'values',
                    0,
                    1,
                    2,
                    3,
                    4
                ]
            ]
        ]
    ]);
    defineFunction('datevalue', function (text) {
        var date = runtime.parseDate(text);
        if (date) {
            return runtime.dateToSerial(date);
        }
        return new CalcError('VALUE');
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('timevalue', function (text) {
        var m = text.toLowerCase().match(/(\d+):(\d+)(:(\d+)(\.(\d+))?)?\s*(am?|pm?)?/);
        if (m) {
            var hh = parseFloat(m[1]);
            var mm = parseFloat(m[2]);
            var ss = m[3] ? parseFloat(m[4]) : 0;
            var ampm = m[7];
            if (ampm && (hh > 12 || hh < 1)) {
                return new CalcError('VALUE');
            }
            if (/^p/.test(ampm)) {
                hh += 12;
            }
            return runtime.packTime(hh, mm, ss, 0);
        }
        return new CalcError('VALUE');
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('mdeterm', function (m) {
        var error = m.each(function (val) {
            if (typeof val != 'number') {
                return new CalcError('VALUE');
            }
        }, true);
        return error || m.determinant();
    }).args([[
            'm',
            [
                'and',
                'matrix',
                [
                    'assert',
                    '$m.width == $m.height'
                ]
            ]
        ]]);
    defineFunction('transpose', function (m) {
        return m.transpose();
    }).args([[
            'range',
            'matrix'
        ]]);
    defineFunction('mmult', function (a, b) {
        return a.multiply(b);
    }).args([
        [
            'a',
            'matrix'
        ],
        [
            'b',
            [
                'and',
                'matrix',
                [
                    'assert',
                    '$b.height == $a.width'
                ]
            ]
        ]
    ]);
    defineFunction('munit', function (n) {
        return new Matrix(this).unit(n);
    }).args([[
            'n',
            'integer+'
        ]]);
    defineFunction('minverse', function (m) {
        var error = m.each(function (val) {
            if (typeof val != 'number') {
                return new CalcError('VALUE');
            }
        }, true);
        return error || m.inverse() || new CalcError('VALUE');
    }).args([[
            'm',
            [
                'and',
                'matrix',
                [
                    'assert',
                    '$m.width == $m.height'
                ]
            ]
        ]]);
    defineFunction('rand', function () {
        return Math.random();
    }).args([]);
    defineFunction('randbetween', function (min, max) {
        return min + Math.floor((max - min + 1) * Math.random());
    }).args([
        [
            'min',
            'integer'
        ],
        [
            'max',
            [
                'and',
                'integer',
                [
                    'assert',
                    '$max >= $min'
                ]
            ]
        ]
    ]);
    defineFunction('true', function () {
        return true;
    }).args([]);
    defineFunction('false', function () {
        return true;
    }).args([]);
    defineFunction('roman', function (num) {
        return util.arabicToRoman(num).toUpperCase();
    }).args([[
            '*number',
            'integer'
        ]]);
    defineFunction('arabic', function (rom) {
        var num = util.romanToArabic(rom);
        return num == null ? new CalcError('VALUE') : num;
    }).args([[
            '*roman',
            'string'
        ]]);
    defineFunction('base', function (number, radix, minLen) {
        var str = number.toString(radix).toUpperCase();
        while (str.length < minLen) {
            str = '0' + str;
        }
        return str;
    }).args([
        [
            '*number',
            'integer'
        ],
        [
            '*radix',
            [
                'and',
                'integer',
                [
                    '[between]',
                    2,
                    36
                ]
            ]
        ],
        [
            '*minLen',
            [
                'or',
                'integer+',
                [
                    'null',
                    0
                ]
            ]
        ]
    ]);
    defineFunction('decimal', function (text, radix) {
        text = text.toUpperCase();
        var val = 0;
        for (var i = 0; i < text.length; ++i) {
            var d = text.charCodeAt(i);
            if (d >= 48 && d <= 57) {
                d -= 48;
            } else if (d >= 65 && d < 55 + radix) {
                d -= 55;
            } else {
                return new CalcError('VALUE');
            }
            val = val * radix + d;
        }
        return val;
    }).args([
        [
            '*text',
            'string'
        ],
        [
            '*radix',
            [
                'and',
                'integer',
                [
                    '[between]',
                    2,
                    36
                ]
            ]
        ]
    ]);
    defineFunction('char', function (code) {
        return String.fromCharCode(code);
    }).args([[
            '*code',
            'integer+'
        ]]);
    var RX_NON_PRINTABLE = /[\0-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
    defineFunction('clean', function (text) {
        return text.replace(RX_NON_PRINTABLE, '');
    }).args([[
            '*text',
            'string'
        ]]);
    defineFunction('code', function (text) {
        return text.charAt(0);
    }).args([[
            '*text',
            'string'
        ]]);
    defineAlias('unichar', 'char');
    defineAlias('unicode', 'code');
    defineFunction('concatenate', function (args) {
        var out = '';
        for (var i = 0; i < args.length; ++i) {
            out += args[i];
        }
        return out;
    }).args([[
            '+',
            [
                '*text',
                'string'
            ]
        ]]);
    defineFunction('dollar', function (number, decimals) {
        var format = '$#,##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-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] + '" aria-label="' + messages[type] + '" href="#" data-border-type="' + type + '" class="k-button k-button-icon">' + '<span class="k-icon k-i-' + kendo.toHyphens(type) + '"></span>' + '</a>';
                }).join('');
                var element = $('<div />', {
                    'class': 'k-spreadsheet-border-type-palette',
                    'html': buttons
                });
                element.appendTo(this.element);
            },
            _borderColorPalette: function () {
                var element = $('<div />', { 'class': 'k-spreadsheet-border-color-palette' });
                element.appendTo(this.element);
                this.colorChooser = new ColorChooser(element, {
                    color: this.color,
                    change: this._colorChange.bind(this)
                });
            },
            _click: function (e) {
                this.type = $(e.currentTarget).data('borderType');
                this.trigger('change', {
                    type: this.type,
                    color: this.color
                });
            },
            _colorChange: function (e) {
                this.color = e.value;
                if (this.type) {
                    this.trigger('change', {
                        type: this.type,
                        color: this.color
                    });
                }
            }
        });
        kendo.spreadsheet.ColorChooser = ColorChooser;
        kendo.spreadsheet.BorderPalette = BorderPalette;
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/toolbar', [
        'kendo.toolbar',
        'kendo.colorpicker',
        'kendo.combobox',
        'kendo.dropdownlist',
        'kendo.popup',
        'spreadsheet/borderpalette'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var ToolBar = kendo.ui.ToolBar;
        var MESSAGES = kendo.spreadsheet.messages.toolbar = {
            addColumnLeft: 'Add column left',
            addColumnRight: 'Add column right',
            addRowAbove: 'Add row above',
            addRowBelow: 'Add row below',
            alignment: 'Alignment',
            alignmentButtons: {
                justtifyLeft: 'Align left',
                justifyCenter: 'Center',
                justifyRight: 'Align right',
                justifyFull: 'Justify',
                alignTop: 'Align top',
                alignMiddle: 'Align middle',
                alignBottom: 'Align bottom'
            },
            backgroundColor: 'Background',
            bold: 'Bold',
            borders: 'Borders',
            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',
            sort: 'Sort',
            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: 'file-excel'
            },
            exportAs: {
                type: 'exportAsDialog',
                dialogName: 'exportAs',
                overflow: 'never',
                text: '',
                iconClass: 'file-excel'
            },
            bold: {
                type: 'button',
                command: 'PropertyChangeCommand',
                property: 'bold',
                value: true,
                iconClass: 'bold',
                togglable: true
            },
            italic: {
                type: 'button',
                command: 'PropertyChangeCommand',
                property: 'italic',
                value: true,
                iconClass: 'italic',
                togglable: true
            },
            underline: {
                type: 'button',
                command: 'PropertyChangeCommand',
                property: 'underline',
                value: true,
                iconClass: 'underline',
                togglable: true
            },
            formatDecreaseDecimal: {
                type: 'button',
                command: 'AdjustDecimalsCommand',
                value: -1,
                iconClass: 'decimal-decrease'
            },
            formatIncreaseDecimal: {
                type: 'button',
                command: 'AdjustDecimalsCommand',
                value: +1,
                iconClass: 'decimal-increase'
            },
            textWrap: {
                type: 'button',
                command: 'TextWrapCommand',
                property: 'wrap',
                value: true,
                iconClass: 'text-wrap',
                togglable: true
            },
            cut: {
                type: 'button',
                command: 'ToolbarCutCommand',
                iconClass: 'cut'
            },
            copy: {
                type: 'button',
                command: 'ToolbarCopyCommand',
                iconClass: 'copy'
            },
            paste: {
                type: 'button',
                command: 'ToolbarPasteCommand',
                iconClass: 'paste'
            },
            separator: { type: 'separator' },
            alignment: {
                type: 'alignment',
                iconClass: 'align-left'
            },
            backgroundColor: {
                type: 'colorPicker',
                property: 'background',
                iconClass: 'paint'
            },
            textColor: {
                type: 'colorPicker',
                property: 'color',
                iconClass: 'foreground-color'
            },
            fontFamily: {
                type: 'fontFamily',
                property: 'fontFamily',
                iconClass: 'font-family'
            },
            fontSize: {
                type: 'fontSize',
                property: 'fontSize',
                iconClass: 'font-size'
            },
            format: {
                type: 'format',
                property: 'format',
                iconClass: 'custom-format'
            },
            filter: {
                type: 'filter',
                property: 'hasFilter',
                iconClass: 'filter'
            },
            merge: {
                type: 'merge',
                iconClass: 'cells-merge'
            },
            freeze: {
                type: 'freeze',
                iconClass: 'pane-freeze'
            },
            borders: {
                type: 'borders',
                iconClass: 'borders-all'
            },
            formatCells: {
                type: 'dialog',
                dialogName: 'formatCells',
                overflow: 'never'
            },
            hyperlink: {
                type: 'dialog',
                dialogName: 'hyperlink',
                iconClass: 'link-horizontal',
                overflow: 'never',
                text: ''
            },
            toggleGridlines: {
                type: 'button',
                command: 'GridLinesChangeCommand',
                property: 'gridLines',
                value: true,
                iconClass: 'border-no',
                togglable: true
            },
            addColumnLeft: {
                type: 'button',
                command: 'AddColumnCommand',
                value: 'left',
                iconClass: 'table-column-insert-left'
            },
            addColumnRight: {
                type: 'button',
                command: 'AddColumnCommand',
                value: 'right',
                iconClass: 'table-column-insert-right'
            },
            addRowBelow: {
                type: 'button',
                command: 'AddRowCommand',
                value: 'below',
                iconClass: 'table-row-insert-below'
            },
            addRowAbove: {
                type: 'button',
                command: 'AddRowCommand',
                value: 'above',
                iconClass: 'table-row-insert-above'
            },
            deleteColumn: {
                type: 'button',
                command: 'DeleteColumnCommand',
                iconClass: 'table-column-delete'
            },
            deleteRow: {
                type: 'button',
                command: 'DeleteRowCommand',
                iconClass: 'table-row-delete'
            },
            sort: {
                type: 'sort',
                iconClass: 'sort-desc'
            },
            validation: {
                type: 'dialog',
                dialogName: 'validation',
                iconClass: 'exception',
                overflow: 'never'
            }
        };
        var SpreadsheetToolBar = ToolBar.extend({
            init: function (element, options) {
                options.items = this._expandTools(options.tools || SpreadsheetToolBar.prototype.options.tools[options.toolbarName]);
                ToolBar.fn.init.call(this, element, options);
                var handleClick = this._click.bind(this);
                this.element.addClass('k-spreadsheet-toolbar');
                this._addSeparators(this.element);
                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-i-' + options.iconClass;
                    var type = options.type;
                    var typeDefaults = {
                        button: { showText: 'overflow' },
                        colorPicker: {
                            toolIcon: spriteCssClass,
                            spriteCssClass: spriteCssClass
                        },
                        borders: { spriteCssClass: spriteCssClass },
                        alignment: { spriteCssClass: spriteCssClass },
                        merge: { spriteCssClass: spriteCssClass },
                        freeze: { spriteCssClass: spriteCssClass }
                    };
                    var tool = $.extend({
                        name: options.name || toolName,
                        text: MESSAGES[options.name || toolName],
                        icon: options.iconClass,
                        attributes: {
                            title: MESSAGES[options.name || toolName],
                            'aria-label': MESSAGES[options.name || toolName]
                        }
                    }, typeDefaults[type], options);
                    if (type == 'splitButton') {
                        tool.menuButtons = tool.menuButtons.map(expandTool);
                    }
                    tool.attributes['data-tool'] = toolName;
                    if (options.property) {
                        tool.attributes['data-property'] = options.property;
                    }
                    return tool;
                }
                return tools.reduce(function (tools, tool) {
                    if ($.isArray(tool)) {
                        tools.push({
                            type: 'buttonGroup',
                            buttons: tool.map(expandTool)
                        });
                    } else {
                        tools.push(expandTool.call(this, tool));
                    }
                    return tools;
                }, []);
            },
            _click: function (e) {
                var toolName = e.target.attr('data-tool');
                var tool = toolDefaults[toolName] || {};
                var commandType = tool.command;
                if (!commandType) {
                    return;
                }
                var args = {
                    command: commandType,
                    options: {
                        property: tool.property || null,
                        value: tool.value || null
                    }
                };
                if (typeof args.options.value === 'boolean') {
                    args.options.value = e.checked ? true : null;
                }
                this.action(args);
            },
            events: [
                'click',
                'toggle',
                'open',
                'close',
                'overflowOpen',
                'overflowClose',
                'action',
                'dialog'
            ],
            options: {
                name: 'SpreadsheetToolBar',
                resizable: true,
                tools: defaultTools
            },
            action: function (args) {
                this.trigger('action', args);
            },
            dialog: function (args) {
                this.trigger('dialog', args);
            },
            refresh: function (activeCell) {
                var range = activeCell;
                var tools = this._tools();
                function setToggle(tool, value) {
                    var toolbar = tool.toolbar;
                    var overflow = tool.overflow;
                    var togglable = toolbar && toolbar.options.togglable || overflow && overflow.options.togglable;
                    if (!togglable) {
                        return;
                    }
                    var toggle = false;
                    if (typeof value === 'boolean') {
                        toggle = value;
                    } else if (typeof value === 'string') {
                        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 />').attr('title', options.attributes.title).attr('aria-label', options.attributes.title).kendoDropDownList({ height: 'auto' }).data('kendoDropDownList');
                this.dropDownList = dropDownList;
                this.element = dropDownList.wrapper;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                dropDownList.bind('open', this._open.bind(this));
                dropDownList.bind('change', this._change.bind(this));
                this.element.width(options.width).attr({
                    'data-command': 'PropertyChangeCommand',
                    'data-property': options.property
                });
            },
            _open: function () {
                var ddl = this.dropDownList;
                var list = ddl.list;
                var listWidth;
                list.css({
                    whiteSpace: 'nowrap',
                    width: 'auto'
                });
                listWidth = list.width();
                if (listWidth) {
                    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-60-down\'></span>' + '</a>');
                this.element.on('click touchend', this.open.bind(this)).attr('data-command', options.command);
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this._popup();
            },
            destroy: function () {
                this.popup.destroy();
            },
            open: function (ev) {
                ev.preventDefault();
                this.popup.toggle();
            },
            _popup: function () {
                var element = this.element;
                this.popup = $('<div class=\'k-spreadsheet-popup\' />').appendTo(element).kendoPopup({ anchor: element }).data('kendoPopup');
            }
        });
        kendo.toolbar.registerComponent('dialog', kendo.toolbar.ToolBarButton.extend({
            init: function (options, toolbar) {
                kendo.toolbar.ToolBarButton.fn.init.call(this, options, toolbar);
                this._dialogName = options.dialogName;
                this.element.bind('click touchend', this.open.bind(this)).data('instance', this);
            },
            open: function () {
                this.toolbar.dialog({ name: this._dialogName });
            }
        }));
        kendo.toolbar.registerComponent('exportAsDialog', kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                this._dialogName = options.dialogName;
                this.toolbar = toolbar;
                this._title = options.attributes.title;
                this.element = $('<button class=\'k-button k-button-icon\'>' + '<span class=\'k-icon k-i-file-excel\' />' + '</button>').attr('title', this._title).attr('aria-label', this._title).data('instance', this);
                this.element.bind('click', this.open.bind(this)).data('instance', this);
            },
            open: function () {
                this.toolbar.dialog({ name: this._dialogName });
            }
        }));
        var OverflowDialogButton = kendo.toolbar.OverflowButton.extend({
            init: function (options, toolbar) {
                kendo.toolbar.OverflowButton.fn.init.call(this, options, toolbar);
                this.element.on('click touchend', this._click.bind(this));
                this.message = this.options.text;
                var instance = this.element.data('button');
                this.element.data(this.options.type, instance);
            },
            _click: $.noop
        });
        var ColorPicker = PopupTool.extend({
            init: function (options, toolbar) {
                PopupTool.fn.init.call(this, options, toolbar);
                this.popup.element.addClass('k-spreadsheet-colorpicker');
                this.colorChooser = new kendo.spreadsheet.ColorChooser(this.popup.element, { change: this._colorChange.bind(this) });
                this.element.attr({ 'data-property': options.property });
                this.element.data({
                    type: 'colorPicker',
                    colorPicker: this,
                    instance: this
                });
            },
            destroy: function () {
                this.colorChooser.destroy();
                PopupTool.fn.destroy.call(this);
            },
            update: function (value) {
                this.value(value);
            },
            value: function (value) {
                this.colorChooser.value(value);
            },
            _colorChange: function (e) {
                this.toolbar.action({
                    command: 'PropertyChangeCommand',
                    options: {
                        property: this.options.property,
                        value: e.sender.value()
                    }
                });
                this.popup.close();
            }
        });
        var ColorPickerButton = OverflowDialogButton.extend({
            init: function (options, toolbar) {
                options.iconName = 'text';
                OverflowDialogButton.fn.init.call(this, options, toolbar);
            },
            _click: function () {
                this.toolbar.dialog({
                    name: 'colorPicker',
                    options: {
                        title: this.options.property,
                        property: this.options.property
                    }
                });
            }
        });
        kendo.toolbar.registerComponent('colorPicker', ColorPicker, ColorPickerButton);
        var FONT_SIZES = [
            8,
            9,
            10,
            11,
            12,
            13,
            14,
            16,
            18,
            20,
            22,
            24,
            26,
            28,
            36,
            48,
            72
        ];
        var DEFAULT_FONT_SIZE = 12;
        var FontSize = kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                var comboBox = $('<input />').attr('aria-label', options.attributes.title).kendoComboBox({
                    change: this._valueChange.bind(this),
                    clearButton: false,
                    dataSource: options.fontSizes || FONT_SIZES,
                    value: DEFAULT_FONT_SIZE
                }).data('kendoComboBox');
                this.comboBox = comboBox;
                this.element = comboBox.wrapper;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this.element.width(options.width).attr({
                    'data-command': 'PropertyChangeCommand',
                    'data-property': options.property
                });
                this.element.data({
                    type: 'fontSize',
                    fontSize: this
                });
            },
            _valueChange: function (e) {
                this.toolbar.action({
                    command: 'PropertyChangeCommand',
                    options: {
                        property: this.options.property,
                        value: kendo.parseInt(e.sender.value())
                    }
                });
            },
            update: function (value) {
                this.value(kendo.parseInt(value) || DEFAULT_FONT_SIZE);
            },
            value: function (value) {
                if (value !== undefined) {
                    this.comboBox.value(value);
                } else {
                    return this.comboBox.value();
                }
            }
        });
        var FontSizeButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({
                    name: 'fontSize',
                    options: {
                        sizes: FONT_SIZES,
                        defaultSize: DEFAULT_FONT_SIZE
                    }
                });
            },
            update: function (value) {
                this._value = value || DEFAULT_FONT_SIZE;
                this.element.find('.k-text').text(this.message + ' (' + this._value + ') ...');
            }
        });
        kendo.toolbar.registerComponent('fontSize', FontSize, FontSizeButton);
        var FONT_FAMILIES = [
            'Arial',
            'Courier New',
            'Georgia',
            'Times New Roman',
            'Trebuchet MS',
            'Verdana'
        ];
        var DEFAULT_FONT_FAMILY = 'Arial';
        var FontFamily = DropDownTool.extend({
            init: function (options, toolbar) {
                DropDownTool.fn.init.call(this, options, toolbar);
                var ddl = this.dropDownList;
                ddl.setDataSource(options.fontFamilies || FONT_FAMILIES);
                ddl.value(DEFAULT_FONT_FAMILY);
                this.element.data({
                    type: 'fontFamily',
                    fontFamily: this
                });
            },
            update: function (value) {
                this.value(value || DEFAULT_FONT_FAMILY);
            }
        });
        var FontFamilyButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({
                    name: 'fontFamily',
                    options: {
                        fonts: FONT_FAMILIES,
                        defaultFont: DEFAULT_FONT_FAMILY
                    }
                });
            },
            update: function (value) {
                this._value = value || DEFAULT_FONT_FAMILY;
                this.element.find('.k-text').text(this.message + ' (' + this._value + ') ...');
            }
        });
        kendo.toolbar.registerComponent('fontFamily', FontFamily, FontFamilyButton);
        var defaultFormats = kendo.spreadsheet.formats = {
            automatic: null,
            number: '#,0.00',
            percent: '0.00%',
            financial: '_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)',
            currency: '$#,##0.00;[Red]$#,##0.00',
            date: 'm/d/yyyy',
            time: 'h:mm:ss AM/PM',
            dateTime: 'm/d/yyyy h:mm',
            duration: '[h]:mm:ss'
        };
        var Format = DropDownTool.extend({
            _revertTitle: function (e) {
                e.sender.value('');
                e.sender.wrapper.width('auto');
            },
            init: function (options, toolbar) {
                DropDownTool.fn.init.call(this, options, toolbar);
                var ddl = this.dropDownList;
                var icon = '<span class=\'k-icon k-i-' + options.iconClass + '\' style=\'line-height: 1em; width: 1.35em;\'></span>';
                ddl.bind('change', this._revertTitle.bind(this));
                ddl.bind('dataBound', this._revertTitle.bind(this));
                ddl.setOptions({
                    dataValueField: 'format',
                    dataTextField: 'name',
                    dataValuePrimitive: true,
                    valueTemplate: icon,
                    template: '# if (data.sample) { #' + '<span class=\'k-spreadsheet-sample\'>#: data.sample #</span>' + '# } #' + '#: data.name #'
                });
                ddl.text(icon);
                ddl.setDataSource([
                    {
                        format: defaultFormats.automatic,
                        name: MESSAGES.formatTypes.automatic
                    },
                    {
                        format: defaultFormats.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: 'align-left',
                    text: MESSAGES.alignmentButtons.justtifyLeft
                },
                {
                    property: 'textAlign',
                    value: 'center',
                    iconClass: 'align-center',
                    text: MESSAGES.alignmentButtons.justifyCenter
                },
                {
                    property: 'textAlign',
                    value: 'right',
                    iconClass: 'align-right',
                    text: MESSAGES.alignmentButtons.justifyRight
                },
                {
                    property: 'textAlign',
                    value: 'justify',
                    iconClass: 'align-justify',
                    text: MESSAGES.alignmentButtons.justifyFull
                },
                {
                    property: 'verticalAlign',
                    value: 'top',
                    iconClass: 'align-top',
                    text: MESSAGES.alignmentButtons.alignTop
                },
                {
                    property: 'verticalAlign',
                    value: 'center',
                    iconClass: 'align-middle',
                    text: MESSAGES.alignmentButtons.alignMiddle
                },
                {
                    property: 'verticalAlign',
                    value: 'bottom',
                    iconClass: 'align-bottom',
                    text: MESSAGES.alignmentButtons.alignBottom
                }
            ],
            destroy: function () {
                this.popup.element.off();
                PopupTool.fn.destroy.call(this);
            },
            update: function (range) {
                var textAlign = range.textAlign();
                var verticalAlign = range.verticalAlign();
                var element = this.popup.element;
                element.find('.k-button').removeClass('k-state-active');
                if (textAlign) {
                    element.find('[data-property=textAlign][data-value=' + textAlign + ']').addClass('k-state-active');
                }
                if (verticalAlign) {
                    element.find('[data-property=verticalAlign][data-value=' + verticalAlign + ']').addClass('k-state-active');
                }
            },
            _commandPalette: function () {
                var buttons = this.buttons;
                var element = $('<div />').appendTo(this.popup.element);
                buttons.forEach(function (options, index) {
                    var button = '<a title=\'' + options.text + '\' data-property=\'' + options.property + '\' data-value=\'' + options.value + '\' class=\'k-button k-button-icon\'>' + '<span class=\'k-icon k-i-' + options.iconClass + '\'></span>' + '</a>';
                    if (index !== 0 && buttons[index - 1].property !== options.property) {
                        element.append($('<span class=\'k-separator\' />'));
                    }
                    element.append(button);
                });
            },
            _action: function (button) {
                var property = button.attr('data-property');
                var value = button.attr('data-value');
                this.toolbar.action({
                    command: 'PropertyChangeCommand',
                    options: {
                        property: property,
                        value: value
                    }
                });
            }
        });
        var AlignmentButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'alignment' });
            }
        });
        kendo.toolbar.registerComponent('alignment', AlignmentTool, AlignmentButton);
        var MergeTool = PopupTool.extend({
            init: function (options, toolbar) {
                PopupTool.fn.init.call(this, options, toolbar);
                this._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: 'cells-merge',
                    text: MESSAGES.mergeButtons.mergeCells
                },
                {
                    value: 'horizontally',
                    iconClass: 'cells-merge-horizontally',
                    text: MESSAGES.mergeButtons.mergeHorizontally
                },
                {
                    value: 'vertically',
                    iconClass: 'cells-merge-vertically',
                    text: MESSAGES.mergeButtons.mergeVertically
                },
                {
                    value: 'unmerge',
                    iconClass: 'table-unmerge',
                    text: MESSAGES.mergeButtons.unmerge
                }
            ],
            destroy: function () {
                this.popup.element.off();
                PopupTool.fn.destroy.call(this);
            },
            _commandPalette: function () {
                var element = $('<div />').appendTo(this.popup.element);
                this.buttons.forEach(function (options) {
                    var button = '<a title=\'' + options.text + '\' data-value=\'' + options.value + '\' class=\'k-button k-button-icontext\'>' + '<span class=\'k-icon k-i-' + options.iconClass + '\'></span>' + options.text + '</a>';
                    element.append(button);
                });
            },
            _action: function (button) {
                var value = button.attr('data-value');
                this.toolbar.action({
                    command: 'MergeCellCommand',
                    options: { value: value }
                });
            }
        });
        var MergeButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'merge' });
            }
        });
        kendo.toolbar.registerComponent('merge', MergeTool, MergeButton);
        var FreezeTool = PopupTool.extend({
            init: function (options, toolbar) {
                PopupTool.fn.init.call(this, options, toolbar);
                this._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: 'pane-freeze',
                    text: MESSAGES.freezeButtons.freezePanes
                },
                {
                    value: 'rows',
                    iconClass: 'row-freeze',
                    text: MESSAGES.freezeButtons.freezeRows
                },
                {
                    value: 'columns',
                    iconClass: 'column-freeze',
                    text: MESSAGES.freezeButtons.freezeColumns
                },
                {
                    value: 'unfreeze',
                    iconClass: 'table-unmerge',
                    text: MESSAGES.freezeButtons.unfreeze
                }
            ],
            destroy: function () {
                this.popup.element.off();
                PopupTool.fn.destroy.call(this);
            },
            _commandPalette: function () {
                var element = $('<div />').appendTo(this.popup.element);
                this.buttons.forEach(function (options) {
                    var button = '<a title=\'' + options.text + '\' data-value=\'' + options.value + '\' class=\'k-button k-button-icontext\'>' + '<span class=\'k-icon k-i-' + options.iconClass + '\'></span>' + options.text + '</a>';
                    element.append(button);
                });
            },
            _action: function (button) {
                var value = button.attr('data-value');
                this.toolbar.action({
                    command: 'FreezePanesCommand',
                    options: { value: value }
                });
            }
        });
        var FreezeButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'freeze' });
            }
        });
        kendo.toolbar.registerComponent('freeze', FreezeTool, FreezeButton);
        var Sort = DropDownTool.extend({
            _revertTitle: function (e) {
                e.sender.value('');
                e.sender.wrapper.width('auto');
            },
            init: function (options, toolbar) {
                DropDownTool.fn.init.call(this, options, toolbar);
                var ddl = this.dropDownList;
                ddl.bind('change', this._revertTitle.bind(this));
                ddl.bind('dataBound', this._revertTitle.bind(this));
                ddl.setOptions({
                    valueTemplate: '<span class=\'k-icon k-i-' + options.iconClass + '\' style=\'line-height: 1em; width: 1.35em;\'></span>',
                    template: '<span class=\'k-icon k-i-#= iconClass #\' style=\'line-height: 1em; width: 1.35em;\'></span>#=text#',
                    dataTextField: 'text',
                    dataValueField: 'value'
                });
                ddl.setDataSource([
                    {
                        value: 'asc',
                        sheet: false,
                        text: MESSAGES.sortButtons.sortRangeAsc,
                        iconClass: 'sort-asc'
                    },
                    {
                        value: 'desc',
                        sheet: false,
                        text: MESSAGES.sortButtons.sortRangeDesc,
                        iconClass: 'sort-desc'
                    }
                ]);
                ddl.select(0);
                this.element.data({
                    type: 'sort',
                    sort: this
                });
            },
            _change: function (e) {
                var instance = e.sender;
                var dataItem = instance.dataItem();
                if (dataItem) {
                    this.toolbar.action({
                        command: 'SortCommand',
                        options: {
                            value: dataItem.value,
                            sheet: dataItem.sheet
                        }
                    });
                }
            },
            value: $.noop
        });
        var SortButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({ name: 'sort' });
            }
        });
        kendo.toolbar.registerComponent('sort', Sort, SortButton);
        var Filter = kendo.toolbar.ToolBarButton.extend({
            init: function (options, toolbar) {
                options.showText = 'overflow';
                kendo.toolbar.ToolBarButton.fn.init.call(this, options, toolbar);
                this.element.on('click', this._click.bind(this));
                this.element.data({
                    type: 'filter',
                    filter: this
                });
            },
            _click: function () {
                this.toolbar.action({ command: 'FilterCommand' });
            },
            update: function (value) {
                this.toggle(value);
            }
        });
        var FilterButton = OverflowDialogButton.extend({
            init: function (options, toolbar) {
                OverflowDialogButton.fn.init.call(this, options, toolbar);
                this.element.data({
                    type: 'filter',
                    filter: this
                });
            },
            _click: function () {
                this.toolbar.action({ command: 'FilterCommand' });
            },
            update: function (value) {
                this.toggle(value);
            }
        });
        kendo.toolbar.registerComponent('filter', Filter, FilterButton);
        var Open = kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                this.toolbar = toolbar;
                this.element = $('<div class=\'k-button k-upload-button k-button-icon\'>' + '<span class=\'k-icon k-i-folder-open\' />' + '</div>').data('instance', this);
                this._title = options.attributes.title;
                this._reset();
            },
            _reset: function () {
                this.element.remove('input');
                $('<input type=\'file\' autocomplete=\'off\' accept=\'.xlsx\'/>').attr('title', this._title).attr('aria-label', this._title).one('change', this._change.bind(this)).appendTo(this.element);
            },
            _change: function (e) {
                this.toolbar.action({
                    command: 'OpenCommand',
                    options: { file: e.target.files[0] }
                });
                this._reset();
            }
        });
        kendo.toolbar.registerComponent('open', Open);
        kendo.spreadsheet.TabStrip = kendo.ui.TabStrip.extend({
            init: function (element, options) {
                kendo.ui.TabStrip.fn.init.call(this, element, options);
                element.addClass('k-spreadsheet-tabstrip');
                this._quickAccessButtons();
                this.toolbars = {};
                var tabs = options.dataSource;
                this.contentElements.each(function (idx, element) {
                    this._toolbar($(element), tabs[idx].id, options.toolbarOptions[tabs[idx].id]);
                }.bind(this));
                this.one('activate', function () {
                    this.toolbars[this.options.dataSource[0].id].resize();
                });
            },
            events: kendo.ui.TabStrip.fn.events.concat([
                'action',
                'dialog'
            ]),
            destroy: function () {
                this.quickAccessToolBar.off('click');
                kendo.ui.TabStrip.fn.destroy.call(this);
                for (var name in this.toolbars) {
                    this.toolbars[name].destroy();
                }
            },
            action: function (args) {
                this.trigger('action', args);
            },
            dialog: function (args) {
                this.trigger('dialog', args);
            },
            refreshTools: function (range) {
                var toolbars = this.toolbars;
                for (var name in toolbars) {
                    if (toolbars.hasOwnProperty(name)) {
                        toolbars[name].refresh(range);
                    }
                }
            },
            _quickAccessButtons: function () {
                var buttons = [
                    {
                        title: MESSAGES.quickAccess.undo,
                        iconClass: 'undo',
                        action: 'undo'
                    },
                    {
                        title: MESSAGES.quickAccess.redo,
                        iconClass: 'redo',
                        action: 'redo'
                    }
                ];
                var buttonTemplate = kendo.template('<a href=\'\\#\' title=\'#= title #\' data-action=\'#= action #\' class=\'k-button k-button-icon\' aria-label=\'#= title #\'><span class=\'k-icon k-i-#=iconClass#\'></span></a>');
                this.quickAccessToolBar = $('<div />', {
                    'class': 'k-spreadsheet-quick-access-toolbar',
                    'html': kendo.render(buttonTemplate, buttons)
                }).insertBefore(this.wrapper);
                this.quickAccessToolBar.on('click', '.k-button', function (e) {
                    e.preventDefault();
                    var action = $(e.currentTarget).attr('data-action');
                    this.action({ action: action });
                }.bind(this));
                this.quickAccessAdjust();
            },
            quickAccessAdjust: function () {
                this.tabGroup.css('padding-left', kendo._outerWidth(this.quickAccessToolBar));
            },
            _toolbar: function (container, name, tools) {
                var element;
                var options;
                if (this.toolbars[name]) {
                    this.toolbars[name].destroy();
                    container.children('.k-toolbar').remove();
                }
                if (tools) {
                    element = container.html('<div />').children('div');
                    options = {
                        tools: typeof tools === 'boolean' ? undefined : tools,
                        toolbarName: name,
                        action: this.action.bind(this),
                        dialog: this.dialog.bind(this)
                    };
                    this.toolbars[name] = new kendo.spreadsheet.ToolBar(element, options);
                }
            }
        });
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/dialogs', [
        'kendo.core',
        'kendo.binder',
        'kendo.validator'
    ], f);
}(function () {
    (function (kendo) {
        if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
            return;
        }
        var $ = kendo.jQuery;
        var ObservableObject = kendo.data.ObservableObject;
        var MESSAGES = kendo.spreadsheet.messages.dialogs = {
            apply: 'Apply',
            save: 'Save',
            cancel: 'Cancel',
            remove: 'Remove',
            retry: 'Retry',
            revert: 'Revert',
            okText: 'OK',
            formatCellsDialog: {
                title: 'Format',
                categories: {
                    number: 'Number',
                    currency: 'Currency',
                    date: 'Date'
                }
            },
            fontFamilyDialog: { title: 'Font' },
            fontSizeDialog: { title: 'Font size' },
            bordersDialog: { title: 'Borders' },
            alignmentDialog: {
                title: 'Alignment',
                buttons: {
                    justtifyLeft: 'Align left',
                    justifyCenter: 'Center',
                    justifyRight: 'Align right',
                    justifyFull: 'Justify',
                    alignTop: 'Align top',
                    alignMiddle: 'Align middle',
                    alignBottom: 'Align bottom'
                }
            },
            mergeDialog: {
                title: 'Merge cells',
                buttons: {
                    mergeCells: 'Merge all',
                    mergeHorizontally: 'Merge horizontally',
                    mergeVertically: 'Merge vertically',
                    unmerge: 'Unmerge'
                }
            },
            freezeDialog: {
                title: 'Freeze panes',
                buttons: {
                    freezePanes: 'Freeze panes',
                    freezeRows: 'Freeze rows',
                    freezeColumns: 'Freeze columns',
                    unfreeze: 'Unfreeze panes'
                }
            },
            confirmationDialog: {
                text: 'Are you sure you want to remove this sheet?',
                title: 'Sheet remove'
            },
            validationDialog: {
                title: 'Data Validation',
                hintMessage: 'Please enter a valid {0} value {1}.',
                hintTitle: 'Validation {0}',
                criteria: {
                    any: 'Any value',
                    number: 'Number',
                    text: 'Text',
                    date: 'Date',
                    custom: 'Custom Formula',
                    list: 'List'
                },
                comparers: {
                    greaterThan: 'greater than',
                    lessThan: 'less than',
                    between: 'between',
                    notBetween: 'not between',
                    equalTo: 'equal to',
                    notEqualTo: 'not equal to',
                    greaterThanOrEqualTo: 'greater than or equal to',
                    lessThanOrEqualTo: 'less than or equal to'
                },
                comparerMessages: {
                    greaterThan: 'greater than {0}',
                    lessThan: 'less than {0}',
                    between: 'between {0} and {1}',
                    notBetween: 'not between {0} and {1}',
                    equalTo: 'equal to {0}',
                    notEqualTo: 'not equal to {0}',
                    greaterThanOrEqualTo: 'greater than or equal to {0}',
                    lessThanOrEqualTo: 'less than or equal to {0}',
                    custom: 'that satisfies the formula: {0}'
                },
                labels: {
                    criteria: 'Criteria',
                    comparer: 'Comparer',
                    min: 'Min',
                    max: 'Max',
                    value: 'Value',
                    start: 'Start',
                    end: 'End',
                    onInvalidData: 'On invalid data',
                    rejectInput: 'Reject input',
                    showWarning: 'Show warning',
                    showHint: 'Show hint',
                    hintTitle: 'Hint title',
                    hintMessage: 'Hint message',
                    ignoreBlank: 'Ignore blank',
                    showListButton: 'Display button to show list',
                    showCalendarButton: 'Display button to show calendar'
                },
                placeholders: {
                    typeTitle: 'Type title',
                    typeMessage: 'Type message'
                }
            },
            exportAsDialog: {
                title: 'Export...',
                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 k-popup-edit-form\' />').addClass(this.options.className || '').append(kendo.template(this.options.template)({
                        messages: kendo.spreadsheet.messages.dialogs || MESSAGES,
                        errors: this.options.errors
                    })).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-edit-form-container\'>' + '<div class=\'k-root-tabs\' data-role=\'tabstrip\' ' + 'data-text-field=\'name\' ' + 'data-bind=\'source: categories, value: categoryFilter\' ' + 'data-animation=\'false\' />' + '<div class=\'k-spreadsheet-preview\' data-bind=\'text: preview\' />' + '<script type=\'text/x-kendo-template\' id=\'format-item-template\'>' + '\\#: data.name \\#' + '</script>' + '<select data-role=\'dropdownlist\' class=\'k-format-filter\' ' + 'data-text-field=\'description\' ' + 'data-value-field=\'value.name\' ' + 'data-bind=\'visible: showCurrencyFilter, value: currency, source: currencies\' />' + '<ul data-role=\'staticlist\' tabindex=\'0\' ' + 'class=\'k-list k-reset\' ' + 'data-template=\'format-item-template\' ' + 'data-value-primitive=\'true\' ' + 'data-value-field=\'value\' ' + 'data-bind=\'source: formats, value: format\' />' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>#: messages.apply #</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>#: messages.cancel #</button>' + '</div>' + '</div>'
            },
            _generateFormats: function () {
                var options = this.options;
                if (!options.currencies) {
                    options.currencies = FormatCellsDialog.currenciesFrom(kendo.cultures);
                }
                if (!options.numberFormats) {
                    options.numberFormats = [
                        {
                            value: '#.00%',
                            name: '100.00%'
                        },
                        {
                            value: '#%',
                            name: '100%'
                        },
                        {
                            value: '#.00',
                            name: '1024.00'
                        },
                        {
                            value: '#,###.00',
                            name: '1,024.00'
                        }
                    ];
                }
                if (!options.dateFormats) {
                    var calendarPatterns = kendo.cultures.current.calendars.standard.patterns;
                    options.dateFormats = uniqueBy('value', $.map(calendarPatterns, function (format) {
                        format = FormatCellsViewModel.convert.date(format);
                        if (!format) {
                            return;
                        }
                        return {
                            value: format,
                            name: formattedValue(34567.7678, format)
                        };
                    }));
                }
            },
            open: function (range) {
                var options = this.options;
                var value = range.value();
                var categories = options.categories.slice(0);
                var element;
                this.viewModel = new FormatCellsViewModel({
                    currencies: options.currencies.slice(0),
                    allFormats: {
                        numberFormats: options.numberFormats.slice(0),
                        dateFormats: options.dateFormats.slice(0)
                    },
                    categories: categories,
                    format: range.format(),
                    category: value instanceof Date ? categories[2] : categories[0],
                    apply: this.apply.bind(this),
                    close: this.close.bind(this),
                    value: value
                });
                SpreadsheetDialog.fn.open.call(this);
                element = this.dialog().element;
                kendo.bind(element, this.viewModel);
                var currencyFilter = element.find('select.k-format-filter').data('kendoDropDownList');
                if (options.currencies.length > 10) {
                    currencyFilter.setOptions({ filter: 'contains' });
                }
                element.find(kendo.roleSelector('staticlist')).parent().addClass('k-list-wrapper');
            },
            apply: function () {
                var format = this.viewModel.format;
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: 'format',
                        value: format
                    }
                });
            }
        });
        FormatCellsDialog.currenciesFrom = function (cultures) {
            return uniqueBy('description', $.map(cultures, function (culture, name) {
                if (!/-/.test(name)) {
                    return;
                }
                var currency = culture.numberFormat.currency;
                var description = kendo.format('{0} ({1}, {2})', currency.name, currency.abbr, currency.symbol);
                return {
                    description: description,
                    value: currency
                };
            }));
        };
        kendo.spreadsheet.dialogs.register('formatCells', FormatCellsDialog);
        kendo.spreadsheet.dialogs.FormatCellsDialog = FormatCellsDialog;
        var MessageDialog = SpreadsheetDialog.extend({
            options: {
                className: 'k-spreadsheet-message',
                title: '',
                messageId: '',
                text: '',
                template: '<div class=\'k-spreadsheet-message-content\' data-bind=\'text: text\' />' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: close\'>' + '#= messages.okText #' + '</button>' + '</div>'
            },
            open: function () {
                SpreadsheetDialog.fn.open.call(this);
                var options = this.options;
                var text = options.text;
                if (options.messageId) {
                    text = kendo.getter(options.messageId, true)(kendo.spreadsheet.messages.dialogs);
                }
                kendo.bind(this.dialog().element, {
                    text: text,
                    close: this.close.bind(this)
                });
            }
        });
        kendo.spreadsheet.dialogs.register('message', MessageDialog);
        var ConfirmationDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.confirmationDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    text: messages.text
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
            },
            options: {
                className: 'k-spreadsheet-message',
                messageId: '',
                template: '<div class=\'k-spreadsheet-message-content\' data-bind=\'text: text\' />' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: confirm\'>' + '#= messages.okText #' + '</button>' + '<button class=\'k-button\' data-bind=\'click: cancel\'>' + '#= messages.cancel #' + '</button>' + '</div>'
            },
            open: function () {
                SpreadsheetDialog.fn.open.call(this);
                var options = this.options;
                var text = options.text;
                if (options.messageId) {
                    text = kendo.getter(options.messageId, true)(kendo.spreadsheet.messages.dialogs);
                }
                kendo.bind(this.dialog().element, {
                    text: text,
                    confirm: this.confirm.bind(this),
                    cancel: this.close.bind(this)
                });
            },
            isConfirmed: function () {
                return this._confirmed;
            },
            confirm: function () {
                this._confirmed = true;
                this.close();
            }
        });
        kendo.spreadsheet.dialogs.register('confirmation', ConfirmationDialog);
        var ValidationErrorDialog = SpreadsheetDialog.extend({
            options: {
                className: 'k-spreadsheet-message',
                title: '',
                messageId: '',
                text: '',
                template: '<div class=\'k-spreadsheet-message-content\' data-bind=\'text: text\' />' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: retry\'>' + '#= messages.retry #' + '</button>' + '<button class=\'k-button\' data-bind=\'click: cancel\'>' + '#= messages.cancel #' + '</button>' + '</div>'
            },
            open: function () {
                SpreadsheetDialog.fn.open.call(this);
                var options = this.options;
                var text = options.text;
                if (options.messageId) {
                    text = kendo.getter(options.messageId, true)(kendo.spreadsheet.messages.dialogs);
                }
                kendo.bind(this.dialog().element, {
                    text: text,
                    retry: this.retry.bind(this),
                    cancel: this.close.bind(this)
                });
            },
            retry: function () {
                this._retry = true;
                this.close();
            }
        });
        kendo.spreadsheet.dialogs.register('validationError', ValidationErrorDialog);
        var FontFamilyDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.fontFamilyDialog || MESSAGES;
                SpreadsheetDialog.fn.init.call(this, $.extend({ title: messages.title }, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                var fonts = this.options.fonts;
                var defaultFont = this.options.defaultFont;
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: fonts }),
                    template: '#: data #',
                    value: defaultFont,
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: 'fontFamily',
                        value: e.sender.value()[0]
                    }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('fontFamily', FontFamilyDialog);
        var FontSizeDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.fontSizeDialog || MESSAGES;
                SpreadsheetDialog.fn.init.call(this, $.extend({ title: messages.title }, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                var sizes = this.options.sizes;
                var defaultSize = this.options.defaultSize;
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: sizes }),
                    template: '#: data #',
                    value: defaultSize,
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: 'fontSize',
                        value: kendo.parseInt(e.sender.value()[0])
                    }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('fontSize', FontSizeDialog);
        var BordersDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.bordersDialog || MESSAGES;
                SpreadsheetDialog.fn.init.call(this, $.extend({ title: messages.title }, options));
                this.element = this.dialog().element;
                this._borderPalette();
                this.viewModel = kendo.observable({
                    apply: this.apply.bind(this),
                    close: this.close.bind(this)
                });
                kendo.bind(this.element.find('.k-action-buttons'), this.viewModel);
            },
            options: {
                width: 177,
                template: '<div></div>' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>#: messages.apply #</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>#: messages.cancel #</button>' + '</div>'
            },
            apply: function () {
                SpreadsheetDialog.fn.apply.call(this);
                var state = this.value();
                this.trigger('action', {
                    command: 'BorderChangeCommand',
                    options: {
                        border: state.type,
                        style: {
                            size: 1,
                            color: state.color
                        }
                    }
                });
            },
            _borderPalette: function () {
                var element = this.dialog().element.find('div:first');
                this.borderPalette = new kendo.spreadsheet.BorderPalette(element, { change: this.value.bind(this) });
            },
            value: function (state) {
                if (state === undefined) {
                    return this._state;
                } else {
                    this._state = state;
                }
            }
        });
        kendo.spreadsheet.dialogs.register('borders', BordersDialog);
        var ColorChooser = SpreadsheetDialog.extend({
            init: function (options) {
                SpreadsheetDialog.fn.init.call(this, options);
                this.element = this.dialog().element;
                this.property = options.property;
                this.options.title = options.title;
                this.viewModel = kendo.observable({
                    apply: this.apply.bind(this),
                    close: this.close.bind(this)
                });
                kendo.bind(this.element.find('.k-action-buttons'), this.viewModel);
            },
            options: { template: '<div></div>' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: apply\'>#: messages.apply #</button>' + '<button class=\'k-button\' data-bind=\'click: close\'>#: messages.cancel #</button>' + '</div>' },
            apply: function () {
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: this.property,
                        value: this.value()
                    }
                });
            },
            value: function (e) {
                if (e === undefined) {
                    return this._value;
                } else {
                    this._value = e.value;
                }
            }
        });
        var ColorPickerDialog = ColorChooser.extend({
            init: function (options) {
                options.width = 177;
                ColorChooser.fn.init.call(this, options);
                this._colorPalette();
            },
            _colorPalette: function () {
                var element = this.dialog().element.find('div:first');
                this.colorPalette = element.kendoColorPalette({
                    palette: [
                        '#ffffff',
                        '#000000',
                        '#d6ecff',
                        '#4e5b6f',
                        '#7fd13b',
                        '#ea157a',
                        '#feb80a',
                        '#00addc',
                        '#738ac8',
                        '#1ab39f',
                        '#f2f2f2',
                        '#7f7f7f',
                        '#a7d6ff',
                        '#d9dde4',
                        '#e5f5d7',
                        '#fad0e4',
                        '#fef0cd',
                        '#c5f2ff',
                        '#e2e7f4',
                        '#c9f7f1',
                        '#d8d8d8',
                        '#595959',
                        '#60b5ff',
                        '#b3bcca',
                        '#cbecb0',
                        '#f6a1c9',
                        '#fee29c',
                        '#8be6ff',
                        '#c7d0e9',
                        '#94efe3',
                        '#bfbfbf',
                        '#3f3f3f',
                        '#007dea',
                        '#8d9baf',
                        '#b2e389',
                        '#f272af',
                        '#fed46b',
                        '#51d9ff',
                        '#aab8de',
                        '#5fe7d5',
                        '#a5a5a5',
                        '#262626',
                        '#003e75',
                        '#3a4453',
                        '#5ea226',
                        '#af0f5b',
                        '#c58c00',
                        '#0081a5',
                        '#425ea9',
                        '#138677',
                        '#7f7f7f',
                        '#0c0c0c',
                        '#00192e',
                        '#272d37',
                        '#3f6c19',
                        '#750a3d',
                        '#835d00',
                        '#00566e',
                        '#2c3f71',
                        '#0c594f'
                    ],
                    change: this.value.bind(this)
                }).data('kendoColorPalette');
            }
        });
        kendo.spreadsheet.dialogs.register('colorPicker', ColorPickerDialog);
        var CustomColorDialog = ColorChooser.extend({
            init: function (options) {
                options.width = 268;
                ColorChooser.fn.init.call(this, options);
                this.dialog().setOptions({ animation: false });
                this.dialog().one('activate', this._colorPicker.bind(this));
            },
            _colorPicker: function () {
                var element = this.dialog().element.find('div:first');
                this.colorPicker = element.kendoFlatColorPicker({ change: this.value.bind(this) }).data('kendoFlatColorPicker');
            }
        });
        kendo.spreadsheet.dialogs.register('customColor', CustomColorDialog);
        var AlignmentDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.alignmentDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    buttons: [
                        {
                            property: 'textAlign',
                            value: 'left',
                            iconClass: 'align-left',
                            text: messages.buttons.justtifyLeft
                        },
                        {
                            property: 'textAlign',
                            value: 'center',
                            iconClass: 'align-center',
                            text: messages.buttons.justifyCenter
                        },
                        {
                            property: 'textAlign',
                            value: 'right',
                            iconClass: 'align-right',
                            text: messages.buttons.justifyRight
                        },
                        {
                            property: 'textAlign',
                            value: 'justify',
                            iconClass: 'align-justify',
                            text: messages.buttons.justifyFull
                        },
                        {
                            property: 'verticalAlign',
                            value: 'top',
                            iconClass: 'align-top',
                            text: messages.buttons.alignTop
                        },
                        {
                            property: 'verticalAlign',
                            value: 'center',
                            iconClass: 'align-middle',
                            text: messages.buttons.alignMiddle
                        },
                        {
                            property: 'verticalAlign',
                            value: 'bottom',
                            iconClass: 'align-bottom',
                            text: messages.buttons.alignBottom
                        }
                    ]
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: this.options.buttons }),
                    template: '<a title=\'#=text#\' data-property=\'#=property#\' data-value=\'#=value#\'>' + '<span class=\'k-icon k-i-#=iconClass#\'></span>' + '#=text#' + '</a>',
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                var dataItem = e.sender.value()[0];
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'PropertyChangeCommand',
                    options: {
                        property: dataItem.property,
                        value: dataItem.value
                    }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('alignment', AlignmentDialog);
        var MergeDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.mergeDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    buttons: [
                        {
                            value: 'cells',
                            iconClass: 'cells-merge',
                            text: messages.buttons.mergeCells
                        },
                        {
                            value: 'horizontally',
                            iconClass: 'cells-merge-horizontally',
                            text: messages.buttons.mergeHorizontally
                        },
                        {
                            value: 'vertically',
                            iconClass: 'cells-merge-vertically',
                            text: messages.buttons.mergeVertically
                        },
                        {
                            value: 'unmerge',
                            iconClass: 'table-unmerge',
                            text: messages.buttons.unmerge
                        }
                    ]
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: this.options.buttons }),
                    template: '<a title=\'#=text#\' data-value=\'#=value#\'>' + '<span class=\'k-icon k-icon k-i-#=iconClass#\'></span>#=text#' + '</a>',
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                var dataItem = e.sender.value()[0];
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'MergeCellCommand',
                    options: { value: dataItem.value }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('merge', MergeDialog);
        var FreezeDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.freezeDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    buttons: [
                        {
                            value: 'panes',
                            iconClass: 'pane-freeze',
                            text: messages.buttons.freezePanes
                        },
                        {
                            value: 'rows',
                            iconClass: 'row-freeze',
                            text: messages.buttons.freezeRows
                        },
                        {
                            value: 'columns',
                            iconClass: 'column-freeze',
                            text: messages.buttons.freezeColumns
                        },
                        {
                            value: 'unfreeze',
                            iconClass: 'table-unmerge',
                            text: messages.buttons.unfreeze
                        }
                    ]
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
                this._list();
            },
            options: { template: '<ul class=\'k-list k-reset\'></ul>' },
            _list: function () {
                var ul = this.dialog().element.find('ul');
                this.list = new kendo.ui.StaticList(ul, {
                    dataSource: new kendo.data.DataSource({ data: this.options.buttons }),
                    template: '<a title=\'#=text#\' data-value=\'#=value#\'>' + '<span class=\'k-icon k-icon k-i-#=iconClass#\'></span>#=text#' + '</a>',
                    change: this.apply.bind(this)
                });
                this.list.dataSource.fetch();
            },
            apply: function (e) {
                var dataItem = e.sender.value()[0];
                SpreadsheetDialog.fn.apply.call(this);
                this.trigger('action', {
                    command: 'FreezePanesCommand',
                    options: { value: dataItem.value }
                });
            }
        });
        kendo.spreadsheet.dialogs.register('freeze', FreezeDialog);
        var ValidationViewModel = kendo.spreadsheet.ValidationCellsViewModel = ObservableObject.extend({
            init: function (options) {
                ObservableObject.fn.init.call(this, options);
                this.bind('change', function (e) {
                    if (e.field === 'criterion') {
                        this.reset();
                        if (this.criterion === 'custom' || this.criterion === 'list') {
                            this.setHintMessageTemplate();
                        }
                    }
                    if (e.field === 'comparer') {
                        this.setHintMessageTemplate();
                    }
                    if ((e.field == 'hintMessage' || e.field == 'hintTitle') && !this._mute) {
                        this.shouldBuild = false;
                    }
                    if ((e.field == 'from' || e.field == 'to' || e.field == 'hintMessageTemplate' || e.field == 'type') && this.shouldBuild) {
                        this.buildMessages();
                    }
                }.bind(this));
                this.reset();
            },
            buildMessages: function () {
                this._mute = true;
                this.set('hintTitle', this.hintTitleTemplate ? kendo.format(this.hintTitleTemplate, this.type) : '');
                this.set('hintMessage', this.hintMessageTemplate ? kendo.format(this.hintMessageTemplate, this.from, this.to) : '');
                this._mute = false;
            },
            reset: function () {
                this.setComparers();
                this.set('comparer', this.comparers[0].type);
                this.set('from', null);
                this.set('to', null);
                this.set('useCustomMessages', false);
                this.shouldBuild = true;
                this.hintTitleTemplate = this.defaultHintTitle;
                this.buildMessages();
            },
            setComparers: function () {
                var all = this.defaultComparers;
                var comparers = [];
                if (this.criterion === 'text') {
                    var text_comparers = [
                        'equalTo',
                        'notEqualTo'
                    ];
                    for (var idx = 0; idx < all.length; idx++) {
                        if (text_comparers[0] == all[idx].type) {
                            comparers.push(all[idx]);
                            text_comparers.shift();
                        }
                    }
                } else {
                    comparers = all.slice();
                }
                this.set('comparers', comparers);
            },
            setHintMessageTemplate: function () {
                if (this.criterion !== 'custom' && this.criterion !== 'list') {
                    this.set('hintMessageTemplate', kendo.format(this.defaultHintMessage, this.criterion, this.comparerMessages[this.comparer]));
                } else {
                    this.set('hintMessageTemplate', '');
                    this.set('hintMessage', '');
                }
            },
            isAny: function () {
                return this.get('criterion') === 'any';
            },
            isNumber: function () {
                return this.get('criterion') === 'number';
            },
            showToForNumber: function () {
                return this.showTo() && this.isNumber();
            },
            showToForDate: function () {
                return this.showTo() && this.isDate();
            },
            isText: function () {
                return this.get('criterion') === 'text';
            },
            isDate: function () {
                return this.get('criterion') === 'date';
            },
            isList: function () {
                return this.get('criterion') === 'list';
            },
            isCustom: function () {
                return this.get('criterion') === 'custom';
            },
            showRemove: function () {
                return this.get('hasValidation');
            },
            showTo: function () {
                return this.get('comparer') == 'between' || this.get('comparer') == 'notBetween';
            },
            update: function (validation) {
                this.set('hasValidation', !!validation);
                if (validation) {
                    this.fromValidationObject(validation);
                }
            },
            fromValidationObject: function (validation) {
                this.set('criterion', validation.dataType);
                this.set('comparer', validation.comparerType);
                this.set('from', validation.from);
                this.set('to', validation.to);
                this.set('type', validation.type);
                this.set('ignoreBlank', validation.allowNulls);
                this.set('showButton', validation.showButton);
                if (validation.messageTemplate || validation.titleTemplate) {
                    this.hintMessageTemplate = validation.messageTemplate;
                    this.hintMessage = validation.messageTemplate;
                    this.hintTitleTemplate = validation.titleTemplate;
                    this.hintTitle = validation.titleTemplate;
                    this.useCustomMessages = true;
                    this.buildMessages();
                } else {
                    this.useCustomMessages = false;
                }
            },
            toValidationObject: function () {
                if (this.criterion === 'any') {
                    return null;
                }
                var options = {
                    type: this.type,
                    dataType: this.criterion,
                    comparerType: this.comparer,
                    from: this.from,
                    to: this.to,
                    allowNulls: this.ignoreBlank,
                    showButton: this.showButton
                };
                if (this.useCustomMessages) {
                    options.messageTemplate = this.shouldBuild ? this.hintMessageTemplate : this.hintMessage;
                    options.titleTemplate = this.hintTitle;
                }
                return options;
            }
        });
        var ValidationDialog = SpreadsheetDialog.extend({
            init: function (options) {
                var messages = kendo.spreadsheet.messages.dialogs.validationDialog || MESSAGES;
                var defaultOptions = {
                    title: messages.title,
                    hintMessage: messages.hintMessage,
                    hintTitle: messages.hintTitle,
                    criteria: [
                        {
                            type: 'any',
                            name: messages.criteria.any
                        },
                        {
                            type: 'number',
                            name: messages.criteria.number
                        },
                        {
                            type: 'text',
                            name: messages.criteria.text
                        },
                        {
                            type: 'date',
                            name: messages.criteria.date
                        },
                        {
                            type: 'custom',
                            name: messages.criteria.custom
                        },
                        {
                            type: 'list',
                            name: messages.criteria.list
                        }
                    ],
                    comparers: [
                        {
                            type: 'greaterThan',
                            name: messages.comparers.greaterThan
                        },
                        {
                            type: 'lessThan',
                            name: messages.comparers.lessThan
                        },
                        {
                            type: 'between',
                            name: messages.comparers.between
                        },
                        {
                            type: 'notBetween',
                            name: messages.comparers.notBetween
                        },
                        {
                            type: 'equalTo',
                            name: messages.comparers.equalTo
                        },
                        {
                            type: 'notEqualTo',
                            name: messages.comparers.notEqualTo
                        },
                        {
                            type: 'greaterThanOrEqualTo',
                            name: messages.comparers.greaterThanOrEqualTo
                        },
                        {
                            type: 'lessThanOrEqualTo',
                            name: messages.comparers.lessThanOrEqualTo
                        }
                    ],
                    comparerMessages: messages.comparerMessages
                };
                SpreadsheetDialog.fn.init.call(this, $.extend(defaultOptions, options));
            },
            options: {
                width: 450,
                criterion: 'any',
                type: 'reject',
                ignoreBlank: true,
                showButton: true,
                useCustomMessages: false,
                errorTemplate: '<div class="k-widget k-tooltip k-tooltip-validation" style="margin:0.5em"><span class="k-icon k-i-warning"> </span>' + '#= message #<div class="k-callout k-callout-n"></div></div>',
                template: '<div class="k-edit-form-container">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.criteria #:</label></div>' + '<div class="k-edit-field">' + '<select data-role="dropdownlist" ' + '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 ImportErrorDialog = MessageDialog.extend({
            options: {
                width: 640,
                title: 'Errors in import',
                template: '<div class=\'k-spreadsheet-message-content k-spreadsheet-import-errors\'>' + '<div class=\'k--header-message\'>We encountered #= errors.length # errors while reading this file.  Please be aware that some formulas might be missing, or contain invalid results.</div>' + '<div class=\'k--errors\'>' + '<table>' + '<thead>' + '<tr><th>Context</th><th>Error message</th></tr>' + '</thead>' + '# for (var i = 0; i < errors.length; ++i) { #' + '# var err = errors[i]; #' + '<tr><td>#: err.context #</td><td>#: err.error #</td></tr>' + '# } #' + '</table>' + '</div>' + '</div>' + '<div class=\'k-action-buttons\'>' + '<button class=\'k-button k-primary\' data-bind=\'click: close\'>' + '#: messages.okText #' + '</button>' + '</div>'
            }
        });
        kendo.spreadsheet.dialogs.register('importError', ImportErrorDialog);
        var UseKeyboardDialog = MessageDialog.extend({
            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('afterDeleteRow', this._sheetDeleteRowHandler).bind('afterInsertRow', this._sheetInsertRowHandler);
            },
            _sheetInsertRow: function (e) {
                if (e.index !== undefined) {
                    this.dataSource.insert(Math.max(e.index - 1, 0), {});
                }
            },
            _sheetDeleteRow: function (e) {
                if (e.index !== undefined) {
                    var dataSource = this.dataSource;
                    var model = dataSource.view()[e.index - 1];
                    if (model) {
                        dataSource.remove(model);
                    }
                }
            },
            _header: function () {
                this.sheet.batch(function () {
                    this.columns.forEach(function (column, index) {
                        this.sheet.range(0, index).value(column.title);
                    }.bind(this));
                }.bind(this));
            },
            _sheetChange: function (e) {
                if (e.insertRow || e.deleteRow) {
                    return;
                }
                if (e.recalc && e.ref) {
                    var dataSource = this.dataSource;
                    var data = dataSource.view();
                    var columns = this.columns;
                    var fields;
                    if (dataSource.reader.model) {
                        fields = dataSource.reader.model.fields;
                    }
                    if (!columns.length && data.length) {
                        columns = Object.keys(data[0].toJSON());
                    }
                    var getters = columns.map(function (column) {
                        var field = column.field;
                        if (field && fields && fields[field] && fields[field].type == 'date') {
                            return kendo.spreadsheet.numberToDate;
                        }
                        return identity;
                    });
                    this._skipRebind = true;
                    var normalizedRef = this.sheet._grid.normalize(e.ref);
                    var values = this.sheet.range(normalizedRef).values();
                    normalizedRef.forEach(function (ref) {
                        ref = ref.toRangeRef();
                        var record;
                        var valueIndex = 0;
                        for (var ri = ref.topLeft.row; ri <= ref.bottomRight.row; ri++) {
                            record = data[ri - 1];
                            if (!record) {
                                record = dataSource.insert(ri - 1, {});
                                data = dataSource.view();
                            }
                            var colValueIndex = 0;
                            for (var ci = ref.topLeft.col; ci <= ref.bottomRight.col && ci < columns.length; ci++) {
                                record.set(columns[ci].field, getters[ci](values[valueIndex][colValueIndex++]));
                            }
                            valueIndex++;
                        }
                    });
                    this._boundRowsCount = dataSource.view().length;
                    this._skipRebind = false;
                }
            },
            _normalizeColumns: function (columns) {
                return columns.map(function (column) {
                    var field = column.field || column;
                    return {
                        field: field,
                        title: column.title || field
                    };
                });
            },
            _dataSource: function () {
                var options = this.options;
                var dataSource = options.dataSource;
                dataSource = Array.isArray(dataSource) ? { data: dataSource } : dataSource;
                if (this.dataSource && this._changeHandler) {
                    this.dataSource.unbind('change', this._changeHandler);
                } else {
                    this._changeHandler = this._change.bind(this);
                }
                this.dataSource = kendo.data.DataSource.create(dataSource).bind('change', this._changeHandler);
            },
            _change: function () {
                if (this._skipRebind) {
                    return;
                }
                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',
            iconCollapse: 'k-i-arrow-45-down-right',
            iconExpand: 'k-i-arrow-60-right',
            iconSearch: 'k-i-zoom',
            textbox: 'k-textbox',
            wrapper: 'k-spreadsheet-filter-menu',
            filterByCondition: 'k-spreadsheet-condition-filter',
            filterByValue: 'k-spreadsheet-value-filter',
            valuesTreeViewWrapper: 'k-spreadsheet-value-treeview-wrapper',
            actionButtons: 'k-action-buttons'
        };
        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',
                    matches: 'Text matches',
                    doesnotmatch: 'Text does not match'
                },
                date: {
                    eq: 'Date is',
                    neq: 'Date is not',
                    lt: 'Date is before',
                    gt: 'Date is after'
                },
                number: {
                    eq: 'Is equal to',
                    neq: 'Is not equal to',
                    gte: 'Is greater than or equal to',
                    gt: 'Is greater than',
                    lte: 'Is less than or equal to',
                    lt: 'Is less than'
                }
            }
        };
        kendo.data.binders.spreadsheetFilterValue = kendo.data.Binder.extend({
            init: function (element, bindings, options) {
                kendo.data.Binder.fn.init.call(this, element, bindings, options);
                this._change = $.proxy(this.change, this);
                $(this.element).on('change', this._change);
            },
            refresh: function () {
                var that = this, value = that.bindings.spreadsheetFilterValue.get();
                $(that.element).val(value instanceof Date ? '' : value);
            },
            change: function () {
                var value = this.element.value;
                this.bindings.spreadsheetFilterValue.set(value);
            }
        });
        kendo.data.binders.widget.spreadsheetFilterValue = kendo.data.Binder.extend({
            init: function (widget, bindings, options) {
                kendo.data.Binder.fn.init.call(this, widget.element[0], bindings, options);
                this.widget = widget;
                this._change = $.proxy(this.change, this);
                this.widget.first('change', this._change);
            },
            refresh: function () {
                var binding = this.bindings.spreadsheetFilterValue, value = binding.get(), type = $(this.widget.element).data('filterType');
                if (type === 'date' && value instanceof Date || type === 'number' && !isNaN(value)) {
                    this.widget.value(value);
                } else {
                    this.widget.value(null);
                }
            },
            change: function () {
                var value = this.widget.value(), binding = this.bindings.spreadsheetFilterValue;
                binding.set(value);
            }
        });
        var templates = {
            filterByValue: '<div class=\'' + classNames.detailsSummary + '\'>#= messages.filterByValue #</div>' + '<div class=\'' + classNames.detailsContent + '\'>' + '<div class=\'k-textbox k-space-right\'>' + '<input placeholder=\'#= messages.search #\' data-#=ns#bind=\'events: { input: filterValues }\' />' + '<span class=\'k-icon k-i-zoom\' />' + '</div>' + '<div data-#=ns#bind=\'visible: hasActiveSearch\'><input class=\'k-checkbox\' type=\'checkbox\' data-#=ns#bind=\'checked: appendToSearch\' id=\'_#=guid#\' /><label class=\'k-checkbox-label\' for=\'_#=guid#\'>#= messages.addToCurrent #</label></div>' + '<div class=\'' + classNames.valuesTreeViewWrapper + '\'>' + '<div data-#=ns#role=\'treeview\' ' + 'data-#=ns#checkboxes=\'{ checkChildren: true }\' ' + 'data-#=ns#bind=\'source: valuesDataSource, events: { check: valuesChange, select: valueSelect }\' ' + '/>' + '</div>' + '</div>',
            filterByCondition: '<div class=\'' + classNames.detailsSummary + '\'>#= messages.filterByCondition #</div>' + '<div class=\'' + classNames.detailsContent + '\'>' + '<div>' + '<select ' + 'data-#=ns#role="dropdownlist"' + 'data-#=ns#bind="value: operator, source: operators, events: { change: operatorChange } "' + 'data-value-primitive="false"' + 'data-option-label="#=messages.operatorNone#"' + 'data-height="auto"' + 'data-text-field="text"' + 'data-value-field="unique">' + '</select>' + '</div>' + '<div data-#=ns#bind="visible: isString">' + '<input data-filter-type="string" data-#=ns#bind="spreadsheetFilterValue: customFilter.criteria[0].value" class="k-textbox" />' + '</div>' + '<div data-#=ns#bind="visible: isNumber">' + '<input data-filter-type="number" data-#=ns#role="numerictextbox" data-#=ns#bind="spreadsheetFilterValue: customFilter.criteria[0].value" />' + '</div>' + '<div data-#=ns#bind="visible: isDate">' + '<input data-filter-type="date" data-#=ns#role="datepicker" data-#=ns#bind="spreadsheetFilterValue: customFilter.criteria[0].value" />' + '</div>' + '</div>',
            menuItem: '<li data-command=\'#=command#\' data-dir=\'#=dir#\'>' + '<span class=\'k-icon k-i-#=iconClass#\'></span>#=text#' + '</li>',
            actionButtons: '<button data-#=ns#bind=\'click: apply\' class=\'k-button k-primary\'>#=messages.apply#</button>' + '<button data-#=ns#bind=\'click: clear\' class=\'k-button\'>#=messages.clear#</button>'
        };
        function distinctValues(values) {
            var hash = {};
            var result = [];
            for (var i = 0; i < values.length; i++) {
                if (!hash[values[i].value]) {
                    hash[values[i].value] = values[i];
                    result.push(values[i]);
                } else if (!hash[values[i].value].checked && values[i].checked) {
                    hash[values[i].value].checked = true;
                }
            }
            return result;
        }
        function filter(dataSource, query) {
            var hasVisibleChildren = false;
            var data = dataSource instanceof kendo.data.HierarchicalDataSource && dataSource.data();
            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',
                        matches: 'Text matches',
                        doesnotmatch: 'Text does not match'
                    },
                    date: {
                        eq: 'Date is',
                        neq: 'Date is not',
                        lt: 'Date is before',
                        gt: 'Date is after'
                    },
                    number: {
                        eq: 'Is equal to',
                        neq: 'Is not equal to',
                        gte: 'Is greater than or equal to',
                        gt: 'Is greater than',
                        lte: 'Is less than or equal to',
                        lt: 'Is less than'
                    }
                }
            },
            events: ['action'],
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.menu.destroy();
                this.valuesTreeView.destroy();
                this.popup.destroy();
            },
            openFor: function (anchor) {
                this.popup.setOptions({ anchor: anchor });
                this.popup.open();
            },
            close: function () {
                this.popup.close();
            },
            clear: function () {
                this.action({
                    command: 'ClearFilterCommand',
                    options: { column: this.options.column }
                });
                this.viewModel.reset();
                this.close();
            },
            apply: function () {
                this._active();
                var options = {
                    operatingRange: this.options.range,
                    column: this.options.column
                };
                var valueFilter;
                var customFilter;
                if (this.viewModel.active === 'value') {
                    this.viewModel.valuesChange({ sender: this.valuesTreeView });
                    valueFilter = this.viewModel.valueFilter.toJSON();
                    if (valueFilter.blanks || valueFilter.values && valueFilter.values.length) {
                        options.valueFilter = valueFilter;
                    }
                } else if (this.viewModel.active === 'custom') {
                    customFilter = this.viewModel.customFilter.toJSON();
                    if (customFilter.criteria.length && customFilter.criteria[0].value !== null) {
                        options.customFilter = customFilter;
                    }
                }
                if (options.valueFilter || options.customFilter) {
                    this.action({
                        command: 'ApplyFilterCommand',
                        options: options
                    });
                }
            },
            action: function (options) {
                this.trigger('action', $.extend({}, options));
            },
            _filterInit: function () {
                var column = this.options.column;
                var range = this.options.range;
                var sheet = range.sheet();
                var activeFilter = FilterMenuController.filter(column, sheet);
                if (activeFilter) {
                    var filterType = FilterMenuController.filterType(range, column);
                    this.viewModel.set('active', activeFilter.type);
                    this.viewModel.set(activeFilter.type + 'Filter', activeFilter.options);
                    if (activeFilter.type == 'custom') {
                        this.viewModel.set('operator', filterType + '_' + activeFilter.operator);
                        this.viewModel.set('operatorType', filterType);
                    }
                } else {
                    this.viewModel.reset();
                }
            },
            _popup: function () {
                this.popup = this.element.kendoPopup({ copyAnchorStyles: false }).data('kendoPopup');
            },
            _sort: function () {
                var template = kendo.template(FilterMenu.templates.menuItem);
                var messages = 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('blur', this._blur.bind(this));
                this.cellInput.bind('blur', this._blur.bind(this));
            },
            events: [
                'activate',
                'deactivate',
                'change',
                'update'
            ],
            _blur: function () {
                this.deactivate();
            },
            _triggerUpdate: function () {
                this.trigger('update', { value: this.value() });
            },
            activeEditor: function () {
                var editor = null;
                var activeElement = kendo._activeElement();
                if (this.barElement()[0] === activeElement) {
                    editor = this.barInput;
                } else if (this.cellElement()[0] === activeElement) {
                    editor = this.cellInput;
                }
                return editor;
            },
            activate: function (options) {
                this._active = true;
                this._rect = options.rect;
                this.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) {
                    this.trigger('change', { value: cellInput.value() });
                }
                this._active = false;
                this._rect = null;
                cellInput.hide();
                this.trigger('deactivate');
            },
            enable: function (enable) {
                this.barInput.enable(enable);
                this.cellInput.enable(enable);
            },
            barElement: function () {
                return this.barInput.element;
            },
            cellElement: function () {
                return this.cellInput.element;
            },
            focus: function (inputType) {
                inputType = inputType || 'cell';
                if (inputType === 'cell') {
                    this.cellInput.element.focus();
                    this.cellInput.end();
                } else {
                    this.barInput.element.focus();
                }
            },
            isActive: function () {
                return this._active;
            },
            isFiltered: function () {
                return this.barInput.popup.visible() || this.cellInput.popup.visible();
            },
            canInsertRef: function (isKeyboardAction) {
                var editor = this.activeEditor();
                return editor && editor.canInsertRef(isKeyboardAction);
            },
            highlightedRefs: function () {
                var editor = this.activeEditor();
                var refs = [];
                if (editor) {
                    refs = editor.highlightedRefs();
                }
                return refs;
            },
            scale: function () {
                this.cellInput.scale();
            },
            toggleTooltip: function (rect) {
                this.cellInput.toggleTooltip(notEqual(this._rect, rect));
            },
            value: function (value) {
                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();
            },
            select: function () {
                this.activeEditor().select();
            }
        });
        function notEqual(oldRect, newRect) {
            return oldRect && (oldRect.top !== newRect.top || oldRect.left !== newRect.left);
        }
        kendo.spreadsheet.SheetEditor = SheetEditor;
    }(kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/autofill', [
        'spreadsheet/runtime',
        'spreadsheet/range'
    ], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var spreadsheet = kendo.spreadsheet;
    var Range = spreadsheet.Range;
    var runtime = spreadsheet.calc.runtime;
    var Formula = runtime.Formula;
    var ERR_INCOMPATIBLE = 'incompatibleRanges';
    var ERR_NO_DIRECTION = 'noFillDirection';
    var FillError = Range.FillError = function (msg) {
        this.code = msg;
    };
    Range.prototype._previewFillFrom = function (srcRange, direction) {
        var destRange = this, sheet = destRange._sheet;
        if (typeof srcRange == 'string') {
            srcRange = sheet.range(srcRange);
        }
        var src = srcRange._ref.toRangeRef();
        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 comboBoxTitle = options.messages.nameBox || 'Name Box';
                var dataSource = new kendo.data.DataSource({
                    transport: {
                        read: function (options) {
                            var data = [];
                            this._workbook.forEachName(function (def) {
                                if (!def.hidden && def.value instanceof kendo.spreadsheet.Ref) {
                                    data.push({ name: def.name });
                                }
                            });
                            options.success(data);
                        }.bind(this),
                        cache: false
                    }
                });
                var comboElement = $('<input />').attr('title', comboBoxTitle).attr('aria-label', comboBoxTitle);
                this.combo = comboElement.appendTo(element).kendoComboBox({
                    clearButton: false,
                    dataTextField: 'name',
                    dataValueField: 'name',
                    template: '#:data.name#<a class=\'k-button-delete\' href=\'\\#\'><span class=\'k-icon k-i-close\'></span></a>',
                    dataSource: dataSource,
                    autoBind: false,
                    ignoreCase: true,
                    change: this._on_listChange.bind(this),
                    noDataTemplate: '<div></div>',
                    open: function () {
                        dataSource.read();
                    }
                }).getKendoComboBox();
                this.combo.input.on('keydown', this._on_keyDown.bind(this)).on('focus', this._on_focus.bind(this));
                this.combo.popup.element.addClass('k-spreadsheet-names-popup').on('mousemove', function (ev) {
                    ev.stopPropagation();
                }).on('click', '.k-button-delete', function (ev) {
                    ev.preventDefault();
                    ev.stopPropagation();
                    var item = $(ev.target).closest('.k-item');
                    item = this.combo.dataItem(item);
                    this._deleteItem(item.name);
                }.bind(this));
            },
            value: function (val) {
                if (val === undefined) {
                    return this.combo.value();
                } else {
                    this.combo.value(val);
                }
            },
            _deleteItem: function (name) {
                this.trigger('delete', { name: name });
            },
            _on_keyDown: function (ev) {
                switch (ev.keyCode) {
                case 27:
                    this.combo.value(this._prevValue);
                    this.trigger('cancel');
                    break;
                case 13:
                    this.trigger('enter');
                    break;
                }
            },
            _on_focus: function () {
                this._prevValue = this.combo.value();
            },
            _on_listChange: function () {
                var name = this.combo.value();
                if (name) {
                    this.trigger('select', { name: name });
                }
            }
        });
        kendo.spreadsheet.NameEditor = NameEditor;
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/print', [
        'kendo.pdf',
        'spreadsheet/sheet',
        'spreadsheet/range',
        'spreadsheet/references',
        'spreadsheet/numformat',
        'util/text-metrics'
    ], f);
}(function () {
    'use strict';
    if (kendo.support.browser.msie && kendo.support.browser.version < 9) {
        return;
    }
    var spreadsheet = kendo.spreadsheet;
    var CellRef = spreadsheet.CellRef;
    var 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 doLayout(sheet, range, options) {
        var grid = sheet._grid;
        range = grid.normalize(range);
        var cells = [];
        var rowHeights = [];
        var colWidths = [];
        var mergedCells = sheet._getMergedCells(range);
        var maxRow = -1, maxCol = -1;
        sheet.forEach(range, function (row, col, cell) {
            var relrow = row - range.topLeft.row;
            var relcol = col - range.topLeft.col;
            var rh = sheet.rowHeight(row);
            var cw = sheet.columnWidth(col);
            if (!relcol) {
                rowHeights.push(rh);
            }
            if (!relrow) {
                colWidths.push(cw);
            }
            if (sheet.isHiddenColumn(col) || sheet.isHiddenRow(row) || !rh || !cw) {
                return;
            }
            var nonEmpty = options.forScreen || shouldDrawCell(cell);
            if (!(options.emptyCells || nonEmpty)) {
                return;
            }
            var id = new CellRef(row, col).print();
            if (mergedCells.secondary[id]) {
                return;
            }
            if (nonEmpty) {
                maxRow = Math.max(maxRow, relrow);
                maxCol = Math.max(maxCol, relcol);
            } else {
                cell.empty = true;
            }
            cell.row = relrow;
            cell.col = relcol;
            var m = mergedCells.primary[id];
            if (m) {
                delete mergedCells.primary[id];
                cell.merged = true;
                cell.rowspan = m.height();
                cell.colspan = m.width();
                if (options.forScreen) {
                    cell.width = sheet._columns.sum(m.topLeft.col, m.bottomRight.col);
                    cell.height = sheet._rows.sum(m.topLeft.row, m.bottomRight.row);
                }
            } else {
                cell.rowspan = 1;
                cell.colspan = 1;
            }
            cells.push(cell);
        });
        rowHeights = rowHeights.slice(0, maxRow + 1);
        colWidths = colWidths.slice(0, maxCol + 1);
        var pageWidth = options.pageWidth;
        var pageHeight = options.pageHeight;
        var scaleFactor = 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 sameBorder(a, b) {
        return a.size === b.size && a.color === b.color;
    }
    function sum(a, b) {
        return a + b;
    }
    function orlast(a, i) {
        return i < a.length ? a[i] : a[a.length - 1];
    }
    function shouldDrawCell(cell) {
        return cell.value != null || cell.merged || cell.background != null || cell.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('#aaa', 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('#aaa', GUIDELINE_WIDTH));
                        }
                    });
                }
                var borders = Borders();
                cells.forEach(function (cell) {
                    drawCell(cell, content, options);
                    borders.add(cell);
                });
                var bordersGroup = new drawing.Group();
                borders.vert.forEach(function (a) {
                    a.forEach(function (b) {
                        if (!b.rendered) {
                            b.rendered = true;
                            bordersGroup.append(new drawing.Path().moveTo(b.x, b.top).lineTo(b.x, b.bottom).close().stroke(b.color, b.size));
                        }
                    });
                });
                borders.horiz.forEach(function (a) {
                    a.forEach(function (b) {
                        if (!b.rendered) {
                            b.rendered = true;
                            bordersGroup.append(new drawing.Path().moveTo(b.left, b.y).lineTo(b.right, b.y).close().stroke(b.color, b.size));
                        }
                    });
                });
                content.append(bordersGroup);
            }
        }
    }
    function drawCell(cell, content, 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));
        }
        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);
        }
    }
    var CONT;
    function drawText(text, color, cell, group) {
        if (!CONT) {
            CONT = document.createElement('div');
            CONT.style.position = 'absolute';
            CONT.style.left = '-10000px';
            CONT.style.top = '-10000px';
            CONT.style.overflow = 'hidden';
            CONT.style.boxSizing = 'border-box';
            CONT.style.padding = '2px 4px';
            CONT.style.lineHeight = 'normal';
            document.body.appendChild(CONT);
        }
        CONT.style.color = color;
        CONT.style.font = makeFontDef(cell);
        CONT.style.width = cell.width + 'px';
        CONT.style.textAlign = cell.textAlign || 'left';
        CONT.style.textDecoration = cell.underline ? 'underline' : 'none';
        if (cell.wrap) {
            CONT.style.whiteSpace = 'pre-wrap';
            CONT.style.overflowWrap = CONT.style.wordWrap = 'break-word';
        } else {
            CONT.style.whiteSpace = 'pre';
            CONT.style.overflowWrap = CONT.style.wordWrap = 'normal';
        }
        if (CONT.firstChild) {
            CONT.removeChild(CONT.firstChild);
        }
        CONT.appendChild(document.createTextNode(text));
        var vtrans = 0;
        switch (cell.verticalAlign) {
        case 'center':
            vtrans = cell.height - CONT.offsetHeight >> 1;
            break;
        case undefined:
        case null:
        case 'bottom':
            vtrans = cell.height - CONT.offsetHeight;
            break;
        }
        if (vtrans < 0) {
            vtrans = 0;
        }
        var text_group = kendo.drawing.drawDOM.drawText(CONT);
        text_group.transform(geo.Matrix.translate(10000 + cell.left, 10000 + cell.top + vtrans));
        group.append(text_group);
    }
    function makeFontDef(cell) {
        var font = [];
        if (cell.italic) {
            font.push('italic');
        }
        if (cell.bold) {
            font.push('bold');
        }
        font.push((cell.fontSize || 12) + 'px');
        font.push(cell.fontFamily || 'Arial');
        return font.join(' ');
    }
    function draw(sheet, range, options, callback) {
        if (options == null && callback == null) {
            callback = range;
            options = {};
            range = spreadsheet.SHEETREF;
        }
        if (callback == null) {
            callback = options;
            if (range instanceof spreadsheet.Range || range instanceof spreadsheet.Ref || typeof range == 'string') {
                options = {};
            } else {
                options = range;
                range = spreadsheet.SHEETREF;
            }
        }
        options = kendo.jQuery.extend({
            paperSize: 'A4',
            landscape: true,
            margin: '1cm',
            guidelines: true,
            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 + 1;
            pageHeight -= paper.margin.top + paper.margin.bottom + 1;
        }
        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);
        }
    };
    function Borders() {
        var horiz = [];
        var vert = [];
        function add(cell) {
            if (cell.borderLeft) {
                addVert(cell.row, cell.col, cell.borderLeft, cell.left, cell.top, cell.bottom);
            }
            if (cell.borderRight) {
                addVert(cell.row, cell.col + cell.colspan, cell.borderRight, cell.right, cell.top, cell.bottom);
            }
            if (cell.borderTop) {
                addHoriz(cell.row, cell.col, cell.borderTop, cell.top, cell.left, cell.right);
            }
            if (cell.borderBottom) {
                addHoriz(cell.row + cell.rowspan, cell.col, cell.borderBottom, cell.bottom, cell.left, cell.right);
            }
        }
        function addVert(row, col, border, x, top, bottom) {
            var a = vert[col] || (vert[col] = []);
            var prev = row > 0 && a[row - 1];
            if (prev && sameBorder(prev, border)) {
                a[row] = prev;
                prev.bottom = bottom;
            } else {
                a[row] = {
                    size: border.size,
                    color: border.color,
                    x: x,
                    top: top,
                    bottom: bottom
                };
            }
        }
        function addHoriz(row, col, border, y, left, right) {
            var a = horiz[row] || (horiz[row] = []);
            var prev = col > 0 && a[col - 1];
            if (prev && sameBorder(prev, border)) {
                a[col] = prev;
                prev.right = right;
            } else {
                a[col] = {
                    size: border.size,
                    color: border.color,
                    y: y,
                    left: left,
                    right: right
                };
            }
        }
        return {
            add: add,
            horiz: horiz,
            vert: vert
        };
    }
    spreadsheet.draw = {
        Borders: Borders,
        doLayout: doLayout,
        drawLayout: drawLayout
    };
}, 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 = e.range || new kendo.spreadsheet.Range(e.ref, this.activeSheet());
                    this.trigger('change', { range: range });
                }
            },
            _workbookCut: function (e) {
                this.trigger('cut', e);
            },
            _workbookCopy: function (e) {
                this.trigger('copy', e);
            },
            _workbookPaste: function (e) {
                this.trigger('paste', e);
            },
            activeSheet: function (sheet) {
                return this._workbook.activeSheet(sheet);
            },
            moveSheetToIndex: function (sheet, index) {
                return this._workbook.moveSheetToIndex(sheet, index);
            },
            insertSheet: function (options) {
                return this._workbook.insertSheet(options);
            },
            sheets: function () {
                return this._workbook.sheets();
            },
            removeSheet: function (sheet) {
                return this._workbook.removeSheet(sheet);
            },
            sheetByName: function (sheetName) {
                return this._workbook.sheetByName(sheetName);
            },
            sheetIndex: function (sheet) {
                return this._workbook.sheetIndex(sheet);
            },
            sheetByIndex: function (index) {
                return this._workbook.sheetByIndex(index);
            },
            renameSheet: function (sheet, newSheetName) {
                return this._workbook.renameSheet(sheet, newSheetName);
            },
            refresh: function (reason) {
                if (!reason) {
                    reason = ALL_REASONS;
                }
                if (!reason.editorClose) {
                    this._view.sheet(this._workbook.activeSheet());
                    this._controller.sheet(this._workbook.activeSheet());
                    this._workbook.refresh(reason);
                }
                if (!reason.editorChange) {
                    this._view.refresh(reason);
                    this._controller.refresh();
                    this._view.render();
                    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();
                }
            },
            _workbookInsertSheet: function (e) {
                if (this.trigger('insertSheet', e)) {
                    e.preventDefault();
                }
            },
            _workbookRemoveSheet: function (e) {
                if (this.trigger('removeSheet', e)) {
                    e.preventDefault();
                }
            },
            _workbookSelectSheet: function (e) {
                if (this.trigger('selectSheet', e)) {
                    e.preventDefault();
                }
            },
            _workbookRenameSheet: function (e) {
                if (this.trigger('renameSheet', e)) {
                    e.preventDefault();
                }
            },
            _workbookInsertRow: function (e) {
                if (this.trigger('insertRow', e)) {
                    e.preventDefault();
                }
            },
            _workbookInsertColumn: function (e) {
                if (this.trigger('insertColumn', e)) {
                    e.preventDefault();
                }
            },
            _workbookDeleteRow: function (e) {
                if (this.trigger('deleteRow', e)) {
                    e.preventDefault();
                }
            },
            _workbookDeleteColumn: function (e) {
                if (this.trigger('deleteColumn', e)) {
                    e.preventDefault();
                }
            },
            _workbookHideRow: function (e) {
                if (this.trigger('hideRow', e)) {
                    e.preventDefault();
                }
            },
            _workbookHideColumn: function (e) {
                if (this.trigger('hideColumn', e)) {
                    e.preventDefault();
                }
            },
            _workbookUnhideRow: function (e) {
                if (this.trigger('unhideRow', e)) {
                    e.preventDefault();
                }
            },
            _workbookUnhideColumn: function (e) {
                if (this.trigger('unhideColumn', e)) {
                    e.preventDefault();
                }
            },
            _workbookSelect: function (e) {
                this.trigger('select', e);
            },
            _workbookChangeFormat: function (e) {
                this.trigger('changeFormat', e);
            },
            _bindWorkbookEvents: function () {
                this._workbook.bind('cut', this._workbookCut.bind(this));
                this._workbook.bind('copy', this._workbookCopy.bind(this));
                this._workbook.bind('paste', this._workbookPaste.bind(this));
                this._workbook.bind('change', this._workbookChange.bind(this));
                this._workbook.bind('excelExport', this._workbookExcelExport.bind(this));
                this._workbook.bind('excelImport', this._workbookExcelImport.bind(this));
                this._workbook.bind('pdfExport', this._workbookPdfExport.bind(this));
                this._workbook.bind('insertSheet', this._workbookInsertSheet.bind(this));
                this._workbook.bind('removeSheet', this._workbookRemoveSheet.bind(this));
                this._workbook.bind('selectSheet', this._workbookSelectSheet.bind(this));
                this._workbook.bind('renameSheet', this._workbookRenameSheet.bind(this));
                this._workbook.bind('insertRow', this._workbookInsertRow.bind(this));
                this._workbook.bind('insertColumn', this._workbookInsertColumn.bind(this));
                this._workbook.bind('deleteRow', this._workbookDeleteRow.bind(this));
                this._workbook.bind('deleteColumn', this._workbookDeleteColumn.bind(this));
                this._workbook.bind('hideRow', this._workbookHideRow.bind(this));
                this._workbook.bind('hideColumn', this._workbookHideColumn.bind(this));
                this._workbook.bind('unhideRow', this._workbookUnhideRow.bind(this));
                this._workbook.bind('unhideColumn', this._workbookUnhideColumn.bind(this));
                this._workbook.bind('select', this._workbookSelect.bind(this));
                this._workbook.bind('changeFormat', this._workbookChangeFormat.bind(this));
            },
            destroy: function () {
                kendo.ui.Widget.fn.destroy.call(this);
                this._workbook.destroy();
                this._controller.destroy();
                this._view.destroy();
                if (this._resizeHandler) {
                    $(window).off('resize' + NS, this._resizeHandler);
                }
            },
            options: {
                name: 'Spreadsheet',
                toolbar: true,
                sheetsbar: true,
                rows: 200,
                columns: 50,
                rowHeight: 20,
                columnWidth: 64,
                headerHeight: 20,
                headerWidth: 32,
                excel: {
                    proxyURL: '',
                    fileName: 'Workbook.xlsx'
                },
                messages: {},
                pdf: {
                    area: 'workbook',
                    fileName: 'Workbook.pdf',
                    proxyURL: '',
                    paperSize: 'a4',
                    landscape: true,
                    margin: null,
                    title: null,
                    author: null,
                    subject: null,
                    keywords: null,
                    creator: 'Kendo UI PDF Generator v.' + kendo.version,
                    date: null
                },
                defaultCellStyle: {
                    fontFamily: 'Arial',
                    fontSize: '12'
                }
            },
            defineName: function (name, value, hidden) {
                return this._workbook.defineName(name, value, hidden);
            },
            undefineName: function (name) {
                return this._workbook.undefineName(name);
            },
            nameValue: function (name) {
                return this._workbook.nameValue(name);
            },
            forEachName: function (func) {
                return this._workbook.forEachName(func);
            },
            cellContextMenu: function () {
                return this._view.cellContextMenu;
            },
            rowHeaderContextMenu: function () {
                return this._view.rowHeaderContextMenu;
            },
            colHeaderContextMenu: function () {
                return this._view.colHeaderContextMenu;
            },
            events: [
                'cut',
                'copy',
                'paste',
                'pdfExport',
                'excelExport',
                'excelImport',
                'change',
                'render',
                'removeSheet',
                'selectSheet',
                'renameSheet',
                'insertRow',
                'insertColumn',
                'deleteRow',
                'insertSheet',
                'deleteColumn',
                'hideRow',
                'hideColumn',
                'unhideRow',
                'unhideColumn',
                'select',
                'changeFormat'
            ]
        });
        kendo.spreadsheet.ALL_REASONS = ALL_REASONS;
        kendo.ui.plugin(Spreadsheet);
        $.extend(true, Spreadsheet, { classNames: classNames });
    }(window.kendo));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pivot.configurator', ['kendo.dom'], f);
}(function () {
    var __meta__ = {
        id: 'pivot.configurator',
        name: 'PivotConfigurator',
        category: 'web',
        depends: [
            'dropdownlist',
            'treeview',
            'pivot.fieldmenu'
        ],
        hidden: true
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Widget = ui.Widget, ns = '.kendoPivotConfigurator', HOVEREVENTS = 'mouseenter' + ns + ' mouseleave' + ns, SETTING_CONTAINER_TEMPLATE = kendo.template('<p class="k-reset"><span class="k-icon #=icon#"></span>${name}</p>' + '<div class="k-list-container k-reset"/>');
        function addKPI(data) {
            var found;
            var idx = 0;
            var length = data.length;
            for (; idx < length; idx++) {
                if (data[idx].type == 2) {
                    found = true;
                    break;
                }
            }
            if (found) {
                data.splice(idx + 1, 0, {
                    caption: 'KPIs',
                    defaultHierarchy: '[KPIs]',
                    name: 'KPIs',
                    uniqueName: '[KPIs]'
                });
            }
        }
        function kpiNode(node) {
            return {
                name: node.uniqueName,
                type: node.type
            };
        }
        function normalizeKPIs(data) {
            for (var idx = 0, length = data.length; idx < length; idx++) {
                data[idx].uniqueName = data[idx].name;
                data[idx].type = 'kpi';
            }
            return data;
        }
        function settingTargetFromNode(node) {
            var target = $(node).closest('.k-pivot-setting');
            if (target.length) {
                return target.data('kendoPivotSettingTarget');
            }
            return null;
        }
        var PivotConfigurator = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this.element.addClass('k-widget k-fieldselector k-alt k-edit-form-container');
                this._dataSource();
                this._layout();
                this.refresh();
                kendo.notify(this);
            },
            events: [],
            options: {
                name: 'PivotConfigurator',
                filterable: false,
                sortable: false,
                messages: {
                    measures: 'Drop Data Fields Here',
                    columns: 'Drop Column Fields Here',
                    rows: 'Drop Rows Fields Here',
                    measuresLabel: 'Measures',
                    columnsLabel: 'Columns',
                    rowsLabel: 'Rows',
                    fieldsLabel: 'Fields'
                }
            },
            _dataSource: function () {
                var that = this;
                if (that.dataSource && that._refreshHandler) {
                    that.dataSource.unbind('change', that._refreshHandler).unbind('error', that._errorHandler).unbind('progress', that._progressHandler);
                } else {
                    that._errorHandler = $.proxy(that._error, that);
                    that._refreshHandler = $.proxy(that.refresh, that);
                    that._progressHandler = $.proxy(that._requestStart, that);
                }
                that.dataSource = kendo.data.PivotDataSource.create(that.options.dataSource);
                that.dataSource.bind('change', that._refreshHandler).bind('error', that._errorHandler).bind('progress', that._progressHandler);
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.measures) {
                    this.measures.setDataSource(dataSource);
                }
                if (this.rows) {
                    this.rows.setDataSource(dataSource);
                }
                if (this.columns) {
                    this.columns.setDataSource(dataSource);
                }
                this.refresh();
            },
            _treeViewDataSource: function () {
                var that = this;
                return kendo.data.HierarchicalDataSource.create({
                    schema: {
                        model: {
                            id: 'uniqueName',
                            hasChildren: function (item) {
                                return !('hierarchyUniqueName' in item) && !('aggregator' in item);
                            }
                        }
                    },
                    transport: {
                        read: function (options) {
                            var promise;
                            var node;
                            var kpi;
                            if ($.isEmptyObject(options.data)) {
                                promise = that.dataSource.schemaDimensions();
                                promise.done(function (data) {
                                    if (!that.dataSource.cubeBuilder) {
                                        addKPI(data);
                                    }
                                    options.success(data);
                                }).fail(options.error);
                            } else {
                                node = that.treeView.dataSource.get(options.data.uniqueName);
                                if (node.uniqueName === '[KPIs]') {
                                    kpi = true;
                                    promise = that.dataSource.schemaKPIs();
                                    promise.done(function (data) {
                                        options.success(normalizeKPIs(data));
                                    }).fail(options.error);
                                } else if (node.type == 'kpi') {
                                    kpi = true;
                                    options.success(buildKPImeasures(node));
                                }
                                if (!kpi) {
                                    if (node.type == 2) {
                                        promise = that.dataSource.schemaMeasures();
                                    } else if (node.dimensionUniqueName) {
                                        promise = that.dataSource.schemaLevels(options.data.uniqueName);
                                    } else {
                                        promise = that.dataSource.schemaHierarchies(options.data.uniqueName);
                                    }
                                    promise.done(options.success).fail(options.error);
                                }
                            }
                        }
                    }
                });
            },
            _progress: function (toggle) {
                kendo.ui.progress(this.element, toggle);
            },
            _error: function () {
                this._progress(false);
            },
            _requestStart: function () {
                this._progress(true);
            },
            _layout: function () {
                this.form = $('<div class="k-columns k-state-default k-floatwrap"/>').appendTo(this.element);
                this._fields();
                this._targets();
            },
            _fields: function () {
                var container = $('<div class="k-state-default"><p class="k-reset"><span class="k-icon k-i-group"></span>' + this.options.messages.fieldsLabel + '</p></div>').appendTo(this.form);
                var template = '# if (item.type == 2 || item.uniqueName == "[KPIs]") { #' + '<span class="k-icon k-i-#= (item.type == 2 ? "sum" : "kpi") #"></span>' + '# } else if (item.type && item.type !== "kpi") { #' + '<span class="k-icon k-i-arrows-dimensions"></span>' + '# } #' + '#: item.caption || item.name #';
                this.treeView = $('<div/>').appendTo(container).kendoTreeView({
                    template: template,
                    dataTextField: 'caption',
                    dragAndDrop: true,
                    autoBind: false,
                    dataSource: this._treeViewDataSource(),
                    dragstart: function (e) {
                        var dataItem = this.dataItem(e.sourceNode);
                        if (!dataItem.hasChildren && !dataItem.aggregator && !dataItem.measure || dataItem.type == 2 || dataItem.uniqueName === '[KPIs]') {
                            e.preventDefault();
                        }
                    },
                    drag: function (e) {
                        var status = 'k-i-cancel';
                        var setting = settingTargetFromNode(e.dropTarget);
                        if (setting && setting.validate(this.dataItem(e.sourceNode))) {
                            status = 'k-i-plus';
                        }
                        e.setStatusClass(status);
                    },
                    drop: function (e) {
                        e.preventDefault();
                        var setting = settingTargetFromNode(e.dropTarget);
                        var node = this.dataItem(e.sourceNode);
                        var idx, length, measures;
                        var name;
                        if (setting && setting.validate(node)) {
                            name = node.defaultHierarchy || node.uniqueName;
                            if (node.type === 'kpi') {
                                measures = buildKPImeasures(node);
                                length = measures.length;
                                name = [];
                                for (idx = 0; idx < length; idx++) {
                                    name.push(kpiNode(measures[idx]));
                                }
                            } else if (node.kpi) {
                                name = [kpiNode(node)];
                            }
                            setting.add(name);
                        }
                    }
                }).data('kendoTreeView');
            },
            _createTarget: function (element, options) {
                var template = '<li class="k-item k-header" data-' + kendo.ns + 'name="${data.name}">${data.name}';
                var sortable = options.sortable;
                var icons = '';
                if (sortable) {
                    icons += '#if (data.sortIcon) {#';
                    icons += '<span class="k-icon ${data.sortIcon}-sm"></span>';
                    icons += '#}#';
                }
                if (options.filterable || sortable) {
                    icons += '<span class="k-icon k-i-more-vertical k-setting-fieldmenu"></span>';
                }
                icons += '<span class="k-icon k-i-close k-setting-delete"></span>';
                template += '<span class="k-field-actions">' + icons + '</span></li>';
                return new kendo.ui.PivotSettingTarget(element, $.extend({
                    dataSource: this.dataSource,
                    hint: function (element) {
                        var wrapper = $('<div class="k-fieldselector"><ul class="k-list k-reset"></ul></div>');
                        wrapper.find('.k-list').append(element.clone());
                        return wrapper;
                    },
                    template: template,
                    emptyTemplate: '<li class="k-item k-empty">${data}</li>'
                }, options));
            },
            _targets: function () {
                var container = $('<div class="k-state-default"/>').appendTo(this.form);
                var columnsContainer = $(SETTING_CONTAINER_TEMPLATE({
                    name: this.options.messages.columnsLabel,
                    icon: 'k-i-columns'
                })).appendTo(container);
                var columns = $('<ul class="k-pivot-configurator-settings k-list k-reset" />').appendTo(columnsContainer.last());
                var rowsContainer = $(SETTING_CONTAINER_TEMPLATE({
                    name: this.options.messages.rowsLabel,
                    icon: 'k-i-rows'
                })).appendTo(container);
                var rows = $('<ul class="k-pivot-configurator-settings k-list k-reset" />').appendTo(rowsContainer.last());
                var measuresContainer = $(SETTING_CONTAINER_TEMPLATE({
                    name: this.options.messages.measuresLabel,
                    icon: 'k-i-sum'
                })).appendTo(container);
                var measures = $('<ul class="k-pivot-configurator-settings k-list k-reset" />').appendTo(measuresContainer.last());
                var options = this.options;
                this.columns = this._createTarget(columns, {
                    filterable: options.filterable,
                    sortable: options.sortable,
                    connectWith: rows,
                    messages: {
                        empty: options.messages.columns,
                        fieldMenu: options.messages.fieldMenu
                    }
                });
                this.rows = this._createTarget(rows, {
                    filterable: options.filterable,
                    sortable: options.sortable,
                    setting: 'rows',
                    connectWith: columns,
                    messages: {
                        empty: this.options.messages.rows,
                        fieldMenu: this.options.messages.fieldMenu
                    }
                });
                this.measures = this._createTarget(measures, {
                    setting: 'measures',
                    messages: { empty: options.messages.measures }
                });
                columns.add(rows).add(measures).on(HOVEREVENTS, '.k-item:not(.k-empty)', this._toggleHover);
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass('k-state-hover', e.type === 'mouseenter');
            },
            _resize: function () {
                var element = this.element;
                var height = this.options.height;
                var border, fields;
                var outerHeight = kendo._outerHeight;
                if (!height) {
                    return;
                }
                element.height(height);
                if (element.is(':visible')) {
                    fields = element.children('.k-columns').children('div.k-state-default');
                    height = element.innerHeight();
                    border = (outerHeight(element) - height) / 2;
                    height = height - (outerHeight(fields, true) - fields.height()) - border;
                    fields.height(height);
                }
            },
            refresh: function () {
                var dataSource = this.dataSource;
                if (dataSource.cubeBuilder || this._cube !== dataSource.cube() || this._catalog !== dataSource.catalog()) {
                    this.treeView.dataSource.fetch();
                }
                this._catalog = this.dataSource.catalog();
                this._cube = this.dataSource.cube();
                this._resize();
                this._progress(false);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.dataSource.unbind('change', this._refreshHandler);
                this.form.find('.k-list').off(ns);
                this.rows.destroy();
                this.columns.destroy();
                this.measures.destroy();
                this.treeView.destroy();
                this.element = null;
                this._refreshHandler = null;
            }
        });
        function kpiMeasure(name, measure, type) {
            return {
                hierarchyUniqueName: name,
                uniqueName: measure,
                caption: measure,
                measure: measure,
                name: measure,
                type: type,
                kpi: true
            };
        }
        function buildKPImeasures(node) {
            var name = node.name;
            return [
                kpiMeasure(name, node.value, 'value'),
                kpiMeasure(name, node.goal, 'goal'),
                kpiMeasure(name, node.status, 'status'),
                kpiMeasure(name, node.trend, 'trend')
            ];
        }
        ui.plugin(PivotConfigurator);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.angular', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'angular',
        name: 'AngularJS Directives',
        category: 'framework',
        description: 'Adds Kendo UI for AngularJS directives',
        depends: ['core'],
        defer: true
    };
    (function ($, angular, undefined) {
        'use strict';
        if (!angular || !angular.injector) {
            return;
        }
        var module = angular.module('kendo.directives', []), $injector = angular.injector(['ng']), $parse = $injector.get('$parse'), $timeout = $injector.get('$timeout'), $defaultCompile, $log = $injector.get('$log');
        function withoutTimeout(f) {
            var save = $timeout;
            try {
                $timeout = function (f) {
                    return f();
                };
                return f();
            } finally {
                $timeout = save;
            }
        }
        var OPTIONS_NOW;
        var createDataSource = function () {
            var types = {
                TreeList: 'TreeListDataSource',
                TreeView: 'HierarchicalDataSource',
                Scheduler: 'SchedulerDataSource',
                PivotGrid: 'PivotDataSource',
                PivotConfigurator: 'PivotDataSource',
                PanelBar: 'HierarchicalDataSource',
                Menu: '$PLAIN',
                ContextMenu: '$PLAIN'
            };
            var toDataSource = function (dataSource, type) {
                if (type == '$PLAIN') {
                    return dataSource;
                }
                return kendo.data[type].create(dataSource);
            };
            return function (scope, element, role, source) {
                var type = types[role] || 'DataSource';
                var current = scope.$eval(source);
                var ds = toDataSource(current, type);
                scope.$watch(source, function (mew) {
                    var widget = kendoWidgetInstance(element);
                    if (widget && typeof widget.setDataSource == 'function') {
                        if (mew !== current) {
                            var ds = toDataSource(mew, type);
                            widget.setDataSource(ds);
                            current = mew;
                        }
                    }
                });
                return ds;
            };
        }();
        var ignoredAttributes = {
            kDataSource: true,
            kOptions: true,
            kRebind: true,
            kNgModel: true,
            kNgDelay: true
        };
        var ignoredOwnProperties = {
            name: true,
            title: true,
            style: true
        };
        function createWidget(scope, element, attrs, widget, origAttr, controllers) {
            if (!(element instanceof jQuery)) {
                throw new Error('The Kendo UI directives require jQuery to be available before AngularJS. Please include jquery before angular in the document.');
            }
            var kNgDelay = attrs.kNgDelay, delayValue = scope.$eval(kNgDelay);
            controllers = controllers || [];
            var ngModel = controllers[0], ngForm = controllers[1];
            var ctor = $(element)[widget];
            if (!ctor) {
                window.console.error('Could not find: ' + widget);
                return null;
            }
            var parsed = parseOptions(scope, element, attrs, widget, ctor);
            var options = parsed.options;
            if (parsed.unresolved.length) {
                var promises = [];
                for (var i = 0, len = parsed.unresolved.length; i < len; i++) {
                    var unresolved = parsed.unresolved[i];
                    var promise = $.Deferred(function (d) {
                        var unwatch = scope.$watch(unresolved.path, function (newValue) {
                            if (newValue !== undefined) {
                                unwatch();
                                d.resolve();
                            }
                        });
                    }).promise();
                    promises.push(promise);
                }
                $.when.apply(null, promises).then(createIt);
                return;
            }
            if (kNgDelay && !delayValue) {
                var root = scope.$root || scope;
                var register = function () {
                    var unregister = scope.$watch(kNgDelay, function (newValue) {
                        if (newValue !== undefined) {
                            unregister();
                            element.removeAttr(attrs.$attr.kNgDelay);
                            kNgDelay = null;
                            $timeout(createIt);
                        }
                    });
                };
                if (/^\$(digest|apply)$/.test(root.$$phase)) {
                    register();
                } else {
                    scope.$apply(register);
                }
                return;
            } else {
                return createIt();
            }
            function createIt() {
                var originalElement;
                if (attrs.kRebind) {
                    originalElement = $($(element)[0].cloneNode(true));
                }
                options = parseOptions(scope, element, attrs, widget, ctor).options;
                if (element.is('select')) {
                    (function (options) {
                        if (options.length > 0) {
                            var first = $(options[0]);
                            if (!/\S/.test(first.text()) && /^\?/.test(first.val())) {
                                first.remove();
                            }
                        }
                    }(element[0].options));
                }
                var object = ctor.call(element, OPTIONS_NOW = options).data(widget);
                exposeWidget(object, scope, attrs, widget, origAttr);
                scope.$emit('kendoWidgetCreated', object);
                var destroyRegister = destroyWidgetOnScopeDestroy(scope, object);
                if (attrs.kRebind) {
                    setupRebind(object, scope, element, originalElement, attrs.kRebind, destroyRegister, attrs);
                }
                if (attrs.kNgDisabled) {
                    var kNgDisabled = attrs.kNgDisabled;
                    var isDisabled = scope.$eval(kNgDisabled);
                    if (isDisabled) {
                        object.enable(!isDisabled);
                    }
                    bindToKNgDisabled(object, scope, element, kNgDisabled);
                }
                if (attrs.kNgReadonly) {
                    var kNgReadonly = attrs.kNgReadonly;
                    var isReadonly = scope.$eval(kNgReadonly);
                    if (isReadonly) {
                        object.readonly(isReadonly);
                    }
                    bindToKNgReadonly(object, scope, element, kNgReadonly);
                }
                if (attrs.kNgModel) {
                    bindToKNgModel(object, scope, attrs.kNgModel);
                }
                if (ngModel) {
                    bindToNgModel(object, scope, element, ngModel, ngForm);
                }
                if (object) {
                    propagateClassToWidgetWrapper(object, element);
                }
                return object;
            }
        }
        function parseOptions(scope, element, attrs, widget, ctor) {
            var role = widget.replace(/^kendo/, '');
            var unresolved = [];
            var optionsPath = attrs.kOptions || attrs.options;
            var optionsValue = scope.$eval(optionsPath);
            if (optionsPath && optionsValue === undefined) {
                unresolved.push({
                    option: 'options',
                    path: optionsPath
                });
            }
            var options = angular.extend({}, attrs.defaultOptions, optionsValue);
            function addOption(name, value) {
                var scopeValue = angular.copy(scope.$eval(value));
                if (scopeValue === undefined) {
                    unresolved.push({
                        option: name,
                        path: value
                    });
                } else {
                    options[name] = scopeValue;
                }
            }
            var widgetOptions = ctor.widget.prototype.options;
            var widgetEvents = ctor.widget.prototype.events;
            $.each(attrs, function (name, value) {
                if (name === 'source' || name === 'kDataSource' || name === 'kScopeField' || name === 'scopeField') {
                    return;
                }
                var dataName = 'data' + name.charAt(0).toUpperCase() + name.slice(1);
                if (name.indexOf('on') === 0) {
                    var eventKey = name.replace(/^on./, function (prefix) {
                        return prefix.charAt(2).toLowerCase();
                    });
                    if (widgetEvents.indexOf(eventKey) > -1) {
                        options[eventKey] = value;
                    }
                }
                if (widgetOptions.hasOwnProperty(dataName)) {
                    addOption(dataName, value);
                } else if (widgetOptions.hasOwnProperty(name) && !ignoredOwnProperties[name]) {
                    addOption(name, value);
                } else if (!ignoredAttributes[name]) {
                    var match = name.match(/^k(On)?([A-Z].*)/);
                    if (match) {
                        var optionName = match[2].charAt(0).toLowerCase() + match[2].slice(1);
                        if (match[1] && name != 'kOnLabel') {
                            options[optionName] = value;
                        } else {
                            if (name == 'kOnLabel') {
                                optionName = 'onLabel';
                            }
                            addOption(optionName, value);
                        }
                    }
                }
            });
            var dataSource = attrs.kDataSource || attrs.source;
            if (dataSource) {
                options.dataSource = createDataSource(scope, element, role, dataSource);
            }
            options.$angular = [scope];
            return {
                options: options,
                unresolved: unresolved
            };
        }
        function bindToKNgDisabled(widget, scope, element, kNgDisabled) {
            if (kendo.ui.PanelBar && widget instanceof kendo.ui.PanelBar || kendo.ui.Menu && widget instanceof kendo.ui.Menu) {
                $log.warn('k-ng-disabled specified on a widget that does not have the enable() method: ' + widget.options.name);
                return;
            }
            scope.$watch(kNgDisabled, function (newValue, oldValue) {
                if (newValue != oldValue) {
                    widget.enable(!newValue);
                }
            });
        }
        function bindToKNgReadonly(widget, scope, element, kNgReadonly) {
            if (typeof widget.readonly != 'function') {
                $log.warn('k-ng-readonly specified on a widget that does not have the readonly() method: ' + widget.options.name);
                return;
            }
            scope.$watch(kNgReadonly, function (newValue, oldValue) {
                if (newValue != oldValue) {
                    widget.readonly(newValue);
                }
            });
        }
        function exposeWidget(widget, scope, attrs, kendoWidget, origAttr) {
            if (attrs[origAttr]) {
                var set = $parse(attrs[origAttr]).assign;
                if (set) {
                    set(scope, widget);
                } else {
                    throw new Error(origAttr + ' attribute used but expression in it is not assignable: ' + attrs[kendoWidget]);
                }
            }
        }
        function formValue(element) {
            if (/checkbox|radio/i.test(element.attr('type'))) {
                return element.prop('checked');
            }
            return element.val();
        }
        var formRegExp = /^(input|select|textarea)$/i;
        function isForm(element) {
            return formRegExp.test(element[0].tagName);
        }
        function bindToNgModel(widget, scope, element, ngModel, ngForm) {
            if (!widget.value) {
                return;
            }
            var value;
            var haveChangeOnElement = false;
            if (isForm(element)) {
                value = function () {
                    return formValue(element);
                };
            } else {
                value = function () {
                    return widget.value();
                };
            }
            var viewRender = function () {
                var val = ngModel.$viewValue;
                if (val === undefined) {
                    val = ngModel.$modelValue;
                }
                if (val === undefined) {
                    val = null;
                }
                haveChangeOnElement = true;
                setTimeout(function () {
                    haveChangeOnElement = false;
                    if (widget) {
                        var kNgModel = scope[widget.element.attr('k-ng-model')];
                        if (kNgModel) {
                            val = kNgModel;
                        }
                        if (widget.options.autoBind === false && !widget.listView.bound()) {
                            if (val) {
                                widget.value(val);
                            }
                        } else {
                            widget.value(val);
                        }
                    }
                }, 0);
            };
            ngModel.$render = viewRender;
            setTimeout(function () {
                if (ngModel.$render !== viewRender) {
                    ngModel.$render = viewRender;
                    ngModel.$render();
                }
            });
            if (isForm(element)) {
                element.on('change', function () {
                    haveChangeOnElement = true;
                });
            }
            var onChange = function (pristine) {
                return function () {
                    var formPristine;
                    if (haveChangeOnElement && !element.is('select')) {
                        return;
                    }
                    if (pristine && ngForm) {
                        formPristine = ngForm.$pristine;
                    }
                    ngModel.$setViewValue(value());
                    if (pristine) {
                        ngModel.$setPristine();
                        if (formPristine) {
                            ngForm.$setPristine();
                        }
                    }
                    digest(scope);
                };
            };
            widget.first('change', onChange(false));
            widget.first('spin', onChange(false));
            if (!(kendo.ui.AutoComplete && widget instanceof kendo.ui.AutoComplete)) {
                widget.first('dataBound', onChange(true));
            }
            var currentVal = value();
            if (!isNaN(ngModel.$viewValue) && currentVal != ngModel.$viewValue) {
                if (!ngModel.$isEmpty(ngModel.$viewValue)) {
                    widget.value(ngModel.$viewValue);
                } else if (currentVal != null && currentVal !== '' && currentVal != ngModel.$viewValue) {
                    ngModel.$setViewValue(currentVal);
                }
            }
            ngModel.$setPristine();
        }
        function bindToKNgModel(widget, scope, kNgModel) {
            if (typeof widget.value != 'function') {
                $log.warn('k-ng-model specified on a widget that does not have the value() method: ' + widget.options.name);
                return;
            }
            var form = $(widget.element).parents('form');
            var ngForm = kendo.getter(form.attr('name'), true)(scope);
            var getter = $parse(kNgModel);
            var setter = getter.assign;
            var updating = false;
            var valueIsCollection = kendo.ui.MultiSelect && widget instanceof kendo.ui.MultiSelect;
            var length = function (value) {
                return value && valueIsCollection ? value.length : 0;
            };
            var currentValueLength = length(getter(scope));
            widget.$angular_setLogicValue(getter(scope));
            var watchHandler = function (newValue, oldValue) {
                if (newValue === undefined) {
                    newValue = null;
                }
                if (updating || newValue == oldValue && length(newValue) == currentValueLength) {
                    return;
                }
                currentValueLength = length(newValue);
                widget.$angular_setLogicValue(newValue);
            };
            if (valueIsCollection) {
                scope.$watchCollection(kNgModel, watchHandler);
            } else {
                scope.$watch(kNgModel, watchHandler);
            }
            var changeHandler = function () {
                updating = true;
                if (ngForm && ngForm.$pristine) {
                    ngForm.$setDirty();
                }
                digest(scope, function () {
                    setter(scope, widget.$angular_getLogicValue());
                    currentValueLength = length(getter(scope));
                });
                updating = false;
            };
            widget.first('change', changeHandler);
            widget.first('spin', changeHandler);
        }
        function destroyWidgetOnScopeDestroy(scope, widget) {
            var deregister = scope.$on('$destroy', function () {
                deregister();
                if (widget) {
                    kendo.destroy(widget.element);
                    widget = null;
                }
            });
            return deregister;
        }
        function propagateClassToWidgetWrapper(widget, element) {
            if (!(window.MutationObserver && widget.wrapper)) {
                return;
            }
            var prevClassList = [].slice.call($(element)[0].classList);
            var mo = new MutationObserver(function (changes) {
                suspend();
                if (!widget) {
                    return;
                }
                changes.forEach(function (chg) {
                    var w = $(widget.wrapper)[0];
                    switch (chg.attributeName) {
                    case 'class':
                        var currClassList = [].slice.call(chg.target.classList);
                        currClassList.forEach(function (cls) {
                            if (prevClassList.indexOf(cls) < 0) {
                                w.classList.add(cls);
                                if (kendo.ui.ComboBox && widget instanceof kendo.ui.ComboBox) {
                                    widget.input[0].classList.add(cls);
                                }
                            }
                        });
                        prevClassList.forEach(function (cls) {
                            if (currClassList.indexOf(cls) < 0) {
                                w.classList.remove(cls);
                                if (kendo.ui.ComboBox && widget instanceof kendo.ui.ComboBox) {
                                    widget.input[0].classList.remove(cls);
                                }
                            }
                        });
                        prevClassList = currClassList;
                        break;
                    case 'disabled':
                        if (typeof widget.enable == 'function' && !widget.element.attr('readonly')) {
                            widget.enable(!$(chg.target).attr('disabled'));
                        }
                        break;
                    case 'readonly':
                        if (typeof widget.readonly == 'function' && !widget.element.attr('disabled')) {
                            widget.readonly(!!$(chg.target).attr('readonly'));
                        }
                        break;
                    }
                });
                resume();
            });
            function suspend() {
                mo.disconnect();
            }
            function resume() {
                mo.observe($(element)[0], { attributes: true });
            }
            resume();
            widget.first('destroy', suspend);
        }
        function setupRebind(widget, scope, element, originalElement, rebindAttr, destroyRegister, attrs) {
            var unregister = scope.$watch(rebindAttr, function (newValue, oldValue) {
                if (!widget._muteRebind && newValue !== oldValue) {
                    unregister();
                    if (attrs._cleanUp) {
                        attrs._cleanUp();
                    }
                    var templateOptions = WIDGET_TEMPLATE_OPTIONS[widget.options.name];
                    if (templateOptions) {
                        templateOptions.forEach(function (name) {
                            var templateContents = scope.$eval(attrs['k' + name]);
                            if (templateContents) {
                                originalElement.append($(templateContents).attr(kendo.toHyphens('k' + name), ''));
                            }
                        });
                    }
                    var _wrapper = $(widget.wrapper)[0];
                    var _element = $(widget.element)[0];
                    var isUpload = widget.options.name === 'Upload';
                    if (isUpload) {
                        element = $(_element);
                    }
                    var compile = element.injector().get('$compile');
                    widget._destroy();
                    if (destroyRegister) {
                        destroyRegister();
                    }
                    widget = null;
                    if (_element) {
                        if (_wrapper) {
                            _wrapper.parentNode.replaceChild(_element, _wrapper);
                        }
                        $(element).replaceWith(originalElement);
                    }
                    compile(originalElement)(scope);
                }
            }, true);
            digest(scope);
        }
        function bind(f, obj) {
            return function (a, b) {
                return f.call(obj, a, b);
            };
        }
        function setTemplate(key, value) {
            this[key] = kendo.stringify(value);
        }
        module.factory('directiveFactory', [
            '$compile',
            function (compile) {
                var kendoRenderedTimeout;
                var RENDERED = false;
                $defaultCompile = compile;
                var create = function (role, origAttr) {
                    return {
                        restrict: 'AC',
                        require: [
                            '?ngModel',
                            '^?form'
                        ],
                        scope: false,
                        controller: [
                            '$scope',
                            '$attrs',
                            '$element',
                            function ($scope, $attrs) {
                                this.template = bind(setTemplate, $attrs);
                                $attrs._cleanUp = bind(function () {
                                    this.template = null;
                                    $attrs._cleanUp = null;
                                }, this);
                            }
                        ],
                        link: function (scope, element, attrs, controllers) {
                            var $element = $(element);
                            var roleattr = role.replace(/([A-Z])/g, '-$1');
                            $element.attr(roleattr, $element.attr('data-' + roleattr));
                            $element[0].removeAttribute('data-' + roleattr);
                            var widget = createWidget(scope, element, attrs, role, origAttr, controllers);
                            if (!widget) {
                                return;
                            }
                            if (kendoRenderedTimeout) {
                                clearTimeout(kendoRenderedTimeout);
                            }
                            kendoRenderedTimeout = setTimeout(function () {
                                scope.$emit('kendoRendered');
                                if (!RENDERED) {
                                    RENDERED = true;
                                    $('form').each(function () {
                                        var form = $(this).controller('form');
                                        if (form) {
                                            form.$setPristine();
                                        }
                                    });
                                }
                            });
                        }
                    };
                };
                return { create: create };
            }
        ]);
        var TAGNAMES = {
            Editor: 'textarea',
            NumericTextBox: 'input',
            DatePicker: 'input',
            DateTimePicker: 'input',
            TimePicker: 'input',
            AutoComplete: 'input',
            ColorPicker: 'input',
            MaskedTextBox: 'input',
            MultiSelect: 'input',
            Upload: 'input',
            Validator: 'form',
            Button: 'button',
            MobileButton: 'a',
            MobileBackButton: 'a',
            MobileDetailButton: 'a',
            ListView: 'ul',
            MobileListView: 'ul',
            PanelBar: 'ul',
            TreeView: 'ul',
            Menu: 'ul',
            ContextMenu: 'ul',
            ActionSheet: 'ul'
        };
        var SKIP_SHORTCUTS = [
            'MobileView',
            'MobileDrawer',
            'MobileLayout',
            'MobileSplitView',
            'MobilePane',
            'MobileModalView'
        ];
        var MANUAL_DIRECTIVES = [
            'MobileApplication',
            'MobileView',
            'MobileModalView',
            'MobileLayout',
            'MobileActionSheet',
            'MobileDrawer',
            'MobileSplitView',
            'MobilePane',
            'MobileScrollView',
            'MobilePopOver'
        ];
        angular.forEach([
            'MobileNavBar',
            'MobileButton',
            'MobileBackButton',
            'MobileDetailButton',
            'MobileTabStrip',
            'MobileScrollView',
            'MobileScroller'
        ], function (widget) {
            MANUAL_DIRECTIVES.push(widget);
            widget = 'kendo' + widget;
            module.directive(widget, function () {
                return {
                    restrict: 'A',
                    link: function (scope, element, attrs) {
                        createWidget(scope, element, attrs, widget, widget);
                    }
                };
            });
        });
        function createDirectives(klass, isMobile) {
            function make(directiveName, widgetName) {
                module.directive(directiveName, [
                    'directiveFactory',
                    function (directiveFactory) {
                        return directiveFactory.create(widgetName, directiveName);
                    }
                ]);
            }
            var name = isMobile ? 'Mobile' : '';
            name += klass.fn.options.name;
            var className = name;
            var shortcut = 'kendo' + name.charAt(0) + name.substr(1).toLowerCase();
            name = 'kendo' + name;
            var dashed = name.replace(/([A-Z])/g, '-$1');
            if (SKIP_SHORTCUTS.indexOf(name.replace('kendo', '')) == -1) {
                var names = name === shortcut ? [name] : [
                    name,
                    shortcut
                ];
                angular.forEach(names, function (directiveName) {
                    module.directive(directiveName, function () {
                        return {
                            restrict: 'E',
                            replace: true,
                            template: function (element, attributes) {
                                var tag = TAGNAMES[className] || 'div';
                                var scopeField = attributes.kScopeField || attributes.scopeField;
                                return '<' + tag + ' ' + dashed + (scopeField ? '="' + scopeField + '"' : '') + '>' + element.html() + '</' + tag + '>';
                            }
                        };
                    });
                });
            }
            if (MANUAL_DIRECTIVES.indexOf(name.replace('kendo', '')) > -1) {
                return;
            }
            make(name, name);
            if (shortcut != name) {
                make(shortcut, name);
            }
        }
        function kendoWidgetInstance(el) {
            el = $(el);
            return kendo.widgetInstance(el, kendo.ui) || kendo.widgetInstance(el, kendo.mobile.ui) || kendo.widgetInstance(el, kendo.dataviz.ui);
        }
        function digest(scope, func) {
            var root = scope.$root || scope;
            var isDigesting = /^\$(digest|apply)$/.test(root.$$phase);
            if (func) {
                if (isDigesting) {
                    func();
                } else {
                    root.$apply(func);
                }
            } else if (!isDigesting) {
                root.$digest();
            }
        }
        function destroyScope(scope, el) {
            scope.$destroy();
            if (el) {
                $(el).removeData('$scope').removeData('$$kendoScope').removeData('$isolateScope').removeData('$isolateScopeNoTemplate').removeClass('ng-scope');
            }
        }
        var pendingPatches = [];
        function defadvice(klass, methodName, func) {
            if ($.isArray(klass)) {
                return angular.forEach(klass, function (klass) {
                    defadvice(klass, methodName, func);
                });
            }
            if (typeof klass == 'string') {
                var a = klass.split('.');
                var x = kendo;
                while (x && a.length > 0) {
                    x = x[a.shift()];
                }
                if (!x) {
                    pendingPatches.push([
                        klass,
                        methodName,
                        func
                    ]);
                    return false;
                }
                klass = x.prototype;
            }
            var origMethod = klass[methodName];
            klass[methodName] = function () {
                var self = this, args = arguments;
                return func.apply({
                    self: self,
                    next: function () {
                        return origMethod.apply(self, arguments.length > 0 ? arguments : args);
                    }
                }, args);
            };
            return true;
        }
        kendo.onWidgetRegistered(function (entry) {
            pendingPatches = $.grep(pendingPatches, function (args) {
                return !defadvice.apply(null, args);
            });
            createDirectives(entry.widget, entry.prefix == 'Mobile');
        });
        defadvice([
            'ui.Widget',
            'mobile.ui.Widget'
        ], 'angular', function (cmd, arg) {
            var self = this.self;
            if (cmd == 'init') {
                if (!arg && OPTIONS_NOW) {
                    arg = OPTIONS_NOW;
                }
                OPTIONS_NOW = null;
                if (arg && arg.$angular) {
                    self.$angular_scope = arg.$angular[0];
                    self.$angular_init(self.element, arg);
                }
                return;
            }
            var scope = self.$angular_scope;
            if (scope) {
                withoutTimeout(function () {
                    var x = arg(), elements = x.elements, data = x.data;
                    if (elements.length > 0) {
                        switch (cmd) {
                        case 'cleanup':
                            angular.forEach(elements, function (el) {
                                var itemScope = $(el).data('$$kendoScope');
                                if (itemScope && itemScope !== scope && itemScope.$$kendoScope) {
                                    destroyScope(itemScope, el);
                                }
                            });
                            break;
                        case 'compile':
                            var injector = self.element.injector();
                            var compile = injector ? injector.get('$compile') : $defaultCompile;
                            angular.forEach(elements, function (el, i) {
                                var itemScope;
                                if (x.scopeFrom) {
                                    itemScope = x.scopeFrom;
                                } else {
                                    var vars = data && data[i];
                                    if (vars !== undefined) {
                                        itemScope = $.extend(scope.$new(), vars);
                                        itemScope.$$kendoScope = true;
                                    } else {
                                        itemScope = scope;
                                    }
                                }
                                $(el).data('$$kendoScope', itemScope);
                                compile(el)(itemScope);
                            });
                            digest(scope);
                            break;
                        }
                    }
                });
            }
        });
        defadvice('ui.Widget', '$angular_getLogicValue', function () {
            return this.self.value();
        });
        defadvice('ui.Widget', '$angular_setLogicValue', function (val) {
            this.self.value(val);
        });
        defadvice('ui.Select', '$angular_getLogicValue', function () {
            var item = this.self.dataItem(), valueField = this.self.options.dataValueField;
            if (item) {
                if (this.self.options.valuePrimitive) {
                    if (!!valueField) {
                        return item[valueField];
                    } else {
                        return item;
                    }
                } else {
                    return item.toJSON();
                }
            } else {
                return null;
            }
        });
        defadvice('ui.Select', '$angular_setLogicValue', function (val) {
            var self = this.self;
            var options = self.options;
            var valueField = options.dataValueField;
            var text = options.text || '';
            if (val === undefined) {
                val = '';
            }
            if (valueField && !options.valuePrimitive && val) {
                text = val[options.dataTextField] || '';
                val = val[valueField || options.dataTextField];
            }
            if (self.options.autoBind === false && !self.listView.bound()) {
                if (!text && val && options.valuePrimitive) {
                    self.value(val);
                } else {
                    self._preselect(val, text);
                }
            } else {
                self.value(val);
            }
        });
        defadvice('ui.MultiSelect', '$angular_getLogicValue', function () {
            var value = this.self.dataItems().slice(0);
            var valueField = this.self.options.dataValueField;
            if (valueField && this.self.options.valuePrimitive) {
                value = $.map(value, function (item) {
                    return item[valueField];
                });
            }
            return value;
        });
        defadvice('ui.MultiSelect', '$angular_setLogicValue', function (val) {
            if (val == null) {
                val = [];
            }
            var self = this.self;
            var options = self.options;
            var valueField = options.dataValueField;
            var data = val;
            if (valueField && !options.valuePrimitive) {
                val = $.map(val, function (item) {
                    return item[valueField];
                });
            }
            if (options.autoBind === false && !options.valuePrimitive && !self.listView.bound()) {
                self._preselect(data, val);
            } else {
                self.value(val);
            }
        });
        defadvice('ui.AutoComplete', '$angular_getLogicValue', function () {
            var options = this.self.options;
            var values = this.self.value().split(options.separator);
            var valuePrimitive = options.valuePrimitive;
            var data = this.self.listView.selectedDataItems();
            var dataItems = [];
            for (var idx = 0, length = data.length; idx < length; idx++) {
                var item = data[idx];
                var dataValue = options.dataTextField ? item[options.dataTextField] : item;
                for (var j = 0; j < values.length; j++) {
                    if (dataValue === values[j]) {
                        if (valuePrimitive) {
                            dataItems.push(dataValue);
                        } else {
                            dataItems.push(item.toJSON());
                        }
                        break;
                    }
                }
            }
            return dataItems;
        });
        defadvice('ui.AutoComplete', '$angular_setLogicValue', function (value) {
            if (value == null) {
                value = [];
            }
            var self = this.self, dataTextField = self.options.dataTextField;
            if (dataTextField && !self.options.valuePrimitive) {
                if (value.length !== undefined) {
                    value = $.map(value, function (item) {
                        return item[dataTextField];
                    });
                } else {
                    value = value[dataTextField];
                }
            }
            self.value(value);
        });
        defadvice('ui.Widget', '$angular_init', function (element, options) {
            var self = this.self;
            if (options && !$.isArray(options)) {
                var scope = self.$angular_scope;
                for (var i = self.events.length; --i >= 0;) {
                    var event = self.events[i];
                    var handler = options[event];
                    if (handler && typeof handler == 'string') {
                        options[event] = self.$angular_makeEventHandler(event, scope, handler);
                    }
                }
            }
        });
        defadvice('ui.Widget', '$angular_makeEventHandler', function (event, scope, handler) {
            handler = $parse(handler);
            return function (e) {
                digest(scope, function () {
                    handler(scope, { kendoEvent: e });
                });
            };
        });
        defadvice([
            'ui.Grid',
            'ui.ListView',
            'ui.TreeView',
            'ui.PanelBar'
        ], '$angular_makeEventHandler', function (event, scope, handler) {
            if (event != 'change') {
                return this.next();
            }
            handler = $parse(handler);
            return function (ev) {
                var widget = ev.sender;
                var options = widget.options;
                var cell, multiple, locals = { kendoEvent: ev }, elems, items, columns, colIdx;
                if (angular.isString(options.selectable)) {
                    cell = options.selectable.indexOf('cell') !== -1;
                    multiple = options.selectable.indexOf('multiple') !== -1;
                }
                elems = locals.selected = this.select();
                items = locals.data = [];
                columns = locals.columns = [];
                for (var i = 0; i < elems.length; i++) {
                    var item = cell ? elems[i].parentNode : elems[i];
                    var dataItem = widget.dataItem(item);
                    if (cell) {
                        if (angular.element.inArray(dataItem, items) < 0) {
                            items.push(dataItem);
                        }
                        colIdx = angular.element(elems[i]).index();
                        if (angular.element.inArray(colIdx, columns) < 0) {
                            columns.push(colIdx);
                        }
                    } else {
                        items.push(dataItem);
                    }
                }
                if (!multiple) {
                    locals.dataItem = locals.data = items[0];
                    locals.angularDataItem = kendo.proxyModelSetters(locals.dataItem);
                    locals.selected = elems[0];
                }
                digest(scope, function () {
                    handler(scope, locals);
                });
            };
        });
        defadvice('ui.Grid', '$angular_init', function (element, options) {
            this.next();
            if (options.columns) {
                var settings = $.extend({}, kendo.Template, options.templateSettings);
                angular.forEach(options.columns, function (col) {
                    if (col.field && !col.template && !col.format && !col.values && (col.encoded === undefined || col.encoded)) {
                        col.template = '<span ng-bind=\'' + kendo.expr(col.field, 'dataItem') + '\'>#: ' + kendo.expr(col.field, settings.paramName) + '#</span>';
                    }
                });
            }
        });
        {
            defadvice('mobile.ui.ButtonGroup', 'value', function (mew) {
                var self = this.self;
                if (mew != null) {
                    self.select(self.element.children('li.km-button').eq(mew));
                    self.trigger('change');
                    self.trigger('select', { index: self.selectedIndex });
                }
                return self.selectedIndex;
            });
            defadvice('mobile.ui.ButtonGroup', '_select', function () {
                this.next();
                this.self.trigger('change');
            });
        }
        module.directive('kendoMobileApplication', function () {
            return {
                terminal: true,
                link: function (scope, element, attrs) {
                    createWidget(scope, element, attrs, 'kendoMobileApplication', 'kendoMobileApplication');
                }
            };
        }).directive('kendoMobileView', function () {
            return {
                scope: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        attrs._instance = createWidget(scope, element, attrs, 'kendoMobileView', 'kendoMobileView');
                    },
                    post: function (scope, element, attrs) {
                        attrs._instance._layout();
                        attrs._instance._scroller();
                    }
                }
            };
        }).directive('kendoMobileDrawer', function () {
            return {
                scope: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        attrs._instance = createWidget(scope, element, attrs, 'kendoMobileDrawer', 'kendoMobileDrawer');
                    },
                    post: function (scope, element, attrs) {
                        attrs._instance._layout();
                        attrs._instance._scroller();
                    }
                }
            };
        }).directive('kendoMobileModalView', function () {
            return {
                scope: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        attrs._instance = createWidget(scope, element, attrs, 'kendoMobileModalView', 'kendoMobileModalView');
                    },
                    post: function (scope, element, attrs) {
                        attrs._instance._layout();
                        attrs._instance._scroller();
                    }
                }
            };
        }).directive('kendoMobileSplitView', function () {
            return {
                terminal: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        attrs._instance = createWidget(scope, element, attrs, 'kendoMobileSplitView', 'kendoMobileSplitView');
                    },
                    post: function (scope, element, attrs) {
                        attrs._instance._layout();
                    }
                }
            };
        }).directive('kendoMobilePane', function () {
            return {
                terminal: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        createWidget(scope, element, attrs, 'kendoMobilePane', 'kendoMobilePane');
                    }
                }
            };
        }).directive('kendoMobileLayout', function () {
            return {
                link: {
                    pre: function (scope, element, attrs) {
                        createWidget(scope, element, attrs, 'kendoMobileLayout', 'kendoMobileLayout');
                    }
                }
            };
        }).directive('kendoMobileActionSheet', function () {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    element.find('a[k-action]').each(function () {
                        $(this).attr('data-' + kendo.ns + 'action', $(this).attr('k-action'));
                    });
                    createWidget(scope, element, attrs, 'kendoMobileActionSheet', 'kendoMobileActionSheet');
                }
            };
        }).directive('kendoMobilePopOver', function () {
            return {
                terminal: true,
                link: {
                    pre: function (scope, element, attrs) {
                        attrs.defaultOptions = scope.viewOptions;
                        createWidget(scope, element, attrs, 'kendoMobilePopOver', 'kendoMobilePopOver');
                    }
                }
            };
        }).directive('kendoViewTitle', function () {
            return {
                restrict: 'E',
                replace: true,
                template: function (element) {
                    return '<span data-' + kendo.ns + 'role=\'view-title\'>' + element.html() + '</span>';
                }
            };
        }).directive('kendoMobileHeader', function () {
            return {
                restrict: 'E',
                link: function (scope, element) {
                    element.addClass('km-header').attr('data-role', 'header');
                }
            };
        }).directive('kendoMobileFooter', function () {
            return {
                restrict: 'E',
                link: function (scope, element) {
                    element.addClass('km-footer').attr('data-role', 'footer');
                }
            };
        }).directive('kendoMobileScrollViewPage', function () {
            return {
                restrict: 'E',
                replace: true,
                template: function (element) {
                    return '<div data-' + kendo.ns + 'role=\'page\'>' + element.html() + '</div>';
                }
            };
        });
        angular.forEach([
            'align',
            'icon',
            'rel',
            'transition',
            'actionsheetContext'
        ], function (attr) {
            var kAttr = 'k' + attr.slice(0, 1).toUpperCase() + attr.slice(1);
            module.directive(kAttr, function () {
                return {
                    restrict: 'A',
                    priority: 2,
                    link: function (scope, element, attrs) {
                        element.attr(kendo.attr(kendo.toHyphens(attr)), scope.$eval(attrs[kAttr]));
                    }
                };
            });
        });
        var WIDGET_TEMPLATE_OPTIONS = {
            'TreeMap': ['Template'],
            'MobileListView': [
                'HeaderTemplate',
                'Template'
            ],
            'MobileScrollView': [
                'EmptyTemplate',
                'Template'
            ],
            'Grid': [
                'AltRowTemplate',
                'DetailTemplate',
                'RowTemplate'
            ],
            'ListView': [
                'EditTemplate',
                'Template',
                'AltTemplate'
            ],
            'Pager': [
                'SelectTemplate',
                'LinkTemplate'
            ],
            'PivotGrid': [
                'ColumnHeaderTemplate',
                'DataCellTemplate',
                'RowHeaderTemplate'
            ],
            'Scheduler': [
                'AllDayEventTemplate',
                'DateHeaderTemplate',
                'EventTemplate',
                'MajorTimeHeaderTemplate',
                'MinorTimeHeaderTemplate'
            ],
            'PanelBar': ['Template'],
            'TreeView': ['Template'],
            'Validator': ['ErrorTemplate']
        };
        (function () {
            var templateDirectives = {};
            angular.forEach(WIDGET_TEMPLATE_OPTIONS, function (templates, widget) {
                angular.forEach(templates, function (template) {
                    if (!templateDirectives[template]) {
                        templateDirectives[template] = [];
                    }
                    templateDirectives[template].push('?^^kendo' + widget);
                });
            });
            angular.forEach(templateDirectives, function (parents, directive) {
                var templateName = 'k' + directive;
                var attrName = kendo.toHyphens(templateName);
                module.directive(templateName, function () {
                    return {
                        restrict: 'A',
                        require: parents,
                        terminal: true,
                        compile: function ($element, $attrs) {
                            if ($attrs[templateName] !== '') {
                                return;
                            }
                            $element.removeAttr(attrName);
                            var template = $element[0].outerHTML;
                            return function (scope, element, attrs, controllers) {
                                var controller;
                                while (!controller && controllers.length) {
                                    controller = controllers.shift();
                                }
                                if (!controller) {
                                    $log.warn(attrName + ' without a matching parent widget found. It can be one of the following: ' + parents.join(', '));
                                } else {
                                    controller.template(templateName, template);
                                    element.remove();
                                }
                            };
                        }
                    };
                });
            });
        }());
    }(window.kendo.jQuery, window.angular));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.web', [
        'kendo.core',
        'kendo.router',
        'kendo.view',
        'kendo.fx',
        'kendo.dom',
        'kendo.data.odata',
        'kendo.data.xml',
        'kendo.data',
        'kendo.ooxml',
        'kendo.excel',
        'kendo.data.signalr',
        'kendo.binder',
        'kendo.drawing',
        'kendo.validator',
        'kendo.userevents',
        'kendo.draganddrop',
        'kendo.mobile.scroller',
        'kendo.groupable',
        'kendo.reorderable',
        'kendo.resizable',
        'kendo.sortable',
        'kendo.selectable',
        'kendo.button',
        'kendo.pager',
        'kendo.popup',
        'kendo.notification',
        'kendo.tooltip',
        'kendo.list',
        'kendo.calendar',
        'kendo.datepicker',
        'kendo.dateinput',
        'kendo.autocomplete',
        'kendo.dropdownlist',
        'kendo.combobox',
        'kendo.multiselect',
        'kendo.colorpicker',
        'kendo.columnmenu',
        'kendo.columnsorter',
        'kendo.grid',
        'kendo.listview',
        'kendo.listbox',
        'kendo.filebrowser',
        'kendo.imagebrowser',
        'kendo.editor',
        'kendo.numerictextbox',
        'kendo.maskedtextbox',
        'kendo.mediaplayer',
        'kendo.menu',
        'kendo.editable',
        'kendo.pivot.fieldmenu',
        'kendo.filtercell',
        'kendo.panelbar',
        'kendo.progressbar',
        'kendo.responsivepanel',
        'kendo.tabstrip',
        'kendo.timepicker',
        'kendo.toolbar',
        'kendo.datetimepicker',
        'kendo.treeview.draganddrop',
        'kendo.treeview',
        'kendo.slider',
        'kendo.splitter',
        'kendo.upload',
        'kendo.dialog',
        'kendo.window',
        'kendo.virtuallist',
        'kendo.scheduler.view',
        'kendo.scheduler.dayview',
        'kendo.scheduler.agendaview',
        'kendo.scheduler.monthview',
        'kendo.scheduler.recurrence',
        'kendo.scheduler',
        'kendo.gantt.list',
        'kendo.gantt.timeline',
        'kendo.gantt',
        'kendo.treelist',
        'kendo.pivotgrid',
        'kendo.spreadsheet',
        'kendo.pivot.configurator',
        'kendo.angular'
    ], f);
}(function () {
    'bundle all';
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/core/kendo-core', [
        'kendo.core',
        'kendo.drawing'
    ], f);
}(function () {
    (function ($) {
        window.kendo.dataviz = window.kendo.dataviz || {};
        var drawing = kendo.drawing;
        var util = drawing.util;
        var Path = drawing.Path;
        var Group = drawing.Group;
        var Class = kendo.Class;
        var geometry = kendo.geometry;
        var Rect = geometry.Rect;
        var Circle = geometry.Circle;
        var geometryTransform = geometry.transform;
        var Segment = geometry.Segment;
        var dataviz = kendo.dataviz;
        var deepExtend = kendo.deepExtend;
        var __common_getter_js = kendo.getter;
        var X = 'x';
        var Y = 'y';
        var TOP = 'top';
        var BOTTOM = 'bottom';
        var LEFT = 'left';
        var RIGHT = 'right';
        var CENTER = 'center';
        var WIDTH = 'width';
        var HEIGHT = 'height';
        var COORD_PRECISION = 3;
        var MAX_VALUE = Number.MAX_VALUE;
        var MIN_VALUE = -Number.MAX_VALUE;
        var DEFAULT_WIDTH = 600;
        var DEFAULT_HEIGHT = 400;
        var WHITE = '#fff';
        var BLACK = '#000';
        var DEFAULT_FONT = '12px sans-serif';
        var DEFAULT_PRECISION = 10;
        var AXIS_LABEL_CLICK = 'axisLabelClick';
        var NOTE_CLICK = 'noteClick';
        var NOTE_HOVER = 'noteHover';
        var OUTSIDE = 'outside';
        var NONE = 'none';
        var CIRCLE = 'circle';
        var TRIANGLE = 'triangle';
        var CROSS = 'cross';
        var ARC = 'arc';
        var INSIDE = 'inside';
        var VALUE = 'value';
        var STRING = 'string';
        var OBJECT = 'object';
        var DATE = 'date';
        var FORMAT_REGEX = /\{\d+:?/;
        var constants = {
            X: X,
            Y: Y,
            WIDTH: WIDTH,
            HEIGHT: HEIGHT,
            DEFAULT_HEIGHT: DEFAULT_HEIGHT,
            DEFAULT_WIDTH: DEFAULT_WIDTH,
            TOP: TOP,
            LEFT: LEFT,
            BOTTOM: BOTTOM,
            RIGHT: RIGHT,
            CENTER: CENTER,
            COORD_PRECISION: COORD_PRECISION,
            DEFAULT_PRECISION: DEFAULT_PRECISION,
            CIRCLE: CIRCLE,
            TRIANGLE: TRIANGLE,
            CROSS: CROSS,
            MAX_VALUE: MAX_VALUE,
            MIN_VALUE: MIN_VALUE,
            WHITE: WHITE,
            BLACK: BLACK,
            DEFAULT_FONT: DEFAULT_FONT,
            AXIS_LABEL_CLICK: AXIS_LABEL_CLICK,
            OUTSIDE: OUTSIDE,
            INSIDE: INSIDE,
            NONE: NONE,
            NOTE_CLICK: NOTE_CLICK,
            NOTE_HOVER: NOTE_HOVER,
            VALUE: VALUE,
            STRING: STRING,
            OBJECT: OBJECT,
            DATE: DATE,
            ARC: ARC,
            FORMAT_REGEX: FORMAT_REGEX
        };
        function isArray(value) {
            return Array.isArray(value);
        }
        function addClass(element, classes) {
            var classArray = isArray(classes) ? classes : [classes];
            for (var idx = 0; idx < classArray.length; idx++) {
                var className = classArray[idx];
                if (element.className.indexOf(className) === -1) {
                    element.className += ' ' + className;
                }
            }
        }
        var SPACE_REGEX = /\s+/g;
        function removeClass(element, className) {
            if (element && element.className) {
                element.className = element.className.replace(className, '').replace(SPACE_REGEX, ' ');
            }
        }
        function alignPathToPixel(path) {
            var offset = 0.5;
            if (path.options.stroke && kendo.drawing.util.defined(path.options.stroke.width)) {
                if (path.options.stroke.width % 2 === 0) {
                    offset = 0;
                }
            }
            for (var i = 0; i < path.segments.length; i++) {
                path.segments[i].anchor().round(0).translate(offset, offset);
            }
            return path;
        }
        function clockwise(angle1, angle2) {
            return -angle1.x * angle2.y + angle1.y * angle2.x < 0;
        }
        function isObject(value) {
            return typeof value === 'object';
        }
        function isString(value) {
            return typeof value === STRING;
        }
        function isNumber(value) {
            return typeof value === 'number' && !isNaN(value);
        }
        function styleValue(value) {
            if (isNumber(value)) {
                return value + 'px';
            }
            return value;
        }
        var SIZE_STYLES_REGEX = /width|height|top|left|bottom|right/i;
        function isSizeField(field) {
            return SIZE_STYLES_REGEX.test(field);
        }
        function elementStyles(element, styles) {
            var stylesArray = isString(styles) ? [styles] : styles;
            if (isArray(stylesArray)) {
                var result = {};
                var style = window.getComputedStyle(element);
                for (var idx = 0; idx < stylesArray.length; idx++) {
                    var field = stylesArray[idx];
                    result[field] = isSizeField(field) ? parseFloat(style[field]) : style[field];
                }
                return result;
            } else if (isObject(styles)) {
                for (var field$1 in styles) {
                    element.style[field$1] = styleValue(styles[field$1]);
                }
            }
        }
        function getSpacing(value, defaultSpacing) {
            if (defaultSpacing === void 0) {
                defaultSpacing = 0;
            }
            var spacing = {
                top: 0,
                right: 0,
                bottom: 0,
                left: 0
            };
            if (typeof value === 'number') {
                spacing[TOP] = spacing[RIGHT] = spacing[BOTTOM] = spacing[LEFT] = value;
            } else {
                spacing[TOP] = value[TOP] || defaultSpacing;
                spacing[RIGHT] = value[RIGHT] || defaultSpacing;
                spacing[BOTTOM] = value[BOTTOM] || defaultSpacing;
                spacing[LEFT] = value[LEFT] || defaultSpacing;
            }
            return spacing;
        }
        function grep(array, callback) {
            var length = array.length;
            var result = [];
            for (var idx = 0; idx < length; idx++) {
                if (callback(array[idx])) {
                    result.push(array[idx]);
                }
            }
            return result;
        }
        function hasClasses(element, classNames) {
            if (element.className) {
                var names = classNames.split(' ');
                for (var idx = 0; idx < names.length; idx++) {
                    if (element.className.indexOf(names[idx]) !== -1) {
                        return true;
                    }
                }
            }
        }
        function inArray(value, array) {
            if (array) {
                return array.indexOf(value) !== -1;
            }
        }
        function interpolateValue(start, end, progress) {
            return kendo.drawing.util.round(start + (end - start) * progress, COORD_PRECISION);
        }
        var TRIGGER = 'trigger';
        var InstanceObserver = Class.extend({
            init: function (observer, handlers) {
                this.observer = observer;
                this.handlerMap = deepExtend({}, this.handlerMap, handlers);
            },
            trigger: function (name, args) {
                var ref = this;
                var observer = ref.observer;
                var handlerMap = ref.handlerMap;
                var isDefaultPrevented;
                if (handlerMap[name]) {
                    isDefaultPrevented = this.callObserver(handlerMap[name], args);
                } else if (observer[TRIGGER]) {
                    isDefaultPrevented = this.callObserver(TRIGGER, name, args);
                }
                return isDefaultPrevented;
            },
            callObserver: function (fnName) {
                var args = [], len = arguments.length - 1;
                while (len-- > 0)
                    args[len] = arguments[len + 1];
                return this.observer[fnName].apply(this.observer, args);
            },
            requiresHandlers: function (names) {
                var this$1 = this;
                if (this.observer.requiresHandlers) {
                    return this.observer.requiresHandlers(names);
                }
                for (var idx = 0; idx < names.length; idx++) {
                    if (this$1.handlerMap[names[idx]]) {
                        return true;
                    }
                }
            }
        });
        function isFunction(fn) {
            return typeof fn === 'function';
        }
        function map(array, callback) {
            var length = array.length;
            var result = [];
            for (var idx = 0; idx < length; idx++) {
                var value = callback(array[idx]);
                if (kendo.drawing.util.defined(value)) {
                    result.push(value);
                }
            }
            return result;
        }
        function mousewheelDelta(e) {
            var delta = 0;
            if (e.wheelDelta) {
                delta = -e.wheelDelta / 120;
                delta = delta > 0 ? Math.ceil(delta) : Math.floor(delta);
            }
            if (e.detail) {
                delta = kendo.drawing.util.round(e.detail / 3);
            }
            return delta;
        }
        var ref = kendo.drawing.util;
        var append = ref.append;
        var bindEvents = ref.bindEvents;
        var defined = ref.defined;
        var deg = ref.deg;
        var elementOffset = ref.elementOffset;
        var elementSize = ref.elementSize;
        var eventElement = ref.eventElement;
        var eventCoordinates = ref.eventCoordinates;
        var last = ref.last;
        var limitValue = ref.limitValue;
        var objectKey = ref.objectKey;
        var rad = ref.rad;
        var round = ref.round;
        var unbindEvents = ref.unbindEvents;
        var valueOrDefault = ref.valueOrDefault;
        var FontLoader = Class.extend({});
        FontLoader.fetchFonts = function (options, fonts, state) {
            if (state === void 0) {
                state = { depth: 0 };
            }
            var MAX_DEPTH = 5;
            if (!options || state.depth > MAX_DEPTH || !document.fonts) {
                return;
            }
            Object.keys(options).forEach(function (key) {
                var value = options[key];
                if (key === 'dataSource' || key[0] === '$' || !value) {
                    return;
                }
                if (key === 'font') {
                    fonts.push(value);
                } else if (typeof value === 'object') {
                    state.depth++;
                    FontLoader.fetchFonts(value, fonts, state);
                    state.depth--;
                }
            });
        };
        FontLoader.loadFonts = function (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();
            }
        };
        FontLoader.preloadFonts = function (options, callback) {
            var fonts = [];
            FontLoader.fetchFonts(options, fonts);
            FontLoader.loadFonts(fonts, callback);
        };
        function setDefaultOptions(type, options) {
            var proto = type.prototype;
            if (proto.options) {
                proto.options = deepExtend({}, proto.options, options);
            } else {
                proto.options = options;
            }
        }
        function sparseArrayLimits(arr) {
            var min = MAX_VALUE;
            var max = MIN_VALUE;
            for (var idx = 0, length = arr.length; idx < length; idx++) {
                var value = arr[idx];
                if (value !== null && isFinite(value)) {
                    min = Math.min(min, value);
                    max = Math.max(max, value);
                }
            }
            return {
                min: min === MAX_VALUE ? undefined : min,
                max: max === MIN_VALUE ? undefined : max
            };
        }
        var Point = Class.extend({
            init: function (x, y) {
                this.x = x || 0;
                this.y = y || 0;
            },
            clone: function () {
                return new Point(this.x, this.y);
            },
            equals: function (point) {
                return point && this.x === point.x && this.y === point.y;
            },
            rotate: function (center, degrees) {
                var theta = rad(degrees);
                var cosT = Math.cos(theta);
                var sinT = Math.sin(theta);
                var cx = center.x;
                var cy = center.y;
                var ref = this;
                var x = ref.x;
                var y = ref.y;
                this.x = round(cx + (x - cx) * cosT + (y - cy) * sinT, COORD_PRECISION);
                this.y = round(cy + (y - cy) * cosT - (x - cx) * sinT, COORD_PRECISION);
                return this;
            },
            multiply: function (a) {
                this.x *= a;
                this.y *= a;
                return this;
            },
            distanceTo: function (point) {
                var dx = this.x - point.x;
                var dy = this.y - point.y;
                return Math.sqrt(dx * dx + dy * dy);
            }
        });
        Point.onCircle = function (center, angle, radius) {
            var radians = rad(angle);
            return new Point(center.x - radius * Math.cos(radians), center.y - radius * Math.sin(radians));
        };
        var Box = Class.extend({
            init: function (x1, y1, x2, y2) {
                this.x1 = x1 || 0;
                this.y1 = y1 || 0;
                this.x2 = x2 || 0;
                this.y2 = y2 || 0;
            },
            width: function () {
                return this.x2 - this.x1;
            },
            height: function () {
                return this.y2 - this.y1;
            },
            translate: function (dx, dy) {
                this.x1 += dx;
                this.x2 += dx;
                this.y1 += dy;
                this.y2 += dy;
                return this;
            },
            move: function (x, y) {
                var height = this.height();
                var width = this.width();
                if (defined(x)) {
                    this.x1 = x;
                    this.x2 = this.x1 + width;
                }
                if (defined(y)) {
                    this.y1 = y;
                    this.y2 = this.y1 + height;
                }
                return this;
            },
            wrap: function (targetBox) {
                this.x1 = Math.min(this.x1, targetBox.x1);
                this.y1 = Math.min(this.y1, targetBox.y1);
                this.x2 = Math.max(this.x2, targetBox.x2);
                this.y2 = Math.max(this.y2, targetBox.y2);
                return this;
            },
            wrapPoint: function (point) {
                var arrayPoint = isArray(point);
                var x = arrayPoint ? point[0] : point.x;
                var y = arrayPoint ? point[1] : point.y;
                this.wrap(new Box(x, y, x, y));
                return this;
            },
            snapTo: function (targetBox, axis) {
                if (axis === X || !axis) {
                    this.x1 = targetBox.x1;
                    this.x2 = targetBox.x2;
                }
                if (axis === Y || !axis) {
                    this.y1 = targetBox.y1;
                    this.y2 = targetBox.y2;
                }
                return this;
            },
            alignTo: function (targetBox, anchor) {
                var height = this.height();
                var width = this.width();
                var axis = anchor === TOP || anchor === BOTTOM ? Y : X;
                var offset = axis === Y ? height : width;
                if (anchor === CENTER) {
                    var targetCenter = targetBox.center();
                    var center = this.center();
                    this.x1 += targetCenter.x - center.x;
                    this.y1 += targetCenter.y - center.y;
                } else if (anchor === TOP || anchor === LEFT) {
                    this[axis + 1] = targetBox[axis + 1] - offset;
                } else {
                    this[axis + 1] = targetBox[axis + 2];
                }
                this.x2 = this.x1 + width;
                this.y2 = this.y1 + height;
                return this;
            },
            shrink: function (dw, dh) {
                this.x2 -= dw;
                this.y2 -= dh;
                return this;
            },
            expand: function (dw, dh) {
                this.shrink(-dw, -dh);
                return this;
            },
            pad: function (padding) {
                var spacing = getSpacing(padding);
                this.x1 -= spacing.left;
                this.x2 += spacing.right;
                this.y1 -= spacing.top;
                this.y2 += spacing.bottom;
                return this;
            },
            unpad: function (padding) {
                var spacing = getSpacing(padding);
                spacing.left = -spacing.left;
                spacing.top = -spacing.top;
                spacing.right = -spacing.right;
                spacing.bottom = -spacing.bottom;
                return this.pad(spacing);
            },
            clone: function () {
                return new Box(this.x1, this.y1, this.x2, this.y2);
            },
            center: function () {
                return new Point(this.x1 + this.width() / 2, this.y1 + this.height() / 2);
            },
            containsPoint: function (point) {
                return point.x >= this.x1 && point.x <= this.x2 && point.y >= this.y1 && point.y <= this.y2;
            },
            points: function () {
                return [
                    new Point(this.x1, this.y1),
                    new Point(this.x2, this.y1),
                    new Point(this.x2, this.y2),
                    new Point(this.x1, this.y2)
                ];
            },
            getHash: function () {
                return [
                    this.x1,
                    this.y1,
                    this.x2,
                    this.y2
                ].join(',');
            },
            overlaps: function (box) {
                return !(box.y2 < this.y1 || this.y2 < box.y1 || box.x2 < this.x1 || this.x2 < box.x1);
            },
            rotate: function (rotation) {
                var width = this.width();
                var height = this.height();
                var ref = this.center();
                var cx = ref.x;
                var cy = ref.y;
                var r1 = rotatePoint(0, 0, cx, cy, rotation);
                var r2 = rotatePoint(width, 0, cx, cy, rotation);
                var r3 = rotatePoint(width, height, cx, cy, rotation);
                var r4 = rotatePoint(0, height, cx, cy, rotation);
                width = Math.max(r1.x, r2.x, r3.x, r4.x) - Math.min(r1.x, r2.x, r3.x, r4.x);
                height = Math.max(r1.y, r2.y, r3.y, r4.y) - Math.min(r1.y, r2.y, r3.y, r4.y);
                this.x2 = this.x1 + width;
                this.y2 = this.y1 + height;
                return this;
            },
            toRect: function () {
                return new Rect([
                    this.x1,
                    this.y1
                ], [
                    this.width(),
                    this.height()
                ]);
            },
            hasSize: function () {
                return this.width() !== 0 && this.height() !== 0;
            },
            align: function (targetBox, axis, alignment) {
                var c1 = axis + 1;
                var c2 = axis + 2;
                var sizeFunc = axis === X ? WIDTH : HEIGHT;
                var size = this[sizeFunc]();
                if (inArray(alignment, [
                        LEFT,
                        TOP
                    ])) {
                    this[c1] = targetBox[c1];
                    this[c2] = this[c1] + size;
                } else if (inArray(alignment, [
                        RIGHT,
                        BOTTOM
                    ])) {
                    this[c2] = targetBox[c2];
                    this[c1] = this[c2] - size;
                } else if (alignment === CENTER) {
                    this[c1] = targetBox[c1] + (targetBox[sizeFunc]() - size) / 2;
                    this[c2] = this[c1] + size;
                }
            }
        });
        function rotatePoint(x, y, cx, cy, angle) {
            var theta = rad(angle);
            return new Point(cx + (x - cx) * Math.cos(theta) + (y - cy) * Math.sin(theta), cy - (x - cx) * Math.sin(theta) + (y - cy) * Math.cos(theta));
        }
        var Ring = Class.extend({
            init: function (center, innerRadius, radius, startAngle, angle) {
                this.center = center;
                this.innerRadius = innerRadius;
                this.radius = radius;
                this.startAngle = startAngle;
                this.angle = angle;
            },
            clone: function () {
                return new Ring(this.center, this.innerRadius, this.radius, this.startAngle, this.angle);
            },
            middle: function () {
                return this.startAngle + this.angle / 2;
            },
            setRadius: function (newRadius, innerRadius) {
                if (innerRadius) {
                    this.innerRadius = newRadius;
                } else {
                    this.radius = newRadius;
                }
                return this;
            },
            point: function (angle, innerRadius) {
                var radianAngle = rad(angle);
                var ax = Math.cos(radianAngle);
                var ay = Math.sin(radianAngle);
                var radius = innerRadius ? this.innerRadius : this.radius;
                var x = round(this.center.x - ax * radius, COORD_PRECISION);
                var y = round(this.center.y - ay * radius, COORD_PRECISION);
                return new Point(x, y);
            },
            adjacentBox: function (distance, width, height) {
                var sector = this.clone().expand(distance);
                var midAndle = sector.middle();
                var midPoint = sector.point(midAndle);
                var hw = width / 2;
                var hh = height / 2;
                var sa = Math.sin(rad(midAndle));
                var ca = Math.cos(rad(midAndle));
                var x = midPoint.x - hw;
                var y = midPoint.y - hh;
                if (Math.abs(sa) < 0.9) {
                    x += hw * -ca / Math.abs(ca);
                }
                if (Math.abs(ca) < 0.9) {
                    y += hh * -sa / Math.abs(sa);
                }
                return new Box(x, y, x + width, y + height);
            },
            containsPoint: function (p) {
                var center = this.center;
                var innerRadius = this.innerRadius;
                var radius = this.radius;
                var startAngle = this.startAngle;
                var endAngle = this.startAngle + this.angle;
                var dx = p.x - center.x;
                var dy = p.y - center.y;
                var vector = new Point(dx, dy);
                var startPoint = this.point(startAngle);
                var startVector = new Point(startPoint.x - center.x, startPoint.y - center.y);
                var endPoint = this.point(endAngle);
                var endVector = new Point(endPoint.x - center.x, endPoint.y - center.y);
                var dist = round(dx * dx + dy * dy, COORD_PRECISION);
                return (startVector.equals(vector) || clockwise(startVector, vector)) && !clockwise(endVector, vector) && dist >= innerRadius * innerRadius && dist <= radius * radius;
            },
            getBBox: function () {
                var this$1 = this;
                var box = new Box(MAX_VALUE, MAX_VALUE, MIN_VALUE, MIN_VALUE);
                var startAngle = round(this.startAngle % 360);
                var endAngle = round((startAngle + this.angle) % 360);
                var innerRadius = this.innerRadius;
                var allAngles = [
                    0,
                    90,
                    180,
                    270,
                    startAngle,
                    endAngle
                ].sort(numericComparer);
                var startAngleIndex = allAngles.indexOf(startAngle);
                var endAngleIndex = allAngles.indexOf(endAngle);
                var angles;
                if (startAngle === endAngle) {
                    angles = allAngles;
                } else {
                    if (startAngleIndex < endAngleIndex) {
                        angles = allAngles.slice(startAngleIndex, endAngleIndex + 1);
                    } else {
                        angles = [].concat(allAngles.slice(0, endAngleIndex + 1), allAngles.slice(startAngleIndex, allAngles.length));
                    }
                }
                for (var i = 0; i < angles.length; i++) {
                    var point = this$1.point(angles[i]);
                    box.wrapPoint(point);
                    box.wrapPoint(point, innerRadius);
                }
                if (!innerRadius) {
                    box.wrapPoint(this.center);
                }
                return box;
            },
            expand: function (value) {
                this.radius += value;
                return this;
            }
        });
        function numericComparer(a, b) {
            return a - b;
        }
        var Sector = Ring.extend({
            init: function (center, radius, startAngle, angle) {
                Ring.fn.init.call(this, center, 0, radius, startAngle, angle);
            },
            expand: function (value) {
                return Ring.fn.expand.call(this, value);
            },
            clone: function () {
                return new Sector(this.center, this.radius, this.startAngle, this.angle);
            },
            setRadius: function (newRadius) {
                this.radius = newRadius;
                return this;
            }
        });
        var ShapeBuilder = Class.extend({
            createRing: function (sector, options) {
                var startAngle = sector.startAngle + 180;
                var endAngle = sector.angle + startAngle;
                var center = new geometry.Point(sector.center.x, sector.center.y);
                var radius = Math.max(sector.radius, 0);
                var innerRadius = Math.max(sector.innerRadius, 0);
                var arc = new geometry.Arc(center, {
                    startAngle: startAngle,
                    endAngle: endAngle,
                    radiusX: radius,
                    radiusY: radius
                });
                var path = Path.fromArc(arc, options).close();
                if (innerRadius) {
                    arc.radiusX = arc.radiusY = innerRadius;
                    var innerEnd = arc.pointAt(endAngle);
                    path.lineTo(innerEnd.x, innerEnd.y);
                    path.arc(endAngle, startAngle, innerRadius, innerRadius, true);
                } else {
                    path.lineTo(center.x, center.y);
                }
                return path;
            }
        });
        ShapeBuilder.current = new ShapeBuilder();
        var ChartElement = Class.extend({
            init: function (options) {
                this.children = [];
                this.options = deepExtend({}, this.options, options);
            },
            reflow: function (targetBox) {
                var children = this.children;
                var box;
                for (var i = 0; i < children.length; i++) {
                    var currentChild = children[i];
                    currentChild.reflow(targetBox);
                    box = box ? box.wrap(currentChild.box) : currentChild.box.clone();
                }
                this.box = box || targetBox;
            },
            destroy: function () {
                var children = this.children;
                if (this.animation) {
                    this.animation.destroy();
                }
                for (var i = 0; i < children.length; i++) {
                    children[i].destroy();
                }
            },
            getRoot: function () {
                var parent = this.parent;
                return parent ? parent.getRoot() : null;
            },
            getSender: function () {
                var service = this.getService();
                if (service) {
                    return service.sender;
                }
            },
            getService: function () {
                var element = this;
                while (element) {
                    if (element.chartService) {
                        return element.chartService;
                    }
                    element = element.parent;
                }
            },
            translateChildren: function (dx, dy) {
                var children = this.children;
                var childrenCount = children.length;
                for (var i = 0; i < childrenCount; i++) {
                    children[i].box.translate(dx, dy);
                }
            },
            append: function () {
                var arguments$1 = arguments;
                var this$1 = this;
                for (var i = 0; i < arguments.length; i++) {
                    var item = arguments$1[i];
                    this$1.children.push(item);
                    item.parent = this$1;
                }
            },
            renderVisual: function () {
                if (this.options.visible === false) {
                    return;
                }
                this.createVisual();
                this.addVisual();
                this.renderChildren();
                this.createAnimation();
                this.renderComplete();
            },
            addVisual: function () {
                if (this.visual) {
                    this.visual.chartElement = this;
                    if (this.parent) {
                        this.parent.appendVisual(this.visual);
                    }
                }
            },
            renderChildren: function () {
                var children = this.children;
                var length = children.length;
                for (var i = 0; i < length; i++) {
                    children[i].renderVisual();
                }
            },
            createVisual: function () {
                this.visual = new Group({
                    zIndex: this.options.zIndex,
                    visible: valueOrDefault(this.options.visible, true)
                });
            },
            createAnimation: function () {
                if (this.visual) {
                    this.animation = drawing.Animation.create(this.visual, this.options.animation);
                }
            },
            appendVisual: function (childVisual) {
                if (!childVisual.chartElement) {
                    childVisual.chartElement = this;
                }
                if (childVisual.options.noclip) {
                    this.clipRoot().visual.append(childVisual);
                } else if (defined(childVisual.options.zIndex)) {
                    this.stackRoot().stackVisual(childVisual);
                } else if (this.isStackRoot) {
                    this.stackVisual(childVisual);
                } else if (this.visual) {
                    this.visual.append(childVisual);
                } else {
                    this.parent.appendVisual(childVisual);
                }
            },
            clipRoot: function () {
                if (this.parent) {
                    return this.parent.clipRoot();
                }
                return this;
            },
            stackRoot: function () {
                if (this.parent) {
                    return this.parent.stackRoot();
                }
                return this;
            },
            stackVisual: function (childVisual) {
                var zIndex = childVisual.options.zIndex || 0;
                var visuals = this.visual.children;
                var length = visuals.length;
                var pos;
                for (pos = 0; pos < length; pos++) {
                    var sibling = visuals[pos];
                    var here = valueOrDefault(sibling.options.zIndex, 0);
                    if (here > zIndex) {
                        break;
                    }
                }
                this.visual.insert(pos, childVisual);
            },
            traverse: function (callback) {
                var children = this.children;
                var length = children.length;
                for (var i = 0; i < length; i++) {
                    var child = children[i];
                    callback(child);
                    if (child.traverse) {
                        child.traverse(callback);
                    }
                }
            },
            closest: function (match) {
                var element = this;
                var matched = false;
                while (element && !matched) {
                    matched = match(element);
                    if (!matched) {
                        element = element.parent;
                    }
                }
                if (matched) {
                    return element;
                }
            },
            renderComplete: function () {
            },
            hasHighlight: function () {
                var options = (this.options || {}).highlight;
                return !(!this.createHighlight || options && options.visible === false);
            },
            toggleHighlight: function (show) {
                var this$1 = this;
                var options = (this.options || {}).highlight;
                var customVisual = (options || {}).visual;
                var highlight = this._highlight;
                if (!highlight) {
                    var highlightOptions = {
                        fill: {
                            color: WHITE,
                            opacity: 0.2
                        },
                        stroke: {
                            color: WHITE,
                            width: 1,
                            opacity: 0.2
                        }
                    };
                    if (customVisual) {
                        highlight = this._highlight = customVisual($.extend(this.highlightVisualArgs(), {
                            createVisual: function () {
                                return this$1.createHighlight(highlightOptions);
                            },
                            sender: this.getSender(),
                            series: this.series,
                            dataItem: this.dataItem,
                            category: this.category,
                            value: this.value,
                            percentage: this.percentage,
                            runningTotal: this.runningTotal,
                            total: this.total
                        }));
                        if (!highlight) {
                            return;
                        }
                    } else {
                        highlight = this._highlight = this.createHighlight(highlightOptions);
                    }
                    highlight.options.zIndex = this.options.zIndex;
                    this.appendVisual(highlight);
                }
                highlight.visible(show);
            },
            createGradientOverlay: function (element, options, gradientOptions) {
                var overlay = new Path($.extend({
                    stroke: { color: 'none' },
                    fill: this.createGradient(gradientOptions),
                    closed: element.options.closed
                }, options));
                overlay.segments.elements(element.segments.elements());
                return overlay;
            },
            createGradient: function (options) {
                if (this.parent) {
                    return this.parent.createGradient(options);
                }
            }
        });
        ChartElement.prototype.options = {};
        var BoxElement = ChartElement.extend({
            init: function (options) {
                ChartElement.fn.init.call(this, options);
                this.options.margin = getSpacing(this.options.margin);
                this.options.padding = getSpacing(this.options.padding);
            },
            reflow: function (targetBox) {
                var this$1 = this;
                var options = this.options;
                var width = options.width;
                var height = options.height;
                var shrinkToFit = options.shrinkToFit;
                var hasSetSize = width && height;
                var margin = options.margin;
                var padding = options.padding;
                var borderWidth = options.border.width;
                var box;
                var reflowPaddingBox = function () {
                    this$1.align(targetBox, X, options.align);
                    this$1.align(targetBox, Y, options.vAlign);
                    this$1.paddingBox = box.clone().unpad(margin).unpad(borderWidth);
                };
                var contentBox = targetBox.clone();
                if (hasSetSize) {
                    contentBox.x2 = contentBox.x1 + width;
                    contentBox.y2 = contentBox.y1 + height;
                }
                if (shrinkToFit) {
                    contentBox.unpad(margin).unpad(borderWidth).unpad(padding);
                }
                ChartElement.fn.reflow.call(this, contentBox);
                if (hasSetSize) {
                    box = this.box = new Box(0, 0, width, height);
                } else {
                    box = this.box;
                }
                if (shrinkToFit && hasSetSize) {
                    reflowPaddingBox();
                    contentBox = this.contentBox = this.paddingBox.clone().unpad(padding);
                } else {
                    contentBox = this.contentBox = box.clone();
                    box.pad(padding).pad(borderWidth).pad(margin);
                    reflowPaddingBox();
                }
                this.translateChildren(box.x1 - contentBox.x1 + margin.left + borderWidth + padding.left, box.y1 - contentBox.y1 + margin.top + borderWidth + padding.top);
                var children = this.children;
                for (var i = 0; i < children.length; i++) {
                    var item = children[i];
                    item.reflow(item.box);
                }
            },
            align: function (targetBox, axis, alignment) {
                this.box.align(targetBox, axis, alignment);
            },
            hasBox: function () {
                var options = this.options;
                return options.border.width || options.background;
            },
            createVisual: function () {
                ChartElement.fn.createVisual.call(this);
                var options = this.options;
                if (options.visible && this.hasBox()) {
                    this.visual.append(Path.fromRect(this.paddingBox.toRect(), this.visualStyle()));
                }
            },
            visualStyle: function () {
                var options = this.options;
                var border = options.border || {};
                return {
                    stroke: {
                        width: border.width,
                        color: border.color,
                        opacity: valueOrDefault(border.opacity, options.opacity),
                        dashType: border.dashType
                    },
                    fill: {
                        color: options.background,
                        opacity: options.opacity
                    },
                    cursor: options.cursor
                };
            }
        });
        setDefaultOptions(BoxElement, {
            align: LEFT,
            vAlign: TOP,
            margin: {},
            padding: {},
            border: {
                color: BLACK,
                width: 0
            },
            background: '',
            shrinkToFit: false,
            width: 0,
            height: 0,
            visible: true
        });
        var ShapeElement = BoxElement.extend({
            init: function (options, pointData) {
                BoxElement.fn.init.call(this, options);
                this.pointData = pointData;
            },
            getElement: function () {
                var ref = this;
                var options = ref.options;
                var box = ref.paddingBox;
                var type = options.type;
                var rotation = options.rotation;
                var center = box.center();
                var halfWidth = box.width() / 2;
                if (!options.visible || !this.hasBox()) {
                    return null;
                }
                var style = this.visualStyle();
                var element;
                if (type === CIRCLE) {
                    element = new drawing.Circle(new Circle([
                        round(box.x1 + halfWidth, COORD_PRECISION),
                        round(box.y1 + box.height() / 2, COORD_PRECISION)
                    ], halfWidth), style);
                } else if (type === TRIANGLE) {
                    element = Path.fromPoints([
                        [
                            box.x1 + halfWidth,
                            box.y1
                        ],
                        [
                            box.x1,
                            box.y2
                        ],
                        [
                            box.x2,
                            box.y2
                        ]
                    ], style).close();
                } else if (type === CROSS) {
                    element = new drawing.MultiPath(style);
                    element.moveTo(box.x1, box.y1).lineTo(box.x2, box.y2);
                    element.moveTo(box.x1, box.y2).lineTo(box.x2, box.y1);
                } else {
                    element = Path.fromRect(box.toRect(), style);
                }
                if (rotation) {
                    element.transform(geometryTransform().rotate(-rotation, [
                        center.x,
                        center.y
                    ]));
                }
                element.options.zIndex = options.zIndex;
                return element;
            },
            createElement: function () {
                var this$1 = this;
                var customVisual = this.options.visual;
                var pointData = this.pointData || {};
                var visual;
                if (customVisual) {
                    visual = customVisual({
                        value: pointData.value,
                        dataItem: pointData.dataItem,
                        sender: this.getSender(),
                        series: pointData.series,
                        category: pointData.category,
                        rect: this.paddingBox.toRect(),
                        options: this.visualOptions(),
                        createVisual: function () {
                            return this$1.getElement();
                        }
                    });
                } else {
                    visual = this.getElement();
                }
                return visual;
            },
            visualOptions: function () {
                var options = this.options;
                return {
                    background: options.background,
                    border: options.border,
                    margin: options.margin,
                    padding: options.padding,
                    type: options.type,
                    size: options.width,
                    visible: options.visible
                };
            },
            createVisual: function () {
                this.visual = this.createElement();
            }
        });
        setDefaultOptions(ShapeElement, {
            type: CIRCLE,
            align: CENTER,
            vAlign: CENTER
        });
        var LINEAR = 'linear';
        var RADIAL = 'radial';
        var GRADIENTS = {
            glass: {
                type: LINEAR,
                rotation: 0,
                stops: [
                    {
                        offset: 0,
                        color: WHITE,
                        opacity: 0
                    },
                    {
                        offset: 0.25,
                        color: WHITE,
                        opacity: 0.3
                    },
                    {
                        offset: 1,
                        color: WHITE,
                        opacity: 0
                    }
                ]
            },
            sharpBevel: {
                type: RADIAL,
                stops: [
                    {
                        offset: 0,
                        color: WHITE,
                        opacity: 0.55
                    },
                    {
                        offset: 0.65,
                        color: WHITE,
                        opacity: 0
                    },
                    {
                        offset: 0.95,
                        color: WHITE,
                        opacity: 0.25
                    }
                ]
            },
            roundedBevel: {
                type: RADIAL,
                stops: [
                    {
                        offset: 0.33,
                        color: WHITE,
                        opacity: 0.06
                    },
                    {
                        offset: 0.83,
                        color: WHITE,
                        opacity: 0.2
                    },
                    {
                        offset: 0.95,
                        color: WHITE,
                        opacity: 0
                    }
                ]
            },
            roundedGlass: {
                type: RADIAL,
                supportVML: false,
                stops: [
                    {
                        offset: 0,
                        color: WHITE,
                        opacity: 0
                    },
                    {
                        offset: 0.5,
                        color: WHITE,
                        opacity: 0.3
                    },
                    {
                        offset: 0.99,
                        color: WHITE,
                        opacity: 0
                    }
                ]
            },
            sharpGlass: {
                type: RADIAL,
                supportVML: false,
                stops: [
                    {
                        offset: 0,
                        color: WHITE,
                        opacity: 0.2
                    },
                    {
                        offset: 0.15,
                        color: WHITE,
                        opacity: 0.15
                    },
                    {
                        offset: 0.17,
                        color: WHITE,
                        opacity: 0.35
                    },
                    {
                        offset: 0.85,
                        color: WHITE,
                        opacity: 0.05
                    },
                    {
                        offset: 0.87,
                        color: WHITE,
                        opacity: 0.15
                    },
                    {
                        offset: 0.99,
                        color: WHITE,
                        opacity: 0
                    }
                ]
            },
            bubbleShadow: {
                type: RADIAL,
                center: [
                    0.5,
                    0.5
                ],
                radius: 0.5
            }
        };
        function boxDiff(r, s) {
            if (r.x1 === s.x1 && r.y1 === s.y1 && r.x2 === s.x2 && r.y2 === s.y2) {
                return s;
            }
            var a = Math.min(r.x1, s.x1);
            var b = Math.max(r.x1, s.x1);
            var c = Math.min(r.x2, s.x2);
            var d = Math.max(r.x2, s.x2);
            var e = Math.min(r.y1, s.y1);
            var f = Math.max(r.y1, s.y1);
            var g = Math.min(r.y2, s.y2);
            var h = Math.max(r.y2, s.y2);
            var boxes = [];
            boxes[0] = new Box(b, e, c, f);
            boxes[1] = new Box(a, f, b, g);
            boxes[2] = new Box(c, f, d, g);
            boxes[3] = new Box(b, g, c, h);
            if (r.x1 === a && r.y1 === e || s.x1 === a && s.y1 === e) {
                boxes[4] = new Box(a, e, b, f);
                boxes[5] = new Box(c, g, d, h);
            } else {
                boxes[4] = new Box(c, e, d, f);
                boxes[5] = new Box(a, g, b, h);
            }
            return grep(boxes, function (box) {
                return box.height() > 0 && box.width() > 0;
            })[0];
        }
        var RootElement = ChartElement.extend({
            init: function (options) {
                ChartElement.fn.init.call(this, options);
                var rootOptions = this.options;
                rootOptions.width = parseInt(rootOptions.width, 10);
                rootOptions.height = parseInt(rootOptions.height, 10);
                this.gradients = {};
            },
            reflow: function () {
                var ref = this;
                var options = ref.options;
                var children = ref.children;
                var currentBox = new Box(0, 0, options.width, options.height);
                this.box = currentBox.unpad(options.margin);
                for (var i = 0; i < children.length; i++) {
                    children[i].reflow(currentBox);
                    currentBox = boxDiff(currentBox, children[i].box) || new Box();
                }
            },
            createVisual: function () {
                this.visual = new Group();
                this.createBackground();
            },
            createBackground: function () {
                var options = this.options;
                var border = options.border || {};
                var box = this.box.clone().pad(options.margin).unpad(border.width);
                var background = Path.fromRect(box.toRect(), {
                    stroke: {
                        color: border.width ? border.color : '',
                        width: border.width,
                        dashType: border.dashType
                    },
                    fill: {
                        color: options.background,
                        opacity: options.opacity
                    },
                    zIndex: -10
                });
                this.visual.append(background);
            },
            getRoot: function () {
                return this;
            },
            createGradient: function (options) {
                var gradients = this.gradients;
                var hashCode = objectKey(options);
                var gradient = GRADIENTS[options.gradient];
                var drawingGradient;
                if (gradients[hashCode]) {
                    drawingGradient = gradients[hashCode];
                } else {
                    var gradientOptions = $.extend({}, gradient, options);
                    if (gradient.type === 'linear') {
                        drawingGradient = new drawing.LinearGradient(gradientOptions);
                    } else {
                        if (options.innerRadius) {
                            gradientOptions.stops = innerRadialStops(gradientOptions);
                        }
                        drawingGradient = new drawing.RadialGradient(gradientOptions);
                        drawingGradient.supportVML = gradient.supportVML !== false;
                    }
                    gradients[hashCode] = drawingGradient;
                }
                return drawingGradient;
            }
        });
        setDefaultOptions(RootElement, {
            width: DEFAULT_WIDTH,
            height: DEFAULT_HEIGHT,
            background: WHITE,
            border: {
                color: BLACK,
                width: 0
            },
            margin: getSpacing(5),
            zIndex: -2
        });
        function innerRadialStops(options) {
            var stops = options.stops;
            var usedSpace = options.innerRadius / options.radius * 100;
            var length = stops.length;
            var currentStops = [];
            for (var i = 0; i < length; i++) {
                var currentStop = $.extend({}, stops[i]);
                currentStop.offset = (currentStop.offset * (100 - usedSpace) + usedSpace) / 100;
                currentStops.push(currentStop);
            }
            return currentStops;
        }
        var FloatElement = ChartElement.extend({
            init: function (options) {
                ChartElement.fn.init.call(this, options);
                this._initDirection();
            },
            _initDirection: function () {
                var options = this.options;
                if (options.vertical) {
                    this.groupAxis = X;
                    this.elementAxis = Y;
                    this.groupSizeField = WIDTH;
                    this.elementSizeField = HEIGHT;
                    this.groupSpacing = options.spacing;
                    this.elementSpacing = options.vSpacing;
                } else {
                    this.groupAxis = Y;
                    this.elementAxis = X;
                    this.groupSizeField = HEIGHT;
                    this.elementSizeField = WIDTH;
                    this.groupSpacing = options.vSpacing;
                    this.elementSpacing = options.spacing;
                }
            },
            reflow: function (targetBox) {
                this.box = targetBox.clone();
                this.reflowChildren();
            },
            reflowChildren: function () {
                var this$1 = this;
                var ref = this;
                var box = ref.box;
                var elementAxis = ref.elementAxis;
                var groupAxis = ref.groupAxis;
                var elementSizeField = ref.elementSizeField;
                var groupSizeField = ref.groupSizeField;
                var ref$1 = this.groupOptions();
                var groups = ref$1.groups;
                var groupsSize = ref$1.groupsSize;
                var maxGroupElementsSize = ref$1.maxGroupElementsSize;
                var groupsCount = groups.length;
                var groupsStart = box[groupAxis + 1] + this.alignStart(groupsSize, box[groupSizeField]());
                if (groupsCount) {
                    var groupStart = groupsStart;
                    for (var groupIdx = 0; groupIdx < groupsCount; groupIdx++) {
                        var group = groups[groupIdx];
                        var groupElements = group.groupElements;
                        var elementStart = box[elementAxis + 1];
                        var groupElementsCount = groupElements.length;
                        for (var idx = 0; idx < groupElementsCount; idx++) {
                            var element = groupElements[idx];
                            var elementSize$$1 = this$1.elementSize(element);
                            var groupElementStart = groupStart + this$1.alignStart(elementSize$$1[groupSizeField], group.groupSize);
                            var elementBox = new Box();
                            elementBox[groupAxis + 1] = groupElementStart;
                            elementBox[groupAxis + 2] = groupElementStart + elementSize$$1[groupSizeField];
                            elementBox[elementAxis + 1] = elementStart;
                            elementBox[elementAxis + 2] = elementStart + elementSize$$1[elementSizeField];
                            element.reflow(elementBox);
                            elementStart += elementSize$$1[elementSizeField] + this$1.elementSpacing;
                        }
                        groupStart += group.groupSize + this$1.groupSpacing;
                    }
                    box[groupAxis + 1] = groupsStart;
                    box[groupAxis + 2] = groupsStart + groupsSize;
                    box[elementAxis + 2] = box[elementAxis + 1] + maxGroupElementsSize;
                }
            },
            alignStart: function (size, maxSize) {
                var start = 0;
                var align = this.options.align;
                if (align === RIGHT || align === BOTTOM) {
                    start = maxSize - size;
                } else if (align === CENTER) {
                    start = (maxSize - size) / 2;
                }
                return start;
            },
            groupOptions: function () {
                var this$1 = this;
                var ref = this;
                var box = ref.box;
                var children = ref.children;
                var elementSizeField = ref.elementSizeField;
                var groupSizeField = ref.groupSizeField;
                var elementSpacing = ref.elementSpacing;
                var groupSpacing = ref.groupSpacing;
                var maxSize = round(box[elementSizeField]());
                var childrenCount = children.length;
                var groups = [];
                var groupSize = 0;
                var groupElementsSize = 0;
                var groupsSize = 0;
                var maxGroupElementsSize = 0;
                var groupElements = [];
                for (var idx = 0; idx < childrenCount; idx++) {
                    var element = children[idx];
                    if (!element.box) {
                        element.reflow(box);
                    }
                    var elementSize$$1 = this$1.elementSize(element);
                    if (this$1.options.wrap && round(groupElementsSize + elementSpacing + elementSize$$1[elementSizeField]) > maxSize) {
                        groups.push({
                            groupElements: groupElements,
                            groupSize: groupSize,
                            groupElementsSize: groupElementsSize
                        });
                        maxGroupElementsSize = Math.max(maxGroupElementsSize, groupElementsSize);
                        groupsSize += groupSpacing + groupSize;
                        groupSize = 0;
                        groupElementsSize = 0;
                        groupElements = [];
                    }
                    groupSize = Math.max(groupSize, elementSize$$1[groupSizeField]);
                    if (groupElementsSize > 0) {
                        groupElementsSize += elementSpacing;
                    }
                    groupElementsSize += elementSize$$1[elementSizeField];
                    groupElements.push(element);
                }
                groups.push({
                    groupElements: groupElements,
                    groupSize: groupSize,
                    groupElementsSize: groupElementsSize
                });
                maxGroupElementsSize = Math.max(maxGroupElementsSize, groupElementsSize);
                groupsSize += groupSize;
                return {
                    groups: groups,
                    groupsSize: groupsSize,
                    maxGroupElementsSize: maxGroupElementsSize
                };
            },
            elementSize: function (element) {
                return {
                    width: element.box.width(),
                    height: element.box.height()
                };
            },
            createVisual: function () {
            }
        });
        setDefaultOptions(FloatElement, {
            vertical: true,
            wrap: true,
            vSpacing: 0,
            spacing: 0
        });
        var DrawingText = drawing.Text;
        var Text = ChartElement.extend({
            init: function (content, options) {
                ChartElement.fn.init.call(this, options);
                this.content = content;
                this.reflow(new Box());
            },
            reflow: function (targetBox) {
                var options = this.options;
                var size = options.size = util.measureText(this.content, { font: options.font });
                this.baseline = size.baseline;
                this.box = new Box(targetBox.x1, targetBox.y1, targetBox.x1 + size.width, targetBox.y1 + size.height);
            },
            createVisual: function () {
                var ref = this.options;
                var font = ref.font;
                var color = ref.color;
                var opacity = ref.opacity;
                var cursor = ref.cursor;
                this.visual = new DrawingText(this.content, this.box.toRect().topLeft(), {
                    font: font,
                    fill: {
                        color: color,
                        opacity: opacity
                    },
                    cursor: cursor
                });
            }
        });
        setDefaultOptions(Text, {
            font: DEFAULT_FONT,
            color: BLACK
        });
        function rectToBox(rect) {
            var origin = rect.origin;
            var bottomRight = rect.bottomRight();
            return new Box(origin.x, origin.y, bottomRight.x, bottomRight.y);
        }
        var ROWS_SPLIT_REGEX = /\n|\\n/m;
        var TextBox = BoxElement.extend({
            init: function (content, options) {
                BoxElement.fn.init.call(this, options);
                this.content = content;
                this._initContainer();
                if (this.options._autoReflow !== false) {
                    this.reflow(new Box());
                }
            },
            _initContainer: function () {
                var options = this.options;
                var rows = String(this.content).split(ROWS_SPLIT_REGEX);
                var floatElement = new FloatElement({
                    vertical: true,
                    align: options.align,
                    wrap: false
                });
                var textOptions = deepExtend({}, options, {
                    opacity: 1,
                    animation: null
                });
                this.container = floatElement;
                this.append(floatElement);
                for (var rowIdx = 0; rowIdx < rows.length; rowIdx++) {
                    var text = new Text(rows[rowIdx].trim(), textOptions);
                    floatElement.append(text);
                }
            },
            reflow: function (targetBox) {
                var options = this.options;
                var visualFn = options.visual;
                this.container.options.align = options.align;
                if (visualFn && !this._boxReflow) {
                    var visualBox = targetBox;
                    if (!visualBox.hasSize()) {
                        this._boxReflow = true;
                        this.reflow(visualBox);
                        this._boxReflow = false;
                        visualBox = this.box;
                    }
                    var visual = this.visual = visualFn(this.visualContext(visualBox));
                    if (visual) {
                        visualBox = rectToBox(visual.clippedBBox() || new Rect());
                        visual.options.zIndex = options.zIndex;
                        visual.options.noclip = options.noclip;
                    }
                    this.box = this.contentBox = this.paddingBox = visualBox;
                } else {
                    BoxElement.fn.reflow.call(this, targetBox);
                    if (options.rotation) {
                        var margin = getSpacing(options.margin);
                        var box = this.box.unpad(margin);
                        this.targetBox = targetBox;
                        this.normalBox = box.clone();
                        box = this.rotate();
                        box.translate(margin.left - margin.right, margin.top - margin.bottom);
                        this.rotatedBox = box.clone();
                        box.pad(margin);
                    }
                }
            },
            createVisual: function () {
                var options = this.options;
                if (!options.visible) {
                    return;
                }
                this.visual = new Group({
                    transform: this.rotationTransform(),
                    zIndex: options.zIndex,
                    noclip: options.noclip
                });
                if (this.hasBox()) {
                    var box = Path.fromRect(this.paddingBox.toRect(), this.visualStyle());
                    this.visual.append(box);
                }
            },
            renderVisual: function () {
                if (this.options.visual) {
                    this.addVisual();
                    this.createAnimation();
                } else {
                    BoxElement.fn.renderVisual.call(this);
                }
            },
            visualOptions: function () {
                var options = this.options;
                return {
                    background: options.background,
                    border: options.border,
                    color: options.color,
                    font: options.font,
                    margin: options.margin,
                    padding: options.padding,
                    visible: options.visible
                };
            },
            visualContext: function (targetBox) {
                var this$1 = this;
                return {
                    text: this.content,
                    rect: targetBox.toRect(),
                    sender: this.getSender(),
                    options: this.visualOptions(),
                    createVisual: function () {
                        this$1._boxReflow = true;
                        this$1.reflow(targetBox);
                        this$1._boxReflow = false;
                        return this$1.getDefaultVisual();
                    }
                };
            },
            getDefaultVisual: function () {
                this.createVisual();
                this.renderChildren();
                var visual = this.visual;
                delete this.visual;
                return visual;
            },
            rotate: function () {
                var options = this.options;
                this.box.rotate(options.rotation);
                this.align(this.targetBox, X, options.align);
                this.align(this.targetBox, Y, options.vAlign);
                return this.box;
            },
            rotationTransform: function () {
                var rotation = this.options.rotation;
                if (!rotation) {
                    return null;
                }
                var ref = this.normalBox.center();
                var cx = ref.x;
                var cy = ref.y;
                var boxCenter = this.rotatedBox.center();
                return geometryTransform().translate(boxCenter.x - cx, boxCenter.y - cy).rotate(rotation, [
                    cx,
                    cy
                ]);
            }
        });
        var Title = ChartElement.extend({
            init: function (options) {
                ChartElement.fn.init.call(this, options);
                this.append(new TextBox(this.options.text, $.extend({}, this.options, { vAlign: this.options.position })));
            },
            reflow: function (targetBox) {
                ChartElement.fn.reflow.call(this, targetBox);
                this.box.snapTo(targetBox, X);
            }
        });
        Title.buildTitle = function (options, parent, defaultOptions) {
            var titleOptions = options;
            if (typeof options === 'string') {
                titleOptions = { text: options };
            }
            titleOptions = $.extend({ visible: true }, defaultOptions, titleOptions);
            var title;
            if (titleOptions && titleOptions.visible && titleOptions.text) {
                title = new Title(titleOptions);
                parent.append(title);
            }
            return title;
        };
        setDefaultOptions(Title, {
            color: BLACK,
            position: TOP,
            align: CENTER,
            margin: getSpacing(5),
            padding: getSpacing(5)
        });
        var AxisLabel = TextBox.extend({
            init: function (value, text, index, dataItem, options) {
                TextBox.fn.init.call(this, text, options);
                this.text = text;
                this.value = value;
                this.index = index;
                this.dataItem = dataItem;
                this.reflow(new Box());
            },
            visualContext: function (targetBox) {
                var context = TextBox.fn.visualContext.call(this, targetBox);
                context.value = this.value;
                context.dataItem = this.dataItem;
                context.format = this.options.format;
                context.culture = this.options.culture;
                return context;
            },
            click: function (widget, e) {
                widget.trigger(AXIS_LABEL_CLICK, {
                    element: eventElement(e),
                    value: this.value,
                    text: this.text,
                    index: this.index,
                    dataItem: this.dataItem,
                    axis: this.parent.options
                });
            },
            rotate: function () {
                if (this.options.alignRotation !== CENTER) {
                    var box = this.normalBox.toRect();
                    var transform = this.rotationTransform();
                    this.box = rectToBox(box.bbox(transform.matrix()));
                } else {
                    TextBox.fn.rotate.call(this);
                }
                return this.box;
            },
            rotationTransform: function () {
                var options = this.options;
                var rotation = options.rotation;
                if (!rotation) {
                    return null;
                }
                if (options.alignRotation === CENTER) {
                    return TextBox.fn.rotationTransform.call(this);
                }
                var rotationMatrix = geometryTransform().rotate(rotation).matrix();
                var box = this.normalBox.toRect();
                var rect = this.targetBox.toRect();
                var rotationOrigin = options.rotationOrigin || TOP;
                var alignAxis = rotationOrigin === TOP || rotationOrigin === BOTTOM ? X : Y;
                var distanceAxis = rotationOrigin === TOP || rotationOrigin === BOTTOM ? Y : X;
                var axisAnchor = rotationOrigin === TOP || rotationOrigin === LEFT ? rect.origin : rect.bottomRight();
                var topLeft = box.topLeft().transformCopy(rotationMatrix);
                var topRight = box.topRight().transformCopy(rotationMatrix);
                var bottomRight = box.bottomRight().transformCopy(rotationMatrix);
                var bottomLeft = box.bottomLeft().transformCopy(rotationMatrix);
                var rotatedBox = Rect.fromPoints(topLeft, topRight, bottomRight, bottomLeft);
                var translate = {};
                translate[distanceAxis] = rect.origin[distanceAxis] - rotatedBox.origin[distanceAxis];
                var distanceLeft = Math.abs(topLeft[distanceAxis] + translate[distanceAxis] - axisAnchor[distanceAxis]);
                var distanceRight = Math.abs(topRight[distanceAxis] + translate[distanceAxis] - axisAnchor[distanceAxis]);
                var alignStart, alignEnd;
                if (round(distanceLeft, DEFAULT_PRECISION) === round(distanceRight, DEFAULT_PRECISION)) {
                    alignStart = topLeft;
                    alignEnd = topRight;
                } else if (distanceRight < distanceLeft) {
                    alignStart = topRight;
                    alignEnd = bottomRight;
                } else {
                    alignStart = topLeft;
                    alignEnd = bottomLeft;
                }
                var alignCenter = alignStart[alignAxis] + (alignEnd[alignAxis] - alignStart[alignAxis]) / 2;
                translate[alignAxis] = rect.center()[alignAxis] - alignCenter;
                return geometryTransform().translate(translate.x, translate.y).rotate(rotation);
            }
        });
        setDefaultOptions(AxisLabel, { _autoReflow: false });
        var defaultImplementation = {
            format: function (format, value) {
                return value;
            },
            toString: function (value) {
                return value;
            },
            parseDate: function (value) {
                return new Date(value);
            }
        };
        var current = defaultImplementation;
        var IntlService = Class.extend({});
        IntlService.register = function (userImplementation) {
            current = userImplementation;
        };
        if (Object.defineProperties) {
            Object.defineProperties(IntlService, {
                implementation: {
                    get: function () {
                        return current;
                    }
                }
            });
        }
        var FORMAT_REPLACE_REGEX = /\{(\d+)(:[^\}]+)?\}/g;
        var FormatService = Class.extend({
            init: function (intlService) {
                this._intlService = intlService;
            },
            auto: function (formatString) {
                var values = [], len = arguments.length - 1;
                while (len-- > 0)
                    values[len] = arguments[len + 1];
                var intl = this.intlService;
                if (formatString.match(FORMAT_REGEX)) {
                    return intl.format.apply(intl, [formatString].concat(values));
                }
                return intl.toString(values[0], formatString);
            },
            localeAuto: function (formatString, values, locale) {
                var intl = this.intlService;
                var result;
                if (formatString.match(FORMAT_REGEX)) {
                    result = formatString.replace(FORMAT_REPLACE_REGEX, function (match, index, placeholderFormat) {
                        var value = values[parseInt(index, 10)];
                        return intl.toString(value, placeholderFormat ? placeholderFormat.substring(1) : '', locale);
                    });
                } else {
                    result = intl.toString(values[0], formatString, locale);
                }
                return result;
            }
        });
        if (Object.defineProperties) {
            Object.defineProperties(FormatService.fn, {
                intlService: {
                    get: function () {
                        return this._intlService || IntlService.implementation;
                    }
                }
            });
        }
        var ChartService = Class.extend({
            init: function (chart, context) {
                if (context === void 0) {
                    context = {};
                }
                this._intlService = context.intlService;
                this.sender = context.sender || chart;
                this.format = new FormatService(context.intlService);
                this.chart = chart;
            },
            notify: function (name, args) {
                this.chart.trigger(name, args);
            }
        });
        if (Object.defineProperties) {
            Object.defineProperties(ChartService.fn, {
                intl: {
                    get: function () {
                        return this._intlService || IntlService.implementation;
                    }
                }
            });
        }
        var current$1;
        var DomEventsBuilder = Class.extend({});
        DomEventsBuilder.register = function (userImplementation) {
            current$1 = userImplementation;
        };
        DomEventsBuilder.create = function (element, events) {
            if (current$1) {
                return current$1.create(element, events);
            }
        };
        var current$2 = {
            compile: function (template) {
                return template;
            }
        };
        var TemplateService = Class.extend({});
        TemplateService.register = function (userImplementation) {
            current$2 = userImplementation;
        };
        TemplateService.compile = function (template) {
            return current$2.compile(template);
        };
        var services = {
            ChartService: ChartService,
            DomEventsBuilder: DomEventsBuilder,
            FormatService: FormatService,
            IntlService: IntlService,
            TemplateService: TemplateService
        };
        var DEFAULT_ICON_SIZE = 7;
        var DEFAULT_LABEL_COLOR = '#fff';
        var Note = BoxElement.extend({
            init: function (fields, options, chartService) {
                BoxElement.fn.init.call(this, options);
                this.fields = fields;
                this.chartService = chartService;
                this.render();
            },
            hide: function () {
                this.options.visible = false;
            },
            show: function () {
                this.options.visible = true;
            },
            render: function () {
                var options = this.options;
                if (options.visible) {
                    var label = options.label;
                    var icon = options.icon;
                    var box = new Box();
                    var size = icon.size;
                    var text = this.fields.text;
                    var width, height;
                    if (defined(label) && label.visible) {
                        if (label.template) {
                            var noteTemplate = TemplateService.compile(label.template);
                            text = noteTemplate(this.fields);
                        } else if (label.format) {
                            text = this.chartService.format.auto(label.format, text);
                        }
                        if (!label.color) {
                            label.color = label.position === INSIDE ? DEFAULT_LABEL_COLOR : icon.background;
                        }
                        this.label = new TextBox(text, deepExtend({}, label));
                        if (label.position === INSIDE && !defined(size)) {
                            if (icon.type === CIRCLE) {
                                size = Math.max(this.label.box.width(), this.label.box.height());
                            } else {
                                width = this.label.box.width();
                                height = this.label.box.height();
                            }
                            box.wrap(this.label.box);
                        }
                    }
                    icon.width = width || size || DEFAULT_ICON_SIZE;
                    icon.height = height || size || DEFAULT_ICON_SIZE;
                    var marker = new ShapeElement(deepExtend({}, icon));
                    this.marker = marker;
                    this.append(marker);
                    if (this.label) {
                        this.append(this.label);
                    }
                    marker.reflow(new Box());
                    this.wrapperBox = box.wrap(marker.box);
                }
            },
            reflow: function (targetBox) {
                var ref = this;
                var options = ref.options;
                var label = ref.label;
                var marker = ref.marker;
                var wrapperBox = ref.wrapperBox;
                var center = targetBox.center();
                var length = options.line.length;
                var position = options.position;
                if (options.visible) {
                    var lineStart, box, contentBox;
                    if (inArray(position, [
                            LEFT,
                            RIGHT
                        ])) {
                        if (position === LEFT) {
                            contentBox = wrapperBox.alignTo(targetBox, position).translate(-length, targetBox.center().y - wrapperBox.center().y);
                            if (options.line.visible) {
                                lineStart = [
                                    targetBox.x1,
                                    center.y
                                ];
                                this.linePoints = [
                                    lineStart,
                                    [
                                        contentBox.x2,
                                        center.y
                                    ]
                                ];
                                box = contentBox.clone().wrapPoint(lineStart);
                            }
                        } else {
                            contentBox = wrapperBox.alignTo(targetBox, position).translate(length, targetBox.center().y - wrapperBox.center().y);
                            if (options.line.visible) {
                                lineStart = [
                                    targetBox.x2,
                                    center.y
                                ];
                                this.linePoints = [
                                    lineStart,
                                    [
                                        contentBox.x1,
                                        center.y
                                    ]
                                ];
                                box = contentBox.clone().wrapPoint(lineStart);
                            }
                        }
                    } else {
                        if (position === BOTTOM) {
                            contentBox = wrapperBox.alignTo(targetBox, position).translate(targetBox.center().x - wrapperBox.center().x, length);
                            if (options.line.visible) {
                                lineStart = [
                                    center.x,
                                    targetBox.y2
                                ];
                                this.linePoints = [
                                    lineStart,
                                    [
                                        center.x,
                                        contentBox.y1
                                    ]
                                ];
                                box = contentBox.clone().wrapPoint(lineStart);
                            }
                        } else {
                            contentBox = wrapperBox.alignTo(targetBox, position).translate(targetBox.center().x - wrapperBox.center().x, -length);
                            if (options.line.visible) {
                                lineStart = [
                                    center.x,
                                    targetBox.y1
                                ];
                                this.linePoints = [
                                    lineStart,
                                    [
                                        center.x,
                                        contentBox.y2
                                    ]
                                ];
                                box = contentBox.clone().wrapPoint(lineStart);
                            }
                        }
                    }
                    if (marker) {
                        marker.reflow(contentBox);
                    }
                    if (label) {
                        label.reflow(contentBox);
                        if (marker) {
                            if (options.label.position === OUTSIDE) {
                                label.box.alignTo(marker.box, position);
                            }
                            label.reflow(label.box);
                        }
                    }
                    this.contentBox = contentBox;
                    this.targetBox = targetBox;
                    this.box = box || contentBox;
                }
            },
            createVisual: function () {
                BoxElement.fn.createVisual.call(this);
                this.visual.options.noclip = this.options.noclip;
                if (this.options.visible) {
                    this.createLine();
                }
            },
            renderVisual: function () {
                var this$1 = this;
                var options = this.options;
                var customVisual = options.visual;
                if (options.visible && customVisual) {
                    this.visual = customVisual($.extend(this.fields, {
                        sender: this.getSender(),
                        rect: this.targetBox.toRect(),
                        options: {
                            background: options.background,
                            border: options.background,
                            icon: options.icon,
                            label: options.label,
                            line: options.line,
                            position: options.position,
                            visible: options.visible
                        },
                        createVisual: function () {
                            this$1.createVisual();
                            this$1.renderChildren();
                            var defaultVisual = this$1.visual;
                            delete this$1.visual;
                            return defaultVisual;
                        }
                    }));
                    this.addVisual();
                } else {
                    BoxElement.fn.renderVisual.call(this);
                }
            },
            createLine: function () {
                var options = this.options.line;
                if (this.linePoints) {
                    var path = Path.fromPoints(this.linePoints, {
                        stroke: {
                            color: options.color,
                            width: options.width,
                            dashType: options.dashType
                        }
                    });
                    alignPathToPixel(path);
                    this.visual.append(path);
                }
            },
            click: function (widget, e) {
                var args = this.eventArgs(e);
                if (!widget.trigger(NOTE_CLICK, args)) {
                    e.preventDefault();
                }
            },
            hover: function (widget, e) {
                var args = this.eventArgs(e);
                if (!widget.trigger(NOTE_HOVER, args)) {
                    e.preventDefault();
                }
            },
            leave: function (widget) {
                widget._unsetActivePoint();
            },
            eventArgs: function (e) {
                var options = this.options;
                return $.extend(this.fields, {
                    element: eventElement(e),
                    text: defined(options.label) ? options.label.text : '',
                    visual: this.visual
                });
            }
        });
        setDefaultOptions(Note, {
            icon: {
                visible: true,
                type: CIRCLE
            },
            label: {
                position: INSIDE,
                visible: true,
                align: CENTER,
                vAlign: CENTER
            },
            line: { visible: true },
            visible: true,
            position: TOP,
            zIndex: 2
        });
        function createAxisTick(options, tickOptions) {
            var tickX = options.tickX;
            var tickY = options.tickY;
            var position = options.position;
            var tick = new Path({
                stroke: {
                    width: tickOptions.width,
                    color: tickOptions.color
                }
            });
            if (options.vertical) {
                tick.moveTo(tickX, position).lineTo(tickX + tickOptions.size, position);
            } else {
                tick.moveTo(position, tickY).lineTo(position, tickY + tickOptions.size);
            }
            alignPathToPixel(tick);
            return tick;
        }
        function createAxisGridLine(options, gridLine) {
            var lineStart = options.lineStart;
            var lineEnd = options.lineEnd;
            var position = options.position;
            var line = new Path({
                stroke: {
                    width: gridLine.width,
                    color: gridLine.color,
                    dashType: gridLine.dashType
                }
            });
            if (options.vertical) {
                line.moveTo(lineStart, position).lineTo(lineEnd, position);
            } else {
                line.moveTo(position, lineStart).lineTo(position, lineEnd);
            }
            alignPathToPixel(line);
            return line;
        }
        var Axis = ChartElement.extend({
            init: function (options, chartService) {
                if (chartService === void 0) {
                    chartService = new ChartService();
                }
                ChartElement.fn.init.call(this, options);
                this.chartService = chartService;
                if (!this.options.visible) {
                    this.options = deepExtend({}, this.options, {
                        labels: { visible: false },
                        line: { visible: false },
                        margin: 0,
                        majorTickSize: 0,
                        minorTickSize: 0
                    });
                }
                this.options.minorTicks = deepExtend({}, {
                    color: this.options.line.color,
                    width: this.options.line.width,
                    visible: this.options.minorTickType !== NONE
                }, this.options.minorTicks, {
                    size: this.options.minorTickSize,
                    align: this.options.minorTickType
                });
                this.options.majorTicks = deepExtend({}, {
                    color: this.options.line.color,
                    width: this.options.line.width,
                    visible: this.options.majorTickType !== NONE
                }, this.options.majorTicks, {
                    size: this.options.majorTickSize,
                    align: this.options.majorTickType
                });
                if (!this.options._deferLabels) {
                    this.createLabels();
                }
                this.createTitle();
                this.createNotes();
            },
            labelsRange: function () {
                return {
                    min: this.options.labels.skip,
                    max: this.labelsCount()
                };
            },
            createLabels: function () {
                var this$1 = this;
                var options = this.options;
                var align = options.vertical ? RIGHT : CENTER;
                var labelOptions = deepExtend({}, options.labels, {
                    align: align,
                    zIndex: options.zIndex
                });
                var step = Math.max(1, labelOptions.step);
                this.children = grep(this.children, function (child) {
                    return !(child instanceof AxisLabel);
                });
                this.labels = [];
                if (labelOptions.visible) {
                    var range = this.labelsRange();
                    var rotation = labelOptions.rotation;
                    if (isObject(rotation)) {
                        labelOptions.alignRotation = rotation.align;
                        labelOptions.rotation = rotation.angle;
                    }
                    if (labelOptions.rotation === 'auto') {
                        labelOptions.rotation = 0;
                        options.autoRotateLabels = true;
                    }
                    for (var idx = range.min; idx < range.max; idx += step) {
                        var label = this$1.createAxisLabel(idx, labelOptions);
                        if (label) {
                            this$1.append(label);
                            this$1.labels.push(label);
                        }
                    }
                }
            },
            lineBox: function () {
                var ref = this;
                var options = ref.options;
                var box = ref.box;
                var vertical = options.vertical;
                var mirror = options.labels.mirror;
                var axisX = mirror ? box.x1 : box.x2;
                var axisY = mirror ? box.y2 : box.y1;
                var lineWidth = options.line.width || 0;
                return vertical ? new Box(axisX, box.y1, axisX, box.y2 - lineWidth) : new Box(box.x1, axisY, box.x2 - lineWidth, axisY);
            },
            createTitle: function () {
                var options = this.options;
                var titleOptions = deepExtend({
                    rotation: options.vertical ? -90 : 0,
                    text: '',
                    zIndex: 1,
                    visualSize: true
                }, options.title);
                if (titleOptions.visible && titleOptions.text) {
                    var title = new TextBox(titleOptions.text, titleOptions);
                    this.append(title);
                    this.title = title;
                }
            },
            createNotes: function () {
                var this$1 = this;
                var options = this.options;
                var notes = options.notes;
                var items = notes.data || [];
                this.notes = [];
                for (var i = 0; i < items.length; i++) {
                    var item = deepExtend({}, notes, items[i]);
                    item.value = this$1.parseNoteValue(item.value);
                    var note = new Note({
                        value: item.value,
                        text: item.label.text,
                        dataItem: item
                    }, item, this$1.chartService);
                    if (note.options.visible) {
                        if (defined(note.options.position)) {
                            if (options.vertical && !inArray(note.options.position, [
                                    LEFT,
                                    RIGHT
                                ])) {
                                note.options.position = options.reverse ? LEFT : RIGHT;
                            } else if (!options.vertical && !inArray(note.options.position, [
                                    TOP,
                                    BOTTOM
                                ])) {
                                note.options.position = options.reverse ? BOTTOM : TOP;
                            }
                        } else {
                            if (options.vertical) {
                                note.options.position = options.reverse ? LEFT : RIGHT;
                            } else {
                                note.options.position = options.reverse ? BOTTOM : TOP;
                            }
                        }
                        this$1.append(note);
                        this$1.notes.push(note);
                    }
                }
            },
            parseNoteValue: function (value) {
                return value;
            },
            renderVisual: function () {
                ChartElement.fn.renderVisual.call(this);
                this.createPlotBands();
            },
            createVisual: function () {
                ChartElement.fn.createVisual.call(this);
                this.createBackground();
                this.createLine();
            },
            gridLinesVisual: function () {
                var gridLines = this._gridLines;
                if (!gridLines) {
                    gridLines = this._gridLines = new Group({ zIndex: -2 });
                    this.appendVisual(this._gridLines);
                }
                return gridLines;
            },
            createTicks: function (lineGroup) {
                var options = this.options;
                var lineBox = this.lineBox();
                var mirror = options.labels.mirror;
                var majorUnit = options.majorTicks.visible ? options.majorUnit : 0;
                var tickLineOptions = { vertical: options.vertical };
                function render(tickPositions, tickOptions, skipUnit) {
                    var count = tickPositions.length;
                    var step = Math.max(1, tickOptions.step);
                    if (tickOptions.visible) {
                        for (var i = tickOptions.skip; i < count; i += step) {
                            if (defined(skipUnit) && i % skipUnit === 0) {
                                continue;
                            }
                            tickLineOptions.tickX = mirror ? lineBox.x2 : lineBox.x2 - tickOptions.size;
                            tickLineOptions.tickY = mirror ? lineBox.y1 - tickOptions.size : lineBox.y1;
                            tickLineOptions.position = tickPositions[i];
                            lineGroup.append(createAxisTick(tickLineOptions, tickOptions));
                        }
                    }
                }
                render(this.getMajorTickPositions(), options.majorTicks);
                render(this.getMinorTickPositions(), options.minorTicks, majorUnit / options.minorUnit);
            },
            createLine: function () {
                var options = this.options;
                var line = options.line;
                var lineBox = this.lineBox();
                if (line.width > 0 && line.visible) {
                    var path = new Path({
                        stroke: {
                            width: line.width,
                            color: line.color,
                            dashType: line.dashType
                        }
                    });
                    path.moveTo(lineBox.x1, lineBox.y1).lineTo(lineBox.x2, lineBox.y2);
                    if (options._alignLines) {
                        alignPathToPixel(path);
                    }
                    var group = this._lineGroup = new Group();
                    group.append(path);
                    this.visual.append(group);
                    this.createTicks(group);
                }
            },
            getActualTickSize: function () {
                var options = this.options;
                var tickSize = 0;
                if (options.majorTicks.visible && options.minorTicks.visible) {
                    tickSize = Math.max(options.majorTicks.size, options.minorTicks.size);
                } else if (options.majorTicks.visible) {
                    tickSize = options.majorTicks.size;
                } else if (options.minorTicks.visible) {
                    tickSize = options.minorTicks.size;
                }
                return tickSize;
            },
            createBackground: function () {
                var ref = this;
                var options = ref.options;
                var box = ref.box;
                var background = options.background;
                if (background) {
                    this._backgroundPath = Path.fromRect(box.toRect(), {
                        fill: { color: background },
                        stroke: null
                    });
                    this.visual.append(this._backgroundPath);
                }
            },
            createPlotBands: function () {
                var this$1 = this;
                var options = this.options;
                var plotBands = options.plotBands || [];
                var vertical = options.vertical;
                var plotArea = this.plotArea;
                if (plotBands.length === 0) {
                    return;
                }
                var group = this._plotbandGroup = new Group({ zIndex: -1 });
                var altAxis = grep(this.pane.axes, function (axis) {
                    return axis.options.vertical !== this$1.options.vertical;
                })[0];
                for (var idx = 0; idx < plotBands.length; idx++) {
                    var item = plotBands[idx];
                    var slotX = void 0, slotY = void 0;
                    if (vertical) {
                        slotX = (altAxis || plotArea.axisX).lineBox();
                        slotY = this$1.getSlot(item.from, item.to, true);
                    } else {
                        slotX = this$1.getSlot(item.from, item.to, true);
                        slotY = (altAxis || plotArea.axisY).lineBox();
                    }
                    if (slotX.width() !== 0 && slotY.height() !== 0) {
                        var bandRect = new Rect([
                            slotX.x1,
                            slotY.y1
                        ], [
                            slotX.width(),
                            slotY.height()
                        ]);
                        var path = Path.fromRect(bandRect, {
                            fill: {
                                color: item.color,
                                opacity: item.opacity
                            },
                            stroke: null
                        });
                        group.append(path);
                    }
                }
                this.appendVisual(group);
            },
            createGridLines: function (altAxis) {
                var options = this.options;
                var minorGridLines = options.minorGridLines;
                var majorGridLines = options.majorGridLines;
                var minorUnit = options.minorUnit;
                var vertical = options.vertical;
                var axisLineVisible = altAxis.options.line.visible;
                var majorUnit = majorGridLines.visible ? options.majorUnit : 0;
                var lineBox = altAxis.lineBox();
                var linePos = lineBox[vertical ? 'y1' : 'x1'];
                var lineOptions = {
                    lineStart: lineBox[vertical ? 'x1' : 'y1'],
                    lineEnd: lineBox[vertical ? 'x2' : 'y2'],
                    vertical: vertical
                };
                var majorTicks = [];
                var container = this.gridLinesVisual();
                function render(tickPositions, gridLine, skipUnit) {
                    var count = tickPositions.length;
                    var step = Math.max(1, gridLine.step);
                    if (gridLine.visible) {
                        for (var i = gridLine.skip; i < count; i += step) {
                            var pos = round(tickPositions[i]);
                            if (!inArray(pos, majorTicks)) {
                                if (i % skipUnit !== 0 && (!axisLineVisible || linePos !== pos)) {
                                    lineOptions.position = pos;
                                    container.append(createAxisGridLine(lineOptions, gridLine));
                                    majorTicks.push(pos);
                                }
                            }
                        }
                    }
                }
                render(this.getMajorTickPositions(), majorGridLines);
                render(this.getMinorTickPositions(), minorGridLines, majorUnit / minorUnit);
                return container.children;
            },
            reflow: function (box) {
                var ref = this;
                var options = ref.options;
                var labels = ref.labels;
                var title = ref.title;
                var vertical = options.vertical;
                var count = labels.length;
                var sizeFn = vertical ? WIDTH : HEIGHT;
                var titleSize = title ? title.box[sizeFn]() : 0;
                var space = this.getActualTickSize() + options.margin + titleSize;
                var rootBox = (this.getRoot() || {}).box || box;
                var boxSize = rootBox[sizeFn]();
                var maxLabelSize = 0;
                for (var i = 0; i < count; i++) {
                    var labelSize = labels[i].box[sizeFn]();
                    if (labelSize + space <= boxSize) {
                        maxLabelSize = Math.max(maxLabelSize, labelSize);
                    }
                }
                if (vertical) {
                    this.box = new Box(box.x1, box.y1, box.x1 + maxLabelSize + space, box.y2);
                } else {
                    this.box = new Box(box.x1, box.y1, box.x2, box.y1 + maxLabelSize + space);
                }
                this.arrangeTitle();
                this.arrangeLabels();
                this.arrangeNotes();
            },
            getLabelsTickPositions: function () {
                return this.getMajorTickPositions();
            },
            labelTickIndex: function (label) {
                return label.index;
            },
            arrangeLabels: function () {
                var this$1 = this;
                var ref = this;
                var options = ref.options;
                var labels = ref.labels;
                var labelsBetweenTicks = !options.justified;
                var vertical = options.vertical;
                var lineBox = this.lineBox();
                var mirror = options.labels.mirror;
                var tickPositions = this.getLabelsTickPositions();
                var labelOffset = this.getActualTickSize() + options.margin;
                for (var idx = 0; idx < labels.length; idx++) {
                    var label = labels[idx];
                    var tickIx = this$1.labelTickIndex(label);
                    var labelSize = vertical ? label.box.height() : label.box.width();
                    var labelPos = tickPositions[tickIx] - labelSize / 2;
                    var labelBox = void 0, firstTickPosition = void 0, nextTickPosition = void 0;
                    if (vertical) {
                        if (labelsBetweenTicks) {
                            firstTickPosition = tickPositions[tickIx];
                            nextTickPosition = tickPositions[tickIx + 1];
                            var middle = firstTickPosition + (nextTickPosition - firstTickPosition) / 2;
                            labelPos = middle - labelSize / 2;
                        }
                        var labelX = lineBox.x2;
                        if (mirror) {
                            labelX += labelOffset;
                            label.options.rotationOrigin = LEFT;
                        } else {
                            labelX -= labelOffset + label.box.width();
                            label.options.rotationOrigin = RIGHT;
                        }
                        labelBox = label.box.move(labelX, labelPos);
                    } else {
                        if (labelsBetweenTicks) {
                            firstTickPosition = tickPositions[tickIx];
                            nextTickPosition = tickPositions[tickIx + 1];
                        } else {
                            firstTickPosition = labelPos;
                            nextTickPosition = labelPos + labelSize;
                        }
                        var labelY = lineBox.y1;
                        if (mirror) {
                            labelY -= labelOffset + label.box.height();
                            label.options.rotationOrigin = BOTTOM;
                        } else {
                            labelY += labelOffset;
                            label.options.rotationOrigin = TOP;
                        }
                        labelBox = new Box(firstTickPosition, labelY, nextTickPosition, labelY + label.box.height());
                    }
                    label.reflow(labelBox);
                }
            },
            autoRotateLabels: function () {
                if (this.options.autoRotateLabels && !this.options.vertical) {
                    var tickPositions = this.getMajorTickPositions();
                    var labels = this.labels;
                    var angle;
                    for (var idx = 0; idx < labels.length; idx++) {
                        var width = tickPositions[idx + 1] - tickPositions[idx];
                        var labelBox = labels[idx].box;
                        if (labelBox.width() > width) {
                            if (labelBox.height() > width) {
                                angle = -90;
                                break;
                            }
                            angle = -45;
                        }
                    }
                    if (angle) {
                        for (var idx$1 = 0; idx$1 < labels.length; idx$1++) {
                            labels[idx$1].options.rotation = angle;
                            labels[idx$1].reflow(new Box());
                        }
                        return true;
                    }
                }
            },
            arrangeTitle: function () {
                var ref = this;
                var options = ref.options;
                var title = ref.title;
                var mirror = options.labels.mirror;
                var vertical = options.vertical;
                if (title) {
                    if (vertical) {
                        title.options.align = mirror ? RIGHT : LEFT;
                        title.options.vAlign = title.options.position;
                    } else {
                        title.options.align = title.options.position;
                        title.options.vAlign = mirror ? TOP : BOTTOM;
                    }
                    title.reflow(this.box);
                }
            },
            arrangeNotes: function () {
                var this$1 = this;
                for (var idx = 0; idx < this.notes.length; idx++) {
                    var item = this$1.notes[idx];
                    var value = item.options.value;
                    var slot = void 0;
                    if (defined(value)) {
                        if (this$1.shouldRenderNote(value)) {
                            item.show();
                        } else {
                            item.hide();
                        }
                        slot = this$1.noteSlot(value);
                    } else {
                        item.hide();
                    }
                    item.reflow(slot || this$1.lineBox());
                }
            },
            noteSlot: function (value) {
                return this.getSlot(value);
            },
            alignTo: function (secondAxis) {
                var lineBox = secondAxis.lineBox();
                var vertical = this.options.vertical;
                var pos = vertical ? Y : X;
                this.box.snapTo(lineBox, pos);
                if (vertical) {
                    this.box.shrink(0, this.lineBox().height() - lineBox.height());
                } else {
                    this.box.shrink(this.lineBox().width() - lineBox.width(), 0);
                }
                this.box[pos + 1] -= this.lineBox()[pos + 1] - lineBox[pos + 1];
                this.box[pos + 2] -= this.lineBox()[pos + 2] - lineBox[pos + 2];
            },
            axisLabelText: function (value, dataItem, options) {
                var text = value;
                if (options.template) {
                    var tmpl = TemplateService.compile(options.template);
                    text = tmpl({
                        value: value,
                        dataItem: dataItem,
                        format: options.format,
                        culture: options.culture
                    });
                } else if (options.format) {
                    text = this.chartService.format.localeAuto(options.format, [value], options.culture);
                }
                return text;
            },
            slot: function (from, to, limit) {
                var slot = this.getSlot(from, to, limit);
                if (slot) {
                    return slot.toRect();
                }
            },
            contentBox: function () {
                var box = this.box.clone();
                var labels = this.labels;
                if (labels.length) {
                    if (labels[0].options.visible) {
                        box.wrap(labels[0].box);
                    }
                    var lastLabel = labels[labels.length - 1];
                    if (lastLabel.options.visible) {
                        box.wrap(lastLabel.box);
                    }
                }
                return box;
            },
            limitRange: function (from, to, min, max, offset) {
                var options = this.options;
                if (from < min && offset < 0 && (!defined(options.min) || options.min <= min) || max < to && offset > 0 && (!defined(options.max) || max <= options.max)) {
                    return null;
                }
                if (to < min && offset > 0 || max < from && offset < 0) {
                    return {
                        min: from,
                        max: to
                    };
                }
                var rangeSize = to - from;
                var minValue = from;
                var maxValue = to;
                if (from < min) {
                    minValue = limitValue(from, min, max);
                    maxValue = limitValue(from + rangeSize, min + rangeSize, max);
                } else if (to > max) {
                    maxValue = limitValue(to, min, max);
                    minValue = limitValue(to - rangeSize, min, max - rangeSize);
                }
                return {
                    min: minValue,
                    max: maxValue
                };
            },
            valueRange: function () {
                return {
                    min: this.seriesMin,
                    max: this.seriesMax
                };
            }
        });
        setDefaultOptions(Axis, {
            labels: {
                visible: true,
                rotation: 0,
                mirror: false,
                step: 1,
                skip: 0
            },
            line: {
                width: 1,
                color: BLACK,
                visible: true
            },
            title: {
                visible: true,
                position: CENTER
            },
            majorTicks: {
                align: OUTSIDE,
                size: 4,
                skip: 0,
                step: 1
            },
            minorTicks: {
                align: OUTSIDE,
                size: 3,
                skip: 0,
                step: 1
            },
            axisCrossingValue: 0,
            majorTickType: OUTSIDE,
            minorTickType: NONE,
            majorGridLines: {
                skip: 0,
                step: 1
            },
            minorGridLines: {
                visible: false,
                width: 1,
                color: BLACK,
                skip: 0,
                step: 1
            },
            margin: 5,
            visible: true,
            reverse: false,
            justified: true,
            notes: { label: { text: '' } },
            _alignLines: true,
            _deferLabels: false
        });
        var MIN_CATEGORY_POINTS_RANGE = 0.01;
        var CategoryAxis = Axis.extend({
            init: function (options, chartService) {
                Axis.fn.init.call(this, options, chartService);
                this._ticks = {};
                this._initCategories(this.options);
            },
            _initCategories: function (options) {
                var categories = (options.categories || []).slice(0);
                var definedMin = defined(options.min);
                var definedMax = defined(options.max);
                options.categories = categories;
                if ((definedMin || definedMax) && categories.length) {
                    options.srcCategories = options.categories;
                    var min = definedMin ? Math.floor(options.min) : 0;
                    var max;
                    if (definedMax) {
                        max = options.justified ? Math.floor(options.max) + 1 : Math.ceil(options.max);
                    } else {
                        max = categories.length;
                    }
                    options.categories = options.categories.slice(min, max);
                }
            },
            rangeIndices: function () {
                var options = this.options;
                var length = options.categories.length || 1;
                var min = isNumber(options.min) ? options.min % 1 : 0;
                var max;
                if (isNumber(options.max) && options.max % 1 !== 0 && options.max < this.totalRange().max) {
                    max = length - (1 - options.max % 1);
                } else {
                    max = length - (options.justified ? 1 : 0);
                }
                return {
                    min: min,
                    max: max
                };
            },
            totalRangeIndices: function (limit) {
                var options = this.options;
                var min = isNumber(options.min) ? options.min : 0;
                var max;
                if (isNumber(options.max)) {
                    max = options.max;
                } else if (isNumber(options.min)) {
                    max = min + options.categories.length;
                } else {
                    max = (options.srcCategories || options.categories).length - (options.justified ? 1 : 0) || 1;
                }
                if (limit) {
                    var totalRange = this.totalRange();
                    min = limitValue(min, 0, totalRange.max);
                    max = limitValue(max, 0, totalRange.max);
                }
                return {
                    min: min,
                    max: max
                };
            },
            range: function () {
                var options = this.options;
                return {
                    min: isNumber(options.min) ? options.min : 0,
                    max: isNumber(options.max) ? options.max : options.categories.length
                };
            },
            totalRange: function () {
                var options = this.options;
                return {
                    min: 0,
                    max: Math.max(this._seriesMax || 0, (options.srcCategories || options.categories).length) - (options.justified ? 1 : 0)
                };
            },
            getScale: function () {
                var ref = this.rangeIndices();
                var min = ref.min;
                var max = ref.max;
                var lineBox = this.lineBox();
                var size = this.options.vertical ? lineBox.height() : lineBox.width();
                var scale = size / (max - min || 1);
                return scale * (this.options.reverse ? -1 : 1);
            },
            getTickPositions: function (stepSize) {
                var ref = this.options;
                var vertical = ref.vertical;
                var reverse = ref.reverse;
                var ref$1 = this.rangeIndices();
                var min = ref$1.min;
                var max = ref$1.max;
                var lineBox = this.lineBox();
                var scale = this.getScale();
                var pos = lineBox[(vertical ? Y : X) + (reverse ? 2 : 1)];
                var positions = [];
                var current = min % 1 !== 0 ? Math.floor(min / 1) + stepSize : min;
                while (current <= max) {
                    positions.push(pos + round(scale * (current - min), COORD_PRECISION));
                    current += stepSize;
                }
                return positions;
            },
            getLabelsTickPositions: function () {
                var tickPositions = this.getMajorTickPositions().slice(0);
                var range = this.rangeIndices();
                var scale = this.getScale();
                var box = this.lineBox();
                var options = this.options;
                var axis = options.vertical ? Y : X;
                var start = options.reverse ? 2 : 1;
                var end = options.reverse ? 1 : 2;
                if (range.min % 1 !== 0) {
                    tickPositions.unshift(box[axis + start] - scale * (range.min % 1));
                }
                if (range.max % 1 !== 0) {
                    tickPositions.push(box[axis + end] + scale * (1 - range.max % 1));
                }
                return tickPositions;
            },
            labelTickIndex: function (label) {
                var range = this.rangeIndices();
                var index = label.index;
                if (range.min > 0) {
                    index = index - Math.floor(range.min);
                }
                return index;
            },
            arrangeLabels: function () {
                Axis.fn.arrangeLabels.call(this);
                this.hideOutOfRangeLabels();
            },
            hideOutOfRangeLabels: function () {
                var ref = this;
                var box = ref.box;
                var labels = ref.labels;
                if (labels.length) {
                    var valueAxis = this.options.vertical ? Y : X;
                    var start = box[valueAxis + 1];
                    var end = box[valueAxis + 2];
                    var firstLabel = labels[0];
                    var lastLabel = last(labels);
                    if (firstLabel.box[valueAxis + 1] > end || firstLabel.box[valueAxis + 2] < start) {
                        firstLabel.options.visible = false;
                    }
                    if (lastLabel.box[valueAxis + 1] > end || lastLabel.box[valueAxis + 2] < start) {
                        lastLabel.options.visible = false;
                    }
                }
            },
            getMajorTickPositions: function () {
                return this.getTicks().majorTicks;
            },
            getMinorTickPositions: function () {
                return this.getTicks().minorTicks;
            },
            getTicks: function () {
                var ref = this.options;
                var reverse = ref.reverse;
                var justified = ref.justified;
                var cache = this._ticks;
                var range = this.rangeIndices();
                var lineBox = this.lineBox();
                var hash = lineBox.getHash() + range.min + ',' + range.max + reverse + justified;
                if (cache._hash !== hash) {
                    cache._hash = hash;
                    cache.majorTicks = this.getTickPositions(1);
                    cache.minorTicks = this.getTickPositions(0.5);
                }
                return cache;
            },
            getSlot: function (from, to, limit) {
                var ref = this;
                var options = ref.options;
                var reverse = options.reverse;
                var justified = options.justified;
                var vertical = options.vertical;
                var ref$1 = this.rangeIndices();
                var min = ref$1.min;
                var valueAxis = vertical ? Y : X;
                var lineBox = this.lineBox();
                var scale = this.getScale();
                var lineStart = lineBox[valueAxis + (reverse ? 2 : 1)];
                var slotBox = lineBox.clone();
                var singleSlot = !defined(to);
                var start = valueOrDefault(from, 0);
                var end = valueOrDefault(to, start);
                end = Math.max(end - 1, start);
                end = Math.max(start, end);
                var p1 = lineStart + (start - min) * scale;
                var p2 = lineStart + (end + 1 - min) * scale;
                if (singleSlot && justified) {
                    p2 = p1;
                }
                if (limit) {
                    p1 = limitValue(p1, lineBox[valueAxis + 1], lineBox[valueAxis + 2]);
                    p2 = limitValue(p2, lineBox[valueAxis + 1], lineBox[valueAxis + 2]);
                }
                slotBox[valueAxis + 1] = reverse ? p2 : p1;
                slotBox[valueAxis + 2] = reverse ? p1 : p2;
                return slotBox;
            },
            slot: function (from, to, limit) {
                var start = from;
                var end = to;
                if (typeof start === 'string') {
                    start = this.categoryIndex(start);
                }
                if (typeof end === 'string') {
                    end = this.categoryIndex(end);
                }
                return Axis.fn.slot.call(this, start, end, limit);
            },
            pointCategoryIndex: function (point) {
                var ref = this.options;
                var reverse = ref.reverse;
                var justified = ref.justified;
                var vertical = ref.vertical;
                var valueAxis = vertical ? Y : X;
                var lineBox = this.lineBox();
                var range = this.rangeIndices();
                var startValue = reverse ? range.max : range.min;
                var scale = this.getScale();
                var lineStart = lineBox[valueAxis + 1];
                var lineEnd = lineBox[valueAxis + 2];
                var pos = point[valueAxis];
                if (pos < lineStart || pos > lineEnd) {
                    return null;
                }
                var value = startValue + (pos - lineStart) / scale;
                var diff = value % 1;
                if (justified) {
                    value = Math.round(value);
                } else if (diff === 0 && value > 0) {
                    value--;
                }
                return Math.floor(value);
            },
            getCategory: function (point) {
                var index = this.pointCategoryIndex(point);
                if (index === null) {
                    return null;
                }
                return this.options.categories[index];
            },
            categoryIndex: function (value) {
                var options = this.options;
                var index = (options.srcCategories || options.categories).indexOf(value);
                return index - Math.floor(options.min || 0);
            },
            translateRange: function (delta) {
                var options = this.options;
                var lineBox = this.lineBox();
                var size = options.vertical ? lineBox.height() : lineBox.width();
                var range = options.categories.length;
                var scale = size / range;
                var offset = round(delta / scale, DEFAULT_PRECISION);
                return {
                    min: offset,
                    max: range + offset
                };
            },
            zoomRange: function (rate) {
                var rangeIndices = this.totalRangeIndices();
                var ref = this.totalRange();
                var totalMin = ref.min;
                var totalMax = ref.max;
                var min = limitValue(rangeIndices.min + rate, totalMin, totalMax);
                var max = limitValue(rangeIndices.max - rate, totalMin, totalMax);
                if (max - min > 0) {
                    return {
                        min: min,
                        max: max
                    };
                }
            },
            scaleRange: function (scale) {
                var range = this.options.categories.length;
                var delta = scale * range;
                return {
                    min: -delta,
                    max: range + delta
                };
            },
            labelsCount: function () {
                var labelsRange = this.labelsRange();
                return labelsRange.max - labelsRange.min;
            },
            labelsRange: function () {
                var options = this.options;
                var justified = options.justified;
                var labelOptions = options.labels;
                var ref = this.totalRangeIndices(true);
                var min = ref.min;
                var max = ref.max;
                var start = Math.floor(min);
                if (!justified) {
                    min = Math.floor(min);
                    max = Math.ceil(max);
                } else {
                    min = Math.ceil(min);
                    max = Math.floor(max);
                }
                var skip;
                if (min > labelOptions.skip) {
                    skip = labelOptions.skip + labelOptions.step * Math.ceil((min - labelOptions.skip) / labelOptions.step);
                } else {
                    skip = labelOptions.skip;
                }
                return {
                    min: skip - start,
                    max: (options.categories.length ? max + (justified ? 1 : 0) : 0) - start
                };
            },
            createAxisLabel: function (index, labelOptions) {
                var options = this.options;
                var dataItem = options.dataItems ? options.dataItems[index] : null;
                var category = valueOrDefault(options.categories[index], '');
                var text = this.axisLabelText(category, dataItem, labelOptions);
                return new AxisLabel(category, text, index, dataItem, labelOptions);
            },
            shouldRenderNote: function (value) {
                var range = this.totalRangeIndices();
                return Math.floor(range.min) <= value && value <= Math.ceil(range.max);
            },
            noteSlot: function (value) {
                var options = this.options;
                var index = value - Math.floor(options.min || 0);
                return this.getSlot(index);
            },
            arrangeNotes: function () {
                Axis.fn.arrangeNotes.call(this);
                this.hideOutOfRangeNotes();
            },
            hideOutOfRangeNotes: function () {
                var ref = this;
                var notes = ref.notes;
                var box = ref.box;
                if (notes && notes.length) {
                    var valueAxis = this.options.vertical ? Y : X;
                    var start = box[valueAxis + 1];
                    var end = box[valueAxis + 2];
                    for (var idx = 0; idx < notes.length; idx++) {
                        var note = notes[idx];
                        if (note.box && (end < note.box[valueAxis + 1] || note.box[valueAxis + 2] < start)) {
                            note.hide();
                        }
                    }
                }
            },
            pan: function (delta) {
                var range = this.totalRangeIndices(true);
                var scale = this.getScale();
                var offset = round(delta / scale, DEFAULT_PRECISION);
                var totalRange = this.totalRange();
                var min = range.min + offset;
                var max = range.max + offset;
                return this.limitRange(min, max, 0, totalRange.max, offset);
            },
            pointsRange: function (start, end) {
                var ref = this.options;
                var reverse = ref.reverse;
                var vertical = ref.vertical;
                var valueAxis = vertical ? Y : X;
                var lineBox = this.lineBox();
                var range = this.totalRangeIndices(true);
                var scale = this.getScale();
                var lineStart = lineBox[valueAxis + (reverse ? 2 : 1)];
                var diffStart = start[valueAxis] - lineStart;
                var diffEnd = end[valueAxis] - lineStart;
                var min = range.min + diffStart / scale;
                var max = range.min + diffEnd / scale;
                var rangeMin = Math.min(min, max);
                var rangeMax = Math.max(min, max);
                if (rangeMax - rangeMin >= MIN_CATEGORY_POINTS_RANGE) {
                    return {
                        min: rangeMin,
                        max: rangeMax
                    };
                }
            },
            valueRange: function () {
                return this.range();
            }
        });
        setDefaultOptions(CategoryAxis, {
            type: 'category',
            categories: [],
            vertical: false,
            majorGridLines: {
                visible: false,
                width: 1,
                color: BLACK
            },
            labels: { zIndex: 1 },
            justified: false,
            _deferLabels: true
        });
        var MILLISECONDS = 'milliseconds';
        var SECONDS = 'seconds';
        var MINUTES = 'minutes';
        var HOURS = 'hours';
        var DAYS = 'days';
        var WEEKS = 'weeks';
        var MONTHS = 'months';
        var YEARS = 'years';
        var TIME_PER_MILLISECOND = 1;
        var TIME_PER_SECOND = 1000;
        var TIME_PER_MINUTE = 60 * TIME_PER_SECOND;
        var TIME_PER_HOUR = 60 * TIME_PER_MINUTE;
        var TIME_PER_DAY = 24 * TIME_PER_HOUR;
        var TIME_PER_WEEK = 7 * TIME_PER_DAY;
        var TIME_PER_MONTH = 31 * TIME_PER_DAY;
        var TIME_PER_YEAR = 365 * TIME_PER_DAY;
        var TIME_PER_UNIT = {
            'years': TIME_PER_YEAR,
            'months': TIME_PER_MONTH,
            'weeks': TIME_PER_WEEK,
            'days': TIME_PER_DAY,
            'hours': TIME_PER_HOUR,
            'minutes': TIME_PER_MINUTE,
            'seconds': TIME_PER_SECOND,
            'milliseconds': TIME_PER_MILLISECOND
        };
        function absoluteDateDiff(a, b) {
            var diff = a.getTime() - b;
            var offsetDiff = a.getTimezoneOffset() - b.getTimezoneOffset();
            return diff - offsetDiff * TIME_PER_MINUTE;
        }
        function addTicks(date, ticks) {
            return new Date(date.getTime() + ticks);
        }
        function toDate(value) {
            var result;
            if (value instanceof Date) {
                result = value;
            } else if (value) {
                result = new Date(value);
            }
            return result;
        }
        function startOfWeek(date, weekStartDay) {
            if (weekStartDay === void 0) {
                weekStartDay = 0;
            }
            var daysToSubtract = 0;
            var day = date.getDay();
            if (!isNaN(day)) {
                while (day !== weekStartDay) {
                    if (day === 0) {
                        day = 6;
                    } else {
                        day--;
                    }
                    daysToSubtract++;
                }
            }
            return addTicks(date, -daysToSubtract * TIME_PER_DAY);
        }
        function adjustDST(date, hours) {
            if (hours === 0 && date.getHours() === 23) {
                date.setHours(date.getHours() + 2);
                return true;
            }
            return false;
        }
        function addHours(date, hours) {
            var roundedDate = new Date(date);
            roundedDate.setMinutes(0, 0, 0);
            var tzDiff = (date.getTimezoneOffset() - roundedDate.getTimezoneOffset()) * TIME_PER_MINUTE;
            return addTicks(roundedDate, tzDiff + hours * TIME_PER_HOUR);
        }
        function addDuration(dateValue, value, unit, weekStartDay) {
            var result = dateValue;
            if (dateValue) {
                var date = toDate(dateValue);
                var hours = date.getHours();
                if (unit === YEARS) {
                    result = new Date(date.getFullYear() + value, 0, 1);
                    adjustDST(result, 0);
                } else if (unit === MONTHS) {
                    result = new Date(date.getFullYear(), date.getMonth() + value, 1);
                    adjustDST(result, hours);
                } else if (unit === WEEKS) {
                    result = addDuration(startOfWeek(date, weekStartDay), value * 7, DAYS);
                    adjustDST(result, hours);
                } else if (unit === DAYS) {
                    result = new Date(date.getFullYear(), date.getMonth(), date.getDate() + value);
                    adjustDST(result, hours);
                } else if (unit === HOURS) {
                    result = addHours(date, value);
                } else if (unit === MINUTES) {
                    result = addTicks(date, value * TIME_PER_MINUTE);
                    if (result.getSeconds() > 0) {
                        result.setSeconds(0);
                    }
                } else if (unit === SECONDS) {
                    result = addTicks(date, value * TIME_PER_SECOND);
                } else if (unit === MILLISECONDS) {
                    result = addTicks(date, value);
                }
                if (unit !== MILLISECONDS && result.getMilliseconds() > 0) {
                    result.setMilliseconds(0);
                }
            }
            return result;
        }
        function floorDate(date, unit, weekStartDay) {
            return addDuration(toDate(date), 0, unit, weekStartDay);
        }
        function ceilDate(dateValue, unit, weekStartDay) {
            var date = toDate(dateValue);
            if (date && floorDate(date, unit, weekStartDay).getTime() === date.getTime()) {
                return date;
            }
            return addDuration(date, 1, unit, weekStartDay);
        }
        function dateComparer(a, b) {
            if (a && b) {
                return a.getTime() - b.getTime();
            }
            return -1;
        }
        function dateDiff(a, b) {
            return a.getTime() - b;
        }
        function toTime(value) {
            if (isArray(value)) {
                var result = [];
                for (var idx = 0; idx < value.length; idx++) {
                    result.push(toTime(value[idx]));
                }
                return result;
            } else if (value) {
                return toDate(value).getTime();
            }
        }
        function dateEquals(a, b) {
            if (a && b) {
                return toTime(a) === toTime(b);
            }
            return a === b;
        }
        function timeIndex(date, start, baseUnit) {
            return absoluteDateDiff(date, start) / TIME_PER_UNIT[baseUnit];
        }
        function dateIndex(value, start, baseUnit, baseUnitStep) {
            var date = toDate(value);
            var startDate = toDate(start);
            var index;
            if (baseUnit === MONTHS) {
                index = date.getMonth() - startDate.getMonth() + (date.getFullYear() - startDate.getFullYear()) * 12 + timeIndex(date, new Date(date.getFullYear(), date.getMonth()), DAYS) / new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
            } else if (baseUnit === YEARS) {
                index = date.getFullYear() - startDate.getFullYear() + dateIndex(date, new Date(date.getFullYear(), 0), MONTHS, 1) / 12;
            } else if (baseUnit === DAYS || baseUnit === WEEKS) {
                index = timeIndex(date, startDate, baseUnit);
            } else {
                index = dateDiff(date, start) / TIME_PER_UNIT[baseUnit];
            }
            return index / baseUnitStep;
        }
        function duration(a, b, unit) {
            var diff;
            if (unit === YEARS) {
                diff = b.getFullYear() - a.getFullYear();
            } else if (unit === MONTHS) {
                diff = duration(a, b, YEARS) * 12 + b.getMonth() - a.getMonth();
            } else if (unit === DAYS) {
                diff = Math.floor(dateDiff(b, a) / TIME_PER_DAY);
            } else {
                diff = Math.floor(dateDiff(b, a) / TIME_PER_UNIT[unit]);
            }
            return diff;
        }
        function lteDateIndex(date, sortedDates) {
            var low = 0;
            var high = sortedDates.length - 1;
            var index;
            while (low <= high) {
                index = Math.floor((low + high) / 2);
                var currentDate = sortedDates[index];
                if (currentDate < date) {
                    low = index + 1;
                    continue;
                }
                if (currentDate > date) {
                    high = index - 1;
                    continue;
                }
                while (dateEquals(sortedDates[index - 1], date)) {
                    index--;
                }
                return index;
            }
            if (sortedDates[index] <= date) {
                return index;
            }
            return index - 1;
        }
        function parseDate(intlService, date) {
            var result;
            if (isString(date)) {
                result = intlService.parseDate(date) || toDate(date);
            } else {
                result = toDate(date);
            }
            return result;
        }
        function parseDates(intlService, dates) {
            if (isArray(dates)) {
                var result = [];
                for (var idx = 0; idx < dates.length; idx++) {
                    result.push(parseDate(intlService, dates[idx]));
                }
                return result;
            }
            return parseDate(intlService, dates);
        }
        var COORDINATE_LIMIT = 300000;
        var DateLabelFormats = {
            seconds: 'HH:mm:ss',
            minutes: 'HH:mm',
            hours: 'HH:mm',
            days: 'M/d',
            weeks: 'M/d',
            months: 'MMM \'yy',
            years: 'yyyy'
        };
        var ZERO_THRESHOLD = 0.2;
        var AUTO = 'auto';
        var BASE_UNITS = [
            MILLISECONDS,
            SECONDS,
            MINUTES,
            HOURS,
            DAYS,
            WEEKS,
            MONTHS,
            YEARS
        ];
        var FIT = 'fit';
        var DateCategoryAxis = CategoryAxis.extend({
            init: function (axisOptions, chartService) {
                CategoryAxis.fn.init.call(this, axisOptions, chartService);
                var intlService = chartService.intl;
                var options = this.options;
                options = deepExtend({ roundToBaseUnit: true }, options, {
                    categories: parseDates(intlService, options.categories),
                    min: parseDate(intlService, options.min),
                    max: parseDate(intlService, options.max)
                });
                options.userSetBaseUnit = options.userSetBaseUnit || options.baseUnit;
                options.userSetBaseUnitStep = options.userSetBaseUnitStep || options.baseUnitStep;
                if (options.categories && options.categories.length > 0) {
                    var baseUnit = (options.baseUnit || '').toLowerCase();
                    var useDefault = baseUnit !== FIT && !inArray(baseUnit, BASE_UNITS);
                    if (useDefault) {
                        options.baseUnit = this.defaultBaseUnit(options);
                    }
                    if (baseUnit === FIT || options.baseUnitStep === AUTO) {
                        this.autoBaseUnit(options);
                    }
                    this._groupsStart = addDuration(options.categories[0], 0, options.baseUnit, options.weekStartDay);
                    this.groupCategories(options);
                } else {
                    options.baseUnit = options.baseUnit || DAYS;
                }
                this.options = options;
            },
            _initCategories: function () {
            },
            shouldRenderNote: function (value) {
                var range = this.range();
                var categories = this.options.categories || [];
                return dateComparer(value, range.min) >= 0 && dateComparer(value, range.max) <= 0 && categories.length;
            },
            parseNoteValue: function (value) {
                return parseDate(this.chartService.intl, value);
            },
            noteSlot: function (value) {
                return this.getSlot(value);
            },
            translateRange: function (delta) {
                var options = this.options;
                var baseUnit = options.baseUnit;
                var weekStartDay = options.weekStartDay;
                var vertical = options.vertical;
                var lineBox = this.lineBox();
                var size = vertical ? lineBox.height() : lineBox.width();
                var range = this.range();
                var scale = size / (range.max - range.min);
                var offset = round(delta / scale, DEFAULT_PRECISION);
                if (range.min && range.max) {
                    var from = addTicks(options.min || range.min, offset);
                    var to = addTicks(options.max || range.max, offset);
                    range = {
                        min: addDuration(from, 0, baseUnit, weekStartDay),
                        max: addDuration(to, 0, baseUnit, weekStartDay)
                    };
                }
                return range;
            },
            scaleRange: function (delta) {
                var rounds = Math.abs(delta);
                var result = this.range();
                var from = result.min;
                var to = result.max;
                if (from && to) {
                    while (rounds--) {
                        var range = dateDiff(from, to);
                        var step = Math.round(range * 0.1);
                        if (delta < 0) {
                            from = addTicks(from, step);
                            to = addTicks(to, -step);
                        } else {
                            from = addTicks(from, -step);
                            to = addTicks(to, step);
                        }
                    }
                    result = {
                        min: from,
                        max: to
                    };
                }
                return result;
            },
            defaultBaseUnit: function (options) {
                var categories = options.categories;
                var count = defined(categories) ? categories.length : 0;
                var minDiff = MAX_VALUE;
                var lastCategory, unit;
                for (var categoryIx = 0; categoryIx < count; categoryIx++) {
                    var category = categories[categoryIx];
                    if (category && lastCategory) {
                        var diff = absoluteDateDiff(category, lastCategory);
                        if (diff > 0) {
                            minDiff = Math.min(minDiff, diff);
                            if (minDiff >= TIME_PER_YEAR) {
                                unit = YEARS;
                            } else if (minDiff >= TIME_PER_MONTH - TIME_PER_DAY * 3) {
                                unit = MONTHS;
                            } else if (minDiff >= TIME_PER_WEEK) {
                                unit = WEEKS;
                            } else if (minDiff >= TIME_PER_DAY) {
                                unit = DAYS;
                            } else if (minDiff >= TIME_PER_HOUR) {
                                unit = HOURS;
                            } else if (minDiff >= TIME_PER_MINUTE) {
                                unit = MINUTES;
                            } else {
                                unit = SECONDS;
                            }
                        }
                    }
                    lastCategory = category;
                }
                return unit || DAYS;
            },
            _categoryRange: function (categories) {
                var range = categories._range;
                if (!range) {
                    range = categories._range = sparseArrayLimits(categories);
                }
                return range;
            },
            totalRange: function () {
                return {
                    min: 0,
                    max: this.options.categories.length
                };
            },
            rangeIndices: function () {
                var options = this.options;
                var categories = options.categories;
                var baseUnit = options.baseUnit;
                var baseUnitStep = options.baseUnitStep || 1;
                var categoryLimits = this.categoriesRange();
                var min = toDate(options.min || categoryLimits.min);
                var max = toDate(options.max || categoryLimits.max);
                var minIdx = 0, maxIdx = 0;
                if (categories.length) {
                    minIdx = dateIndex(min, categories[0], baseUnit, baseUnitStep);
                    maxIdx = dateIndex(max, categories[0], baseUnit, baseUnitStep);
                    if (options.roundToBaseUnit) {
                        minIdx = Math.floor(minIdx);
                        maxIdx = options.justified ? Math.floor(maxIdx) : Math.ceil(maxIdx);
                    }
                }
                return {
                    min: minIdx,
                    max: maxIdx
                };
            },
            labelsRange: function () {
                var options = this.options;
                var labelOptions = options.labels;
                var range = this.rangeIndices();
                var min = Math.floor(range.min);
                var max = Math.ceil(range.max);
                return {
                    min: min + labelOptions.skip,
                    max: options.categories.length ? max + (options.justified ? 1 : 0) : 0
                };
            },
            categoriesRange: function () {
                var options = this.options;
                var range = this._categoryRange(options.srcCategories || options.categories);
                var max = toDate(range.max);
                if (!options.justified && dateEquals(max, this._roundToTotalStep(max, options, false))) {
                    max = this._roundToTotalStep(max, options, true, true);
                }
                return {
                    min: toDate(range.min),
                    max: max
                };
            },
            currentRange: function () {
                var options = this.options;
                var round$$1 = options.roundToBaseUnit !== false;
                var totalRange = this.categoriesRange();
                var min = options.min;
                var max = options.max;
                if (!min) {
                    min = round$$1 ? this._roundToTotalStep(totalRange.min, options, false) : totalRange.min;
                }
                if (!max) {
                    max = round$$1 ? this._roundToTotalStep(totalRange.max, options, !options.justified) : totalRange.max;
                }
                return {
                    min: min,
                    max: max
                };
            },
            datesRange: function () {
                var range = this._categoryRange(this.options.srcCategories || this.options.categories);
                return {
                    min: toDate(range.min),
                    max: toDate(range.max)
                };
            },
            pan: function (delta) {
                var options = this.options;
                var lineBox = this.lineBox();
                var size = options.vertical ? lineBox.height() : lineBox.width();
                var ref = this.currentRange();
                var min = ref.min;
                var max = ref.max;
                var totalLimits = this.totalLimits();
                var scale = size / (max - min);
                var offset = round(delta / scale, DEFAULT_PRECISION);
                var from = addTicks(min, offset);
                var to = addTicks(max, offset);
                var panRange = this.limitRange(toTime(from), toTime(to), toTime(totalLimits.min), toTime(totalLimits.max), offset);
                if (panRange) {
                    panRange.min = toDate(panRange.min);
                    panRange.max = toDate(panRange.max);
                    panRange.baseUnit = options.baseUnit;
                    panRange.baseUnitStep = options.baseUnitStep || 1;
                    panRange.userSetBaseUnit = options.userSetBaseUnit;
                    panRange.userSetBaseUnitStep = options.userSetBaseUnitStep;
                    return panRange;
                }
            },
            pointsRange: function (start, end) {
                var pointsRange = CategoryAxis.fn.pointsRange.call(this, start, end);
                var datesRange = this.currentRange();
                var indicesRange = this.rangeIndices();
                var scale = dateDiff(datesRange.max, datesRange.min) / (indicesRange.max - indicesRange.min);
                var options = this.options;
                var min = addTicks(datesRange.min, pointsRange.min * scale);
                var max = addTicks(datesRange.min, pointsRange.max * scale);
                return {
                    min: min,
                    max: max,
                    baseUnit: options.userSetBaseUnit,
                    baseUnitStep: options.userSetBaseUnitStep
                };
            },
            zoomRange: function (delta) {
                var options = this.options;
                var totalLimits = this.totalLimits();
                var weekStartDay = options.weekStartDay;
                var baseUnit = options.baseUnit;
                var baseUnitStep = options.baseUnitStep || 1;
                var ref = this.currentRange();
                var rangeMin = ref.min;
                var rangeMax = ref.max;
                var min = addDuration(rangeMin, delta * baseUnitStep, baseUnit, weekStartDay);
                var max = addDuration(rangeMax, -delta * baseUnitStep, baseUnit, weekStartDay);
                if (options.userSetBaseUnit === FIT) {
                    var autoBaseUnitSteps = options.autoBaseUnitSteps;
                    var maxDateGroups = options.maxDateGroups;
                    var maxDiff = last(autoBaseUnitSteps[baseUnit]) * maxDateGroups * TIME_PER_UNIT[baseUnit];
                    var rangeDiff = dateDiff(rangeMax, rangeMin);
                    var diff = dateDiff(max, min);
                    var baseUnitIndex = BASE_UNITS.indexOf(baseUnit);
                    var autoBaseUnitStep, ticks;
                    if (diff < TIME_PER_UNIT[baseUnit] && baseUnit !== MILLISECONDS) {
                        baseUnit = BASE_UNITS[baseUnitIndex - 1];
                        autoBaseUnitStep = last(autoBaseUnitSteps[baseUnit]);
                        ticks = (rangeDiff - (maxDateGroups - 1) * autoBaseUnitStep * TIME_PER_UNIT[baseUnit]) / 2;
                        min = addTicks(rangeMin, ticks);
                        max = addTicks(rangeMax, -ticks);
                    } else if (diff > maxDiff && baseUnit !== YEARS) {
                        var stepIndex = 0;
                        do {
                            baseUnitIndex++;
                            baseUnit = BASE_UNITS[baseUnitIndex];
                            stepIndex = 0;
                            ticks = 2 * TIME_PER_UNIT[baseUnit];
                            do {
                                autoBaseUnitStep = autoBaseUnitSteps[baseUnit][stepIndex];
                                stepIndex++;
                            } while (stepIndex < autoBaseUnitSteps[baseUnit].length && ticks * autoBaseUnitStep < rangeDiff);
                        } while (baseUnit !== YEARS && ticks * autoBaseUnitStep < rangeDiff);
                        ticks = (ticks * autoBaseUnitStep - rangeDiff) / 2;
                        if (ticks > 0) {
                            min = addTicks(rangeMin, -ticks);
                            max = addTicks(rangeMax, ticks);
                            min = addTicks(min, limitValue(max, totalLimits.min, totalLimits.max) - max);
                            max = addTicks(max, limitValue(min, totalLimits.min, totalLimits.max) - min);
                        }
                    }
                }
                min = toDate(limitValue(min, totalLimits.min, totalLimits.max));
                max = toDate(limitValue(max, totalLimits.min, totalLimits.max));
                if (min && max && dateDiff(max, min) > 0) {
                    return {
                        min: min,
                        max: max,
                        baseUnit: options.userSetBaseUnit,
                        baseUnitStep: options.userSetBaseUnitStep
                    };
                }
            },
            totalLimits: function () {
                var options = this.options;
                var datesRange = this.datesRange();
                var min = this._roundToTotalStep(toDate(datesRange.min), options, false);
                var max = datesRange.max;
                if (!options.justified) {
                    max = this._roundToTotalStep(max, options, true, dateEquals(max, this._roundToTotalStep(max, options, false)));
                }
                return {
                    min: min,
                    max: max
                };
            },
            range: function (rangeOptions) {
                var options = rangeOptions || this.options;
                var categories = options.categories;
                var autoUnit = options.baseUnit === FIT;
                var baseUnit = autoUnit ? BASE_UNITS[0] : options.baseUnit;
                var baseUnitStep = options.baseUnitStep || 1;
                var stepOptions = {
                    baseUnit: baseUnit,
                    baseUnitStep: baseUnitStep,
                    weekStartDay: options.weekStartDay
                };
                var categoryLimits = this._categoryRange(categories);
                var min = toDate(options.min || categoryLimits.min);
                var max = toDate(options.max || categoryLimits.max);
                return {
                    min: this._roundToTotalStep(min, stepOptions, false),
                    max: this._roundToTotalStep(max, stepOptions, true, true)
                };
            },
            autoBaseUnit: function (options) {
                var categoryLimits = this._categoryRange(options.categories);
                var span = toDate(options.max || categoryLimits.max) - toDate(options.min || categoryLimits.min);
                var maxDateGroups = options.maxDateGroups || this.options.maxDateGroups;
                var autoUnit = options.baseUnit === FIT;
                var autoUnitIx = 0;
                var baseUnit = autoUnit ? BASE_UNITS[autoUnitIx++] : options.baseUnit;
                var units = span / TIME_PER_UNIT[baseUnit];
                var totalUnits = units;
                var autoBaseUnitSteps = deepExtend({}, this.options.autoBaseUnitSteps, options.autoBaseUnitSteps);
                var unitSteps, step, nextStep;
                while (!step || units >= maxDateGroups) {
                    unitSteps = unitSteps || autoBaseUnitSteps[baseUnit].slice(0);
                    nextStep = unitSteps.shift();
                    if (nextStep) {
                        step = nextStep;
                        units = totalUnits / step;
                    } else if (baseUnit === last(BASE_UNITS)) {
                        step = Math.ceil(totalUnits / maxDateGroups);
                        break;
                    } else if (autoUnit) {
                        baseUnit = BASE_UNITS[autoUnitIx++] || last(BASE_UNITS);
                        totalUnits = span / TIME_PER_UNIT[baseUnit];
                        unitSteps = null;
                    } else {
                        if (units > maxDateGroups) {
                            step = Math.ceil(totalUnits / maxDateGroups);
                        }
                        break;
                    }
                }
                options.baseUnitStep = step;
                options.baseUnit = baseUnit;
            },
            groupCategories: function (options) {
                var categories = options.categories;
                var baseUnit = options.baseUnit;
                var baseUnitStep = options.baseUnitStep || 1;
                var maxCategory = toDate(sparseArrayLimits(categories).max);
                var ref = this.range(options);
                var min = ref.min;
                var max = ref.max;
                var groups = [];
                var nextDate;
                for (var date = min; date < max; date = nextDate) {
                    groups.push(date);
                    nextDate = addDuration(date, baseUnitStep, baseUnit, options.weekStartDay);
                    if (nextDate > maxCategory && !options.max) {
                        break;
                    }
                }
                options.srcCategories = categories;
                options.categories = groups;
            },
            _roundToTotalStep: function (value, axisOptions, upper, roundToNext) {
                var options = axisOptions || this.options;
                var baseUnit = options.baseUnit;
                var baseUnitStep = options.baseUnitStep || 1;
                var start = this._groupsStart;
                if (start) {
                    var step = dateIndex(value, start, baseUnit, baseUnitStep);
                    var roundedStep = upper ? Math.ceil(step) : Math.floor(step);
                    if (roundToNext) {
                        roundedStep++;
                    }
                    return addDuration(start, roundedStep * baseUnitStep, baseUnit, options.weekStartDay);
                }
                return addDuration(value, upper ? baseUnitStep : 0, baseUnit, options.weekStartDay);
            },
            createAxisLabel: function (index, labelOptions) {
                var options = this.options;
                var dataItem = options.dataItems ? options.dataItems[index] : null;
                var date = options.categories[index];
                var baseUnit = options.baseUnit;
                var unitFormat = labelOptions.dateFormats[baseUnit];
                var visible = true;
                if (options.justified) {
                    var roundedDate = floorDate(date, baseUnit, options.weekStartDay);
                    visible = dateEquals(roundedDate, date);
                } else if (!options.roundToBaseUnit) {
                    visible = !dateEquals(this.range().max, date);
                }
                if (visible) {
                    labelOptions.format = labelOptions.format || unitFormat;
                    var text = this.axisLabelText(date, dataItem, labelOptions);
                    if (text) {
                        return new AxisLabel(date, text, index, dataItem, labelOptions);
                    }
                }
            },
            categoryIndex: function (value) {
                var options = this.options;
                var categories = options.categories;
                var index = -1;
                if (categories.length) {
                    index = Math.floor(dateIndex(toDate(value), categories[0], options.baseUnit, options.baseUnitStep || 1));
                }
                return index;
            },
            getSlot: function (a, b, limit) {
                var start = a;
                var end = b;
                if (typeof start === OBJECT) {
                    start = this.categoryIndex(start);
                }
                if (typeof end === OBJECT) {
                    end = this.categoryIndex(end);
                }
                return CategoryAxis.fn.getSlot.call(this, start, end, limit);
            },
            valueRange: function () {
                var options = this.options;
                var range = this._categoryRange(options.srcCategories || options.categories);
                return {
                    min: toDate(range.min),
                    max: toDate(range.max)
                };
            }
        });
        setDefaultOptions(DateCategoryAxis, {
            type: DATE,
            labels: { dateFormats: DateLabelFormats },
            autoBaseUnitSteps: {
                milliseconds: [
                    1,
                    10,
                    100
                ],
                seconds: [
                    1,
                    2,
                    5,
                    15,
                    30
                ],
                minutes: [
                    1,
                    2,
                    5,
                    15,
                    30
                ],
                hours: [
                    1,
                    2,
                    3
                ],
                days: [
                    1,
                    2,
                    3
                ],
                weeks: [
                    1,
                    2
                ],
                months: [
                    1,
                    2,
                    3,
                    6
                ],
                years: [
                    1,
                    2,
                    3,
                    5,
                    10,
                    25,
                    50
                ]
            },
            maxDateGroups: 10
        });
        function autoMajorUnit(min, max) {
            var diff = round(max - min, DEFAULT_PRECISION - 1);
            if (diff === 0) {
                if (max === 0) {
                    return 0.1;
                }
                diff = Math.abs(max);
            }
            var scale = Math.pow(10, Math.floor(Math.log(diff) / Math.log(10)));
            var relativeValue = round(diff / scale, DEFAULT_PRECISION);
            var scaleMultiplier = 1;
            if (relativeValue < 1.904762) {
                scaleMultiplier = 0.2;
            } else if (relativeValue < 4.761904) {
                scaleMultiplier = 0.5;
            } else if (relativeValue < 9.523809) {
                scaleMultiplier = 1;
            } else {
                scaleMultiplier = 2;
            }
            return round(scale * scaleMultiplier, DEFAULT_PRECISION);
        }
        function autoAxisMin(min, max, narrow) {
            if (!min && !max) {
                return 0;
            }
            var axisMin;
            if (min >= 0 && max >= 0) {
                var minValue = min === max ? 0 : min;
                var diff = (max - minValue) / max;
                if (narrow === false || !narrow && diff > ZERO_THRESHOLD) {
                    return 0;
                }
                axisMin = Math.max(0, minValue - (max - minValue) / 2);
            } else {
                axisMin = min;
            }
            return axisMin;
        }
        function autoAxisMax(min, max, narrow) {
            if (!min && !max) {
                return 1;
            }
            var axisMax;
            if (min <= 0 && max <= 0) {
                var maxValue = min === max ? 0 : max;
                var diff = Math.abs((maxValue - min) / maxValue);
                if (narrow === false || !narrow && diff > ZERO_THRESHOLD) {
                    return 0;
                }
                axisMax = Math.min(0, maxValue - (min - maxValue) / 2);
            } else {
                axisMax = max;
            }
            return axisMax;
        }
        function floor(value, step) {
            return round(Math.floor(value / step) * step, DEFAULT_PRECISION);
        }
        function ceil(value, step) {
            return round(Math.ceil(value / step) * step, DEFAULT_PRECISION);
        }
        function limitCoordinate(value) {
            return Math.max(Math.min(value, COORDINATE_LIMIT), -COORDINATE_LIMIT);
        }
        var MIN_VALUE_RANGE = Math.pow(10, -DEFAULT_PRECISION + 1);
        var NumericAxis = Axis.extend({
            init: function (seriesMin, seriesMax, options, chartService) {
                var autoOptions = autoAxisOptions(seriesMin, seriesMax, options);
                var totalOptions = totalAxisOptions(autoOptions, options);
                Axis.fn.init.call(this, axisOptions(autoOptions, options), chartService);
                this.totalMin = totalOptions.min;
                this.totalMax = totalOptions.max;
                this.totalMajorUnit = totalOptions.majorUnit;
                this.seriesMin = seriesMin;
                this.seriesMax = seriesMax;
            },
            startValue: function () {
                return 0;
            },
            range: function () {
                var options = this.options;
                return {
                    min: options.min,
                    max: options.max
                };
            },
            getDivisions: function (stepValue) {
                if (stepValue === 0) {
                    return 1;
                }
                var options = this.options;
                var range = options.max - options.min;
                return Math.floor(round(range / stepValue, COORD_PRECISION)) + 1;
            },
            getTickPositions: function (unit, skipUnit) {
                var options = this.options;
                var vertical = options.vertical;
                var reverse = options.reverse;
                var lineBox = this.lineBox();
                var lineSize = vertical ? lineBox.height() : lineBox.width();
                var range = options.max - options.min;
                var scale = lineSize / range;
                var step = unit * scale;
                var divisions = this.getDivisions(unit);
                var dir = (vertical ? -1 : 1) * (reverse ? -1 : 1);
                var startEdge = dir === 1 ? 1 : 2;
                var positions = [];
                var pos = lineBox[(vertical ? Y : X) + startEdge];
                var skipStep = 0;
                if (skipUnit) {
                    skipStep = skipUnit / unit;
                }
                for (var idx = 0; idx < divisions; idx++) {
                    if (idx % skipStep !== 0) {
                        positions.push(round(pos, COORD_PRECISION));
                    }
                    pos = pos + step * dir;
                }
                return positions;
            },
            getMajorTickPositions: function () {
                return this.getTickPositions(this.options.majorUnit);
            },
            getMinorTickPositions: function () {
                return this.getTickPositions(this.options.minorUnit);
            },
            getSlot: function (a, b, limit) {
                if (limit === void 0) {
                    limit = false;
                }
                var options = this.options;
                var vertical = options.vertical;
                var reverse = options.reverse;
                var valueAxis = vertical ? Y : X;
                var lineBox = this.lineBox();
                var lineStart = lineBox[valueAxis + (reverse ? 2 : 1)];
                var lineSize = vertical ? lineBox.height() : lineBox.width();
                var dir = reverse ? -1 : 1;
                var step = dir * (lineSize / (options.max - options.min));
                var slotBox = new Box(lineBox.x1, lineBox.y1, lineBox.x1, lineBox.y1);
                var start = a;
                var end = b;
                if (!defined(start)) {
                    start = end || 0;
                }
                if (!defined(end)) {
                    end = start || 0;
                }
                if (limit) {
                    start = Math.max(Math.min(start, options.max), options.min);
                    end = Math.max(Math.min(end, options.max), options.min);
                }
                var p1, p2;
                if (vertical) {
                    p1 = options.max - Math.max(start, end);
                    p2 = options.max - Math.min(start, end);
                } else {
                    p1 = Math.min(start, end) - options.min;
                    p2 = Math.max(start, end) - options.min;
                }
                slotBox[valueAxis + 1] = limitCoordinate(lineStart + step * (reverse ? p2 : p1));
                slotBox[valueAxis + 2] = limitCoordinate(lineStart + step * (reverse ? p1 : p2));
                return slotBox;
            },
            getValue: function (point) {
                var options = this.options;
                var vertical = options.vertical;
                var reverse = options.reverse;
                var max = Number(options.max);
                var min = Number(options.min);
                var valueAxis = vertical ? Y : X;
                var lineBox = this.lineBox();
                var lineStart = lineBox[valueAxis + (reverse ? 2 : 1)];
                var lineSize = vertical ? lineBox.height() : lineBox.width();
                var dir = reverse ? -1 : 1;
                var offset = dir * (point[valueAxis] - lineStart);
                var step = (max - min) / lineSize;
                var valueOffset = offset * step;
                if (offset < 0 || offset > lineSize) {
                    return null;
                }
                var value = vertical ? max - valueOffset : min + valueOffset;
                return round(value, DEFAULT_PRECISION);
            },
            translateRange: function (delta) {
                var options = this.options;
                var vertical = options.vertical;
                var reverse = options.reverse;
                var max = options.max;
                var min = options.min;
                var lineBox = this.lineBox();
                var size = vertical ? lineBox.height() : lineBox.width();
                var range = max - min;
                var scale = size / range;
                var offset = round(delta / scale, DEFAULT_PRECISION);
                if ((vertical || reverse) && !(vertical && reverse)) {
                    offset = -offset;
                }
                return {
                    min: min + offset,
                    max: max + offset
                };
            },
            scaleRange: function (delta) {
                var options = this.options;
                var offset = -delta * options.majorUnit;
                return {
                    min: options.min - offset,
                    max: options.max + offset
                };
            },
            labelsCount: function () {
                return this.getDivisions(this.options.majorUnit);
            },
            createAxisLabel: function (index, labelOptions) {
                var options = this.options;
                var value = round(options.min + index * options.majorUnit, DEFAULT_PRECISION);
                var text = this.axisLabelText(value, null, labelOptions);
                return new AxisLabel(value, text, index, null, labelOptions);
            },
            shouldRenderNote: function (value) {
                var range = this.range();
                return range.min <= value && value <= range.max;
            },
            pan: function (delta) {
                var range = this.translateRange(delta);
                return this.limitRange(range.min, range.max, this.totalMin, this.totalMax);
            },
            pointsRange: function (start, end) {
                var startValue = this.getValue(start);
                var endValue = this.getValue(end);
                var min = Math.min(startValue, endValue);
                var max = Math.max(startValue, endValue);
                if (this.isValidRange(min, max)) {
                    return {
                        min: min,
                        max: max
                    };
                }
            },
            zoomRange: function (delta) {
                var ref = this;
                var totalMin = ref.totalMin;
                var totalMax = ref.totalMax;
                var newRange = this.scaleRange(delta);
                var min = limitValue(newRange.min, totalMin, totalMax);
                var max = limitValue(newRange.max, totalMin, totalMax);
                if (this.isValidRange(min, max)) {
                    return {
                        min: min,
                        max: max
                    };
                }
            },
            isValidRange: function (min, max) {
                return max - min > MIN_VALUE_RANGE;
            }
        });
        function autoAxisOptions(seriesMin, seriesMax, options) {
            var narrowRange = options.narrowRange;
            var autoMin = autoAxisMin(seriesMin, seriesMax, narrowRange);
            var autoMax = autoAxisMax(seriesMin, seriesMax, narrowRange);
            var majorUnit = autoMajorUnit(autoMin, autoMax);
            var autoOptions = { majorUnit: majorUnit };
            if (options.roundToMajorUnit !== false) {
                if (autoMin < 0 && remainderClose(autoMin, majorUnit, 1 / 3)) {
                    autoMin -= majorUnit;
                }
                if (autoMax > 0 && remainderClose(autoMax, majorUnit, 1 / 3)) {
                    autoMax += majorUnit;
                }
            }
            autoOptions.min = floor(autoMin, majorUnit);
            autoOptions.max = ceil(autoMax, majorUnit);
            return autoOptions;
        }
        function totalAxisOptions(autoOptions, options) {
            return {
                min: defined(options.min) ? Math.min(autoOptions.min, options.min) : autoOptions.min,
                max: defined(options.max) ? Math.max(autoOptions.max, options.max) : autoOptions.max,
                majorUnit: autoOptions.majorUnit
            };
        }
        function axisOptions(autoOptions, userOptions) {
            var options = userOptions;
            if (userOptions) {
                var userSetLimits = defined(userOptions.min) || defined(userOptions.max);
                if (userSetLimits) {
                    if (userOptions.min === userOptions.max) {
                        if (userOptions.min > 0) {
                            userOptions.min = 0;
                        } else {
                            userOptions.max = 1;
                        }
                    }
                }
                if (userOptions.majorUnit) {
                    autoOptions.min = floor(autoOptions.min, userOptions.majorUnit);
                    autoOptions.max = ceil(autoOptions.max, userOptions.majorUnit);
                } else if (userSetLimits) {
                    options = deepExtend(autoOptions, userOptions);
                    autoOptions.majorUnit = autoMajorUnit(options.min, options.max);
                }
            }
            autoOptions.minorUnit = (options.majorUnit || autoOptions.majorUnit) / 5;
            return deepExtend(autoOptions, options);
        }
        function remainderClose(value, divisor, ratio) {
            var remainder = round(Math.abs(value % divisor), DEFAULT_PRECISION);
            var threshold = divisor * (1 - ratio);
            return remainder === 0 || remainder > threshold;
        }
        setDefaultOptions(NumericAxis, {
            type: 'numeric',
            min: 0,
            max: 1,
            vertical: true,
            majorGridLines: {
                visible: true,
                width: 1,
                color: BLACK
            },
            labels: { format: '#.####################' },
            zIndex: 1
        });
        var DateValueAxis = Axis.extend({
            init: function (seriesMin, seriesMax, axisOptions, chartService) {
                var min = toDate(seriesMin);
                var max = toDate(seriesMax);
                var intlService = chartService.intl;
                var options = axisOptions || {};
                options = deepExtend(options || {}, {
                    min: parseDate(intlService, options.min),
                    max: parseDate(intlService, options.max),
                    axisCrossingValue: parseDates(intlService, options.axisCrossingValues || options.axisCrossingValue)
                });
                options = applyDefaults(min, max, options);
                Axis.fn.init.call(this, options, chartService);
                this.seriesMin = min;
                this.seriesMax = max;
                this.totalMin = toTime(floorDate(toTime(min) - 1, options.baseUnit));
                this.totalMax = toTime(ceilDate(toTime(max) + 1, options.baseUnit));
            },
            range: function () {
                var options = this.options;
                return {
                    min: options.min,
                    max: options.max
                };
            },
            getDivisions: function (stepValue) {
                var options = this.options;
                return Math.floor(duration(options.min, options.max, options.baseUnit) / stepValue + 1);
            },
            getTickPositions: function (step) {
                var options = this.options;
                var vertical = options.vertical;
                var lineBox = this.lineBox();
                var dir = (vertical ? -1 : 1) * (options.reverse ? -1 : 1);
                var startEdge = dir === 1 ? 1 : 2;
                var start = lineBox[(vertical ? Y : X) + startEdge];
                var divisions = this.getDivisions(step);
                var timeRange = dateDiff(options.max, options.min);
                var lineSize = vertical ? lineBox.height() : lineBox.width();
                var scale = lineSize / timeRange;
                var positions = [start];
                for (var i = 1; i < divisions; i++) {
                    var date = addDuration(options.min, i * step, options.baseUnit);
                    var pos = start + dateDiff(date, options.min) * scale * dir;
                    positions.push(round(pos, COORD_PRECISION));
                }
                return positions;
            },
            getMajorTickPositions: function () {
                return this.getTickPositions(this.options.majorUnit);
            },
            getMinorTickPositions: function () {
                return this.getTickPositions(this.options.minorUnit);
            },
            getSlot: function (a, b, limit) {
                return NumericAxis.prototype.getSlot.call(this, toDate(a), toDate(b), limit);
            },
            getValue: function (point) {
                var value = NumericAxis.prototype.getValue.call(this, point);
                return value !== null ? toDate(value) : null;
            },
            labelsCount: function () {
                return this.getDivisions(this.options.majorUnit);
            },
            createAxisLabel: function (index, labelOptions) {
                var options = this.options;
                var offset = index * options.majorUnit;
                var date = options.min;
                if (offset > 0) {
                    date = addDuration(date, offset, options.baseUnit);
                }
                var unitFormat = labelOptions.dateFormats[options.baseUnit];
                labelOptions.format = labelOptions.format || unitFormat;
                var text = this.axisLabelText(date, null, labelOptions);
                return new AxisLabel(date, text, index, null, labelOptions);
            },
            translateRange: function (delta, exact) {
                var options = this.options;
                var baseUnit = options.baseUnit;
                var weekStartDay = options.weekStartDay;
                var lineBox = this.lineBox();
                var size = options.vertical ? lineBox.height() : lineBox.width();
                var range = this.range();
                var scale = size / dateDiff(range.max, range.min);
                var offset = round(delta / scale, DEFAULT_PRECISION);
                var from = addTicks(options.min, offset);
                var to = addTicks(options.max, offset);
                if (!exact) {
                    from = addDuration(from, 0, baseUnit, weekStartDay);
                    to = addDuration(to, 0, baseUnit, weekStartDay);
                }
                return {
                    min: from,
                    max: to
                };
            },
            scaleRange: function (delta) {
                var ref = this.options;
                var from = ref.min;
                var to = ref.max;
                var rounds = Math.abs(delta);
                while (rounds--) {
                    var range = dateDiff(from, to);
                    var step = Math.round(range * 0.1);
                    if (delta < 0) {
                        from = addTicks(from, step);
                        to = addTicks(to, -step);
                    } else {
                        from = addTicks(from, -step);
                        to = addTicks(to, step);
                    }
                }
                return {
                    min: from,
                    max: to
                };
            },
            shouldRenderNote: function (value) {
                var range = this.range();
                return dateComparer(value, range.min) >= 0 && dateComparer(value, range.max) <= 0;
            },
            pan: function (delta) {
                var range = this.translateRange(delta, true);
                var limittedRange = this.limitRange(toTime(range.min), toTime(range.max), this.totalMin, this.totalMax);
                if (limittedRange) {
                    return {
                        min: toDate(limittedRange.min),
                        max: toDate(limittedRange.max)
                    };
                }
            },
            pointsRange: function (start, end) {
                var startValue = this.getValue(start);
                var endValue = this.getValue(end);
                var min = Math.min(startValue, endValue);
                var max = Math.max(startValue, endValue);
                return {
                    min: toDate(min),
                    max: toDate(max)
                };
            },
            zoomRange: function (delta) {
                var range = this.scaleRange(delta);
                var min = toDate(limitValue(toTime(range.min), this.totalMin, this.totalMax));
                var max = toDate(limitValue(toTime(range.max), this.totalMin, this.totalMax));
                return {
                    min: min,
                    max: max
                };
            }
        });
        function timeUnits(delta) {
            var unit = HOURS;
            if (delta >= TIME_PER_YEAR) {
                unit = YEARS;
            } else if (delta >= TIME_PER_MONTH) {
                unit = MONTHS;
            } else if (delta >= TIME_PER_WEEK) {
                unit = WEEKS;
            } else if (delta >= TIME_PER_DAY) {
                unit = DAYS;
            }
            return unit;
        }
        function applyDefaults(seriesMin, seriesMax, options) {
            var min = options.min || seriesMin;
            var max = options.max || seriesMax;
            var baseUnit = options.baseUnit || (max && min ? timeUnits(absoluteDateDiff(max, min)) : HOURS);
            var baseUnitTime = TIME_PER_UNIT[baseUnit];
            var autoMin = floorDate(toTime(min) - 1, baseUnit) || toDate(max);
            var autoMax = ceilDate(toTime(max) + 1, baseUnit);
            var userMajorUnit = options.majorUnit ? options.majorUnit : undefined;
            var majorUnit = userMajorUnit || ceil(autoMajorUnit(autoMin.getTime(), autoMax.getTime()), baseUnitTime) / baseUnitTime;
            var actualUnits = duration(autoMin, autoMax, baseUnit);
            var totalUnits = ceil(actualUnits, majorUnit);
            var unitsToAdd = totalUnits - actualUnits;
            var head = Math.floor(unitsToAdd / 2);
            var tail = unitsToAdd - head;
            if (!options.baseUnit) {
                delete options.baseUnit;
            }
            options.baseUnit = options.baseUnit || baseUnit;
            options.min = options.min || addDuration(autoMin, -head, baseUnit);
            options.max = options.max || addDuration(autoMax, tail, baseUnit);
            options.minorUnit = options.minorUnit || majorUnit / 5;
            options.majorUnit = majorUnit;
            return options;
        }
        setDefaultOptions(DateValueAxis, {
            type: DATE,
            majorGridLines: {
                visible: true,
                width: 1,
                color: BLACK
            },
            labels: { dateFormats: DateLabelFormats }
        });
        var DEFAULT_MAJOR_UNIT = 10;
        var LogarithmicAxis = Axis.extend({
            init: function (seriesMin, seriesMax, options, chartService) {
                var axisOptions = deepExtend({
                    majorUnit: DEFAULT_MAJOR_UNIT,
                    min: seriesMin,
                    max: seriesMax
                }, options);
                var base = axisOptions.majorUnit;
                var autoMax = autoAxisMax$1(seriesMax, base);
                var autoMin = autoAxisMin$1(seriesMin, seriesMax, axisOptions);
                var range = initRange(autoMin, autoMax, axisOptions, options);
                axisOptions.max = range.max;
                axisOptions.min = range.min;
                axisOptions.minorUnit = options.minorUnit || round(base - 1, DEFAULT_PRECISION);
                Axis.fn.init.call(this, axisOptions, chartService);
                this.totalMin = defined(options.min) ? Math.min(autoMin, options.min) : autoMin;
                this.totalMax = defined(options.max) ? Math.max(autoMax, options.max) : autoMax;
                this.logMin = round(log(range.min, base), DEFAULT_PRECISION);
                this.logMax = round(log(range.max, base), DEFAULT_PRECISION);
                this.seriesMin = seriesMin;
                this.seriesMax = seriesMax;
                this.createLabels();
            },
            startValue: function () {
                return this.options.min;
            },
            getSlot: function (a, b, limit) {
                var ref = this;
                var options = ref.options;
                var logMin = ref.logMin;
                var logMax = ref.logMax;
                var reverse = options.reverse;
                var vertical = options.vertical;
                var base = options.majorUnit;
                var valueAxis = vertical ? Y : X;
                var lineBox = this.lineBox();
                var lineStart = lineBox[valueAxis + (reverse ? 2 : 1)];
                var lineSize = vertical ? lineBox.height() : lineBox.width();
                var dir = reverse ? -1 : 1;
                var step = dir * (lineSize / (logMax - logMin));
                var slotBox = new Box(lineBox.x1, lineBox.y1, lineBox.x1, lineBox.y1);
                var start = a;
                var end = b;
                if (!defined(start)) {
                    start = end || 1;
                }
                if (!defined(end)) {
                    end = start || 1;
                }
                if (start <= 0 || end <= 0) {
                    return null;
                }
                if (limit) {
                    start = Math.max(Math.min(start, options.max), options.min);
                    end = Math.max(Math.min(end, options.max), options.min);
                }
                start = log(start, base);
                end = log(end, base);
                var p1, p2;
                if (vertical) {
                    p1 = logMax - Math.max(start, end);
                    p2 = logMax - Math.min(start, end);
                } else {
                    p1 = Math.min(start, end) - logMin;
                    p2 = Math.max(start, end) - logMin;
                }
                slotBox[valueAxis + 1] = limitCoordinate(lineStart + step * (reverse ? p2 : p1));
                slotBox[valueAxis + 2] = limitCoordinate(lineStart + step * (reverse ? p1 : p2));
                return slotBox;
            },
            getValue: function (point) {
                var ref = this;
                var options = ref.options;
                var logMin = ref.logMin;
                var logMax = ref.logMax;
                var reverse = options.reverse;
                var vertical = options.vertical;
                var base = options.majorUnit;
                var lineBox = this.lineBox();
                var dir = vertical === reverse ? 1 : -1;
                var startEdge = dir === 1 ? 1 : 2;
                var lineSize = vertical ? lineBox.height() : lineBox.width();
                var step = (logMax - logMin) / lineSize;
                var valueAxis = vertical ? Y : X;
                var lineStart = lineBox[valueAxis + startEdge];
                var offset = dir * (point[valueAxis] - lineStart);
                var valueOffset = offset * step;
                if (offset < 0 || offset > lineSize) {
                    return null;
                }
                var value = logMin + valueOffset;
                return round(Math.pow(base, value), DEFAULT_PRECISION);
            },
            range: function () {
                var options = this.options;
                return {
                    min: options.min,
                    max: options.max
                };
            },
            scaleRange: function (delta) {
                var base = this.options.majorUnit;
                var offset = -delta;
                return {
                    min: Math.pow(base, this.logMin - offset),
                    max: Math.pow(base, this.logMax + offset)
                };
            },
            translateRange: function (delta) {
                var ref = this;
                var options = ref.options;
                var logMin = ref.logMin;
                var logMax = ref.logMax;
                var reverse = options.reverse;
                var vertical = options.vertical;
                var base = options.majorUnit;
                var lineBox = this.lineBox();
                var size = vertical ? lineBox.height() : lineBox.width();
                var scale = size / (logMax - logMin);
                var offset = round(delta / scale, DEFAULT_PRECISION);
                if ((vertical || reverse) && !(vertical && reverse)) {
                    offset = -offset;
                }
                return {
                    min: Math.pow(base, logMin + offset),
                    max: Math.pow(base, logMax + offset)
                };
            },
            labelsCount: function () {
                var floorMax = Math.floor(this.logMax);
                var count = Math.floor(floorMax - this.logMin) + 1;
                return count;
            },
            getMajorTickPositions: function () {
                var ticks = [];
                this.traverseMajorTicksPositions(function (position) {
                    ticks.push(position);
                }, {
                    step: 1,
                    skip: 0
                });
                return ticks;
            },
            createTicks: function (lineGroup) {
                var options = this.options;
                var majorTicks = options.majorTicks;
                var minorTicks = options.minorTicks;
                var vertical = options.vertical;
                var mirror = options.labels.mirror;
                var lineBox = this.lineBox();
                var ticks = [];
                var tickLineOptions = { vertical: vertical };
                function render(tickPosition, tickOptions) {
                    tickLineOptions.tickX = mirror ? lineBox.x2 : lineBox.x2 - tickOptions.size;
                    tickLineOptions.tickY = mirror ? lineBox.y1 - tickOptions.size : lineBox.y1;
                    tickLineOptions.position = tickPosition;
                    lineGroup.append(createAxisTick(tickLineOptions, tickOptions));
                }
                if (majorTicks.visible) {
                    this.traverseMajorTicksPositions(render, majorTicks);
                }
                if (minorTicks.visible) {
                    this.traverseMinorTicksPositions(render, minorTicks);
                }
                return ticks;
            },
            createGridLines: function (altAxis) {
                var options = this.options;
                var minorGridLines = options.minorGridLines;
                var majorGridLines = options.majorGridLines;
                var vertical = options.vertical;
                var lineBox = altAxis.lineBox();
                var lineOptions = {
                    lineStart: lineBox[vertical ? 'x1' : 'y1'],
                    lineEnd: lineBox[vertical ? 'x2' : 'y2'],
                    vertical: vertical
                };
                var majorTicks = [];
                var container = this.gridLinesVisual();
                function render(tickPosition, gridLine) {
                    if (!inArray(tickPosition, majorTicks)) {
                        lineOptions.position = tickPosition;
                        container.append(createAxisGridLine(lineOptions, gridLine));
                        majorTicks.push(tickPosition);
                    }
                }
                if (majorGridLines.visible) {
                    this.traverseMajorTicksPositions(render, majorGridLines);
                }
                if (minorGridLines.visible) {
                    this.traverseMinorTicksPositions(render, minorGridLines);
                }
                return container.children;
            },
            traverseMajorTicksPositions: function (callback, tickOptions) {
                var ref = this._lineOptions();
                var lineStart = ref.lineStart;
                var step = ref.step;
                var ref$1 = this;
                var logMin = ref$1.logMin;
                var logMax = ref$1.logMax;
                for (var power = Math.ceil(logMin) + tickOptions.skip; power <= logMax; power += tickOptions.step) {
                    var position = round(lineStart + step * (power - logMin), DEFAULT_PRECISION);
                    callback(position, tickOptions);
                }
            },
            traverseMinorTicksPositions: function (callback, tickOptions) {
                var this$1 = this;
                var ref = this.options;
                var min = ref.min;
                var max = ref.max;
                var minorUnit = ref.minorUnit;
                var base = ref.majorUnit;
                var ref$1 = this._lineOptions();
                var lineStart = ref$1.lineStart;
                var step = ref$1.step;
                var ref$2 = this;
                var logMin = ref$2.logMin;
                var logMax = ref$2.logMax;
                var start = Math.floor(logMin);
                for (var power = start; power < logMax; power++) {
                    var minorOptions = this$1._minorIntervalOptions(power);
                    for (var idx = tickOptions.skip; idx < minorUnit; idx += tickOptions.step) {
                        var value = minorOptions.value + idx * minorOptions.minorStep;
                        if (value > max) {
                            break;
                        }
                        if (value >= min) {
                            var position = round(lineStart + step * (log(value, base) - logMin), DEFAULT_PRECISION);
                            callback(position, tickOptions);
                        }
                    }
                }
            },
            createAxisLabel: function (index, labelOptions) {
                var power = Math.ceil(this.logMin + index);
                var value = Math.pow(this.options.majorUnit, power);
                var text = this.axisLabelText(value, null, labelOptions);
                return new AxisLabel(value, text, index, null, labelOptions);
            },
            shouldRenderNote: function (value) {
                var range = this.range();
                return range.min <= value && value <= range.max;
            },
            pan: function (delta) {
                var range = this.translateRange(delta);
                return this.limitRange(range.min, range.max, this.totalMin, this.totalMax, -delta);
            },
            pointsRange: function (start, end) {
                var startValue = this.getValue(start);
                var endValue = this.getValue(end);
                var min = Math.min(startValue, endValue);
                var max = Math.max(startValue, endValue);
                return {
                    min: min,
                    max: max
                };
            },
            zoomRange: function (delta) {
                var ref = this;
                var options = ref.options;
                var totalMin = ref.totalMin;
                var totalMax = ref.totalMax;
                var newRange = this.scaleRange(delta);
                var min = limitValue(newRange.min, totalMin, totalMax);
                var max = limitValue(newRange.max, totalMin, totalMax);
                var base = options.majorUnit;
                var acceptOptionsRange = max > min && options.min && options.max && round(log(options.max, base) - log(options.min, base), DEFAULT_PRECISION) < 1;
                var acceptNewRange = !(options.min === totalMin && options.max === totalMax) && round(log(max, base) - log(min, base), DEFAULT_PRECISION) >= 1;
                if (acceptOptionsRange || acceptNewRange) {
                    return {
                        min: min,
                        max: max
                    };
                }
            },
            _minorIntervalOptions: function (power) {
                var ref = this.options;
                var minorUnit = ref.minorUnit;
                var base = ref.majorUnit;
                var value = Math.pow(base, power);
                var nextValue = Math.pow(base, power + 1);
                var difference = nextValue - value;
                var minorStep = difference / minorUnit;
                return {
                    value: value,
                    minorStep: minorStep
                };
            },
            _lineOptions: function () {
                var ref = this.options;
                var reverse = ref.reverse;
                var vertical = ref.vertical;
                var valueAxis = vertical ? Y : X;
                var lineBox = this.lineBox();
                var dir = vertical === reverse ? 1 : -1;
                var startEdge = dir === 1 ? 1 : 2;
                var lineSize = vertical ? lineBox.height() : lineBox.width();
                var step = dir * (lineSize / (this.logMax - this.logMin));
                var lineStart = lineBox[valueAxis + startEdge];
                return {
                    step: step,
                    lineStart: lineStart,
                    lineBox: lineBox
                };
            }
        });
        function initRange(autoMin, autoMax, axisOptions, options) {
            var min = axisOptions.min;
            var max = axisOptions.max;
            if (defined(axisOptions.axisCrossingValue) && axisOptions.axisCrossingValue <= 0) {
                throwNegativeValuesError();
            }
            if (!defined(options.max)) {
                max = autoMax;
            } else if (options.max <= 0) {
                throwNegativeValuesError();
            }
            if (!defined(options.min)) {
                min = autoMin;
            } else if (options.min <= 0) {
                throwNegativeValuesError();
            }
            return {
                min: min,
                max: max
            };
        }
        function autoAxisMin$1(min, max, options) {
            var base = options.majorUnit;
            var autoMin = min;
            if (min <= 0) {
                autoMin = max <= 1 ? Math.pow(base, -2) : 1;
            } else if (!options.narrowRange) {
                autoMin = Math.pow(base, Math.floor(log(min, base)));
            }
            return autoMin;
        }
        function autoAxisMax$1(max, base) {
            var logMaxRemainder = round(log(max, base), DEFAULT_PRECISION) % 1;
            var autoMax;
            if (max <= 0) {
                autoMax = base;
            } else if (logMaxRemainder !== 0 && (logMaxRemainder < 0.3 || logMaxRemainder > 0.9)) {
                autoMax = Math.pow(base, log(max, base) + 0.2);
            } else {
                autoMax = Math.pow(base, Math.ceil(log(max, base)));
            }
            return autoMax;
        }
        function throwNegativeValuesError() {
            throw new Error('Non positive values cannot be used for a logarithmic axis');
        }
        function log(y, x) {
            return Math.log(y) / Math.log(x);
        }
        setDefaultOptions(LogarithmicAxis, {
            type: 'log',
            majorUnit: DEFAULT_MAJOR_UNIT,
            minorUnit: 1,
            axisCrossingValue: 1,
            vertical: true,
            majorGridLines: {
                visible: true,
                width: 1,
                color: BLACK
            },
            zIndex: 1,
            _deferLabels: true
        });
        var GridLinesMixin = {
            createGridLines: function (altAxis) {
                var options = this.options;
                var radius = Math.abs(this.box.center().y - altAxis.lineBox().y1);
                var gridLines = [];
                var skipMajor = false;
                var majorAngles, minorAngles;
                if (options.majorGridLines.visible) {
                    majorAngles = this.majorGridLineAngles(altAxis);
                    skipMajor = true;
                    gridLines = this.renderMajorGridLines(majorAngles, radius, options.majorGridLines);
                }
                if (options.minorGridLines.visible) {
                    minorAngles = this.minorGridLineAngles(altAxis, skipMajor);
                    append(gridLines, this.renderMinorGridLines(minorAngles, radius, options.minorGridLines, altAxis, skipMajor));
                }
                return gridLines;
            },
            renderMajorGridLines: function (angles, radius, options) {
                return this.renderGridLines(angles, radius, options);
            },
            renderMinorGridLines: function (angles, radius, options, altAxis, skipMajor) {
                var radiusCallback = this.radiusCallback && this.radiusCallback(radius, altAxis, skipMajor);
                return this.renderGridLines(angles, radius, options, radiusCallback);
            },
            renderGridLines: function (angles, radius, options, radiusCallback) {
                var style = {
                    stroke: {
                        width: options.width,
                        color: options.color,
                        dashType: options.dashType
                    }
                };
                var center = this.box.center();
                var circle = new Circle([
                    center.x,
                    center.y
                ], radius);
                var container = this.gridLinesVisual();
                for (var i = 0; i < angles.length; i++) {
                    var line = new Path(style);
                    if (radiusCallback) {
                        circle.radius = radiusCallback(angles[i]);
                    }
                    line.moveTo(circle.center).lineTo(circle.pointAt(angles[i] + 180));
                    container.append(line);
                }
                return container.children;
            },
            gridLineAngles: function (altAxis, size, skip, step, skipAngles) {
                var this$1 = this;
                var divs = this.intervals(size, skip, step, skipAngles);
                var options = altAxis.options;
                var altAxisVisible = options.visible && (options.line || {}).visible !== false;
                return map(divs, function (d) {
                    var alpha = this$1.intervalAngle(d);
                    if (!altAxisVisible || alpha !== 90) {
                        return alpha;
                    }
                });
            }
        };
        var RadarCategoryAxis = CategoryAxis.extend({
            range: function () {
                return {
                    min: 0,
                    max: this.options.categories.length
                };
            },
            reflow: function (box) {
                this.box = box;
                this.reflowLabels();
            },
            lineBox: function () {
                return this.box;
            },
            reflowLabels: function () {
                var this$1 = this;
                var ref = this;
                var labels = ref.labels;
                var labelOptions = ref.options.labels;
                var skip = labelOptions.skip || 0;
                var step = labelOptions.step || 1;
                var measureBox = new Box();
                for (var i = 0; i < labels.length; i++) {
                    labels[i].reflow(measureBox);
                    var labelBox = labels[i].box;
                    labels[i].reflow(this$1.getSlot(skip + i * step).adjacentBox(0, labelBox.width(), labelBox.height()));
                }
            },
            intervals: function (size, skipOption, stepOption, skipAngles) {
                if (skipAngles === void 0) {
                    skipAngles = false;
                }
                var options = this.options;
                var categories = options.categories.length;
                var divCount = categories / size || 1;
                var divAngle = 360 / divCount;
                var skip = skipOption || 0;
                var step = stepOption || 1;
                var divs = [];
                var angle = 0;
                for (var i = skip; i < divCount; i += step) {
                    if (options.reverse) {
                        angle = 360 - i * divAngle;
                    } else {
                        angle = i * divAngle;
                    }
                    angle = round(angle, COORD_PRECISION) % 360;
                    if (!(skipAngles && inArray(angle, skipAngles))) {
                        divs.push(angle);
                    }
                }
                return divs;
            },
            majorIntervals: function () {
                return this.intervals(1);
            },
            minorIntervals: function () {
                return this.intervals(0.5);
            },
            intervalAngle: function (interval) {
                return (360 + interval + this.options.startAngle) % 360;
            },
            majorAngles: function () {
                var this$1 = this;
                return map(this.majorIntervals(), function (interval) {
                    return this$1.intervalAngle(interval);
                });
            },
            createLine: function () {
                return [];
            },
            majorGridLineAngles: function (altAxis) {
                var majorGridLines = this.options.majorGridLines;
                return this.gridLineAngles(altAxis, 1, majorGridLines.skip, majorGridLines.step);
            },
            minorGridLineAngles: function (altAxis, skipMajor) {
                var ref = this.options;
                var minorGridLines = ref.minorGridLines;
                var majorGridLines = ref.majorGridLines;
                var majorGridLineAngles = skipMajor ? this.intervals(1, majorGridLines.skip, majorGridLines.step) : null;
                return this.gridLineAngles(altAxis, 0.5, minorGridLines.skip, minorGridLines.step, majorGridLineAngles);
            },
            radiusCallback: function (radius, altAxis, skipMajor) {
                if (altAxis.options.type !== ARC) {
                    var minorAngle = rad(360 / (this.options.categories.length * 2));
                    var minorRadius = Math.cos(minorAngle) * radius;
                    var majorAngles = this.majorAngles();
                    var radiusCallback = function (angle) {
                        if (!skipMajor && inArray(angle, majorAngles)) {
                            return radius;
                        }
                        return minorRadius;
                    };
                    return radiusCallback;
                }
            },
            createPlotBands: function () {
                var this$1 = this;
                var plotBands = this.options.plotBands || [];
                var group = this._plotbandGroup = new Group({ zIndex: -1 });
                for (var i = 0; i < plotBands.length; i++) {
                    var band = plotBands[i];
                    var slot = this$1.plotBandSlot(band);
                    var singleSlot = this$1.getSlot(band.from);
                    var head = band.from - Math.floor(band.from);
                    slot.startAngle += head * singleSlot.angle;
                    var tail = Math.ceil(band.to) - band.to;
                    slot.angle -= (tail + head) * singleSlot.angle;
                    var ring = ShapeBuilder.current.createRing(slot, {
                        fill: {
                            color: band.color,
                            opacity: band.opacity
                        },
                        stroke: { opacity: band.opacity }
                    });
                    group.append(ring);
                }
                this.appendVisual(group);
            },
            plotBandSlot: function (band) {
                return this.getSlot(band.from, band.to - 1);
            },
            getSlot: function (from, to) {
                var options = this.options;
                var justified = options.justified;
                var box = this.box;
                var divs = this.majorAngles();
                var totalDivs = divs.length;
                var slotAngle = 360 / totalDivs;
                var fromValue = from;
                if (options.reverse && !justified) {
                    fromValue = (fromValue + 1) % totalDivs;
                }
                fromValue = limitValue(Math.floor(fromValue), 0, totalDivs - 1);
                var slotStart = divs[fromValue];
                if (justified) {
                    slotStart = slotStart - slotAngle / 2;
                    if (slotStart < 0) {
                        slotStart += 360;
                    }
                }
                var toValue = limitValue(Math.ceil(to || fromValue), fromValue, totalDivs - 1);
                var slots = toValue - fromValue + 1;
                var angle = slotAngle * slots;
                return new Ring(box.center(), 0, box.height() / 2, slotStart, angle);
            },
            slot: function (from, to) {
                var slot = this.getSlot(from, to);
                var startAngle = slot.startAngle + 180;
                var endAngle = startAngle + slot.angle;
                return new geometry.Arc([
                    slot.center.x,
                    slot.center.y
                ], {
                    startAngle: startAngle,
                    endAngle: endAngle,
                    radiusX: slot.radius,
                    radiusY: slot.radius
                });
            },
            pointCategoryIndex: function (point) {
                var this$1 = this;
                var length = this.options.categories.length;
                var index = null;
                for (var i = 0; i < length; i++) {
                    var slot = this$1.getSlot(i);
                    if (slot.containsPoint(point)) {
                        index = i;
                        break;
                    }
                }
                return index;
            }
        });
        setDefaultOptions(RadarCategoryAxis, {
            startAngle: 90,
            labels: { margin: getSpacing(10) },
            majorGridLines: { visible: true },
            justified: true
        });
        deepExtend(RadarCategoryAxis.prototype, GridLinesMixin);
        var PolarAxis = Axis.extend({
            init: function (options, chartService) {
                Axis.fn.init.call(this, options, chartService);
                var instanceOptions = this.options;
                instanceOptions.minorUnit = instanceOptions.minorUnit || instanceOptions.majorUnit / 2;
            },
            getDivisions: function (stepValue) {
                return NumericAxis.prototype.getDivisions.call(this, stepValue) - 1;
            },
            reflow: function (box) {
                this.box = box;
                this.reflowLabels();
            },
            reflowLabels: function () {
                var this$1 = this;
                var ref = this;
                var options = ref.options;
                var labels = ref.labels;
                var labelOptions = ref.options.labels;
                var skip = labelOptions.skip || 0;
                var step = labelOptions.step || 1;
                var measureBox = new Box();
                var divs = this.intervals(options.majorUnit, skip, step);
                for (var i = 0; i < labels.length; i++) {
                    labels[i].reflow(measureBox);
                    var labelBox = labels[i].box;
                    labels[i].reflow(this$1.getSlot(divs[i]).adjacentBox(0, labelBox.width(), labelBox.height()));
                }
            },
            lineBox: function () {
                return this.box;
            },
            intervals: function (size, skipOption, stepOption, skipAngles) {
                if (skipAngles === void 0) {
                    skipAngles = false;
                }
                var min = this.options.min;
                var divisions = this.getDivisions(size);
                var divs = [];
                var skip = skipOption || 0;
                var step = stepOption || 1;
                for (var i = skip; i < divisions; i += step) {
                    var current = (360 + min + i * size) % 360;
                    if (!(skipAngles && inArray(current, skipAngles))) {
                        divs.push(current);
                    }
                }
                return divs;
            },
            majorIntervals: function () {
                return this.intervals(this.options.majorUnit);
            },
            minorIntervals: function () {
                return this.intervals(this.options.minorUnit);
            },
            intervalAngle: function (i) {
                return (540 - i - this.options.startAngle) % 360;
            },
            createLine: function () {
                return [];
            },
            majorGridLineAngles: function (altAxis) {
                var majorGridLines = this.options.majorGridLines;
                return this.gridLineAngles(altAxis, this.options.majorUnit, majorGridLines.skip, majorGridLines.step);
            },
            minorGridLineAngles: function (altAxis, skipMajor) {
                var options = this.options;
                var minorGridLines = options.minorGridLines;
                var majorGridLines = options.majorGridLines;
                var majorGridLineAngles = skipMajor ? this.intervals(options.majorUnit, majorGridLines.skip, majorGridLines.step) : null;
                return this.gridLineAngles(altAxis, options.minorUnit, minorGridLines.skip, minorGridLines.step, majorGridLineAngles);
            },
            plotBandSlot: function (band) {
                return this.getSlot(band.from, band.to);
            },
            getSlot: function (a, b) {
                var ref = this;
                var options = ref.options;
                var box = ref.box;
                var startAngle = options.startAngle;
                var start = limitValue(a, options.min, options.max);
                var end = limitValue(b || start, start, options.max);
                if (options.reverse) {
                    start *= -1;
                    end *= -1;
                }
                start = (540 - start - startAngle) % 360;
                end = (540 - end - startAngle) % 360;
                if (end < start) {
                    var tmp = start;
                    start = end;
                    end = tmp;
                }
                return new Ring(box.center(), 0, box.height() / 2, start, end - start);
            },
            slot: function (from, to) {
                if (to === void 0) {
                    to = from;
                }
                var options = this.options;
                var start = 360 - options.startAngle;
                var slot = this.getSlot(from, to);
                var min = Math.min(from, to);
                var max = Math.max(from, to);
                var startAngle, endAngle;
                if (options.reverse) {
                    startAngle = min;
                    endAngle = max;
                } else {
                    startAngle = 360 - max;
                    endAngle = 360 - min;
                }
                startAngle = (startAngle + start) % 360;
                endAngle = (endAngle + start) % 360;
                return new geometry.Arc([
                    slot.center.x,
                    slot.center.y
                ], {
                    startAngle: startAngle,
                    endAngle: endAngle,
                    radiusX: slot.radius,
                    radiusY: slot.radius
                });
            },
            getValue: function (point) {
                var options = this.options;
                var center = this.box.center();
                var dx = point.x - center.x;
                var dy = point.y - center.y;
                var theta = Math.round(deg(Math.atan2(dy, dx)));
                var start = options.startAngle;
                if (!options.reverse) {
                    theta *= -1;
                    start *= -1;
                }
                return (theta + start + 360) % 360;
            },
            valueRange: function () {
                return {
                    min: 0,
                    max: Math.PI * 2
                };
            }
        });
        setDefaultOptions(PolarAxis, {
            type: 'polar',
            startAngle: 0,
            reverse: false,
            majorUnit: 60,
            min: 0,
            max: 360,
            labels: { margin: getSpacing(10) },
            majorGridLines: {
                color: BLACK,
                visible: true,
                width: 1
            },
            minorGridLines: { color: '#aaa' }
        });
        deepExtend(PolarAxis.prototype, GridLinesMixin, {
            createPlotBands: RadarCategoryAxis.prototype.createPlotBands,
            majorAngles: RadarCategoryAxis.prototype.majorAngles,
            range: NumericAxis.prototype.range,
            labelsCount: NumericAxis.prototype.labelsCount,
            createAxisLabel: NumericAxis.prototype.createAxisLabel
        });
        var RadarNumericAxisMixin = {
            options: { majorGridLines: { visible: true } },
            createPlotBands: function () {
                var this$1 = this;
                var ref = this.options;
                var type = ref.majorGridLines.type;
                var plotBands = ref.plotBands;
                if (plotBands === void 0) {
                    plotBands = [];
                }
                var altAxis = this.plotArea.polarAxis;
                var majorAngles = altAxis.majorAngles();
                var center = altAxis.box.center();
                var group = this._plotbandGroup = new Group({ zIndex: -1 });
                for (var i = 0; i < plotBands.length; i++) {
                    var band = plotBands[i];
                    var bandStyle = {
                        fill: {
                            color: band.color,
                            opacity: band.opacity
                        },
                        stroke: { opacity: band.opacity }
                    };
                    var slot = this$1.getSlot(band.from, band.to, true);
                    var ring = new Ring(center, center.y - slot.y2, center.y - slot.y1, 0, 360);
                    var shape = void 0;
                    if (type === ARC) {
                        shape = ShapeBuilder.current.createRing(ring, bandStyle);
                    } else {
                        shape = Path.fromPoints(this$1.plotBandPoints(ring, majorAngles), bandStyle).close();
                    }
                    group.append(shape);
                }
                this.appendVisual(group);
            },
            plotBandPoints: function (ring, angles) {
                var innerPoints = [];
                var outerPoints = [];
                var center = [
                    ring.center.x,
                    ring.center.y
                ];
                var innerCircle = new Circle(center, ring.innerRadius);
                var outerCircle = new Circle(center, ring.radius);
                for (var i = 0; i < angles.length; i++) {
                    innerPoints.push(innerCircle.pointAt(angles[i] + 180));
                    outerPoints.push(outerCircle.pointAt(angles[i] + 180));
                }
                innerPoints.reverse();
                innerPoints.push(innerPoints[0]);
                outerPoints.push(outerPoints[0]);
                return outerPoints.concat(innerPoints);
            },
            createGridLines: function (altAxis) {
                var options = this.options;
                var majorTicks = this.radarMajorGridLinePositions();
                var majorAngles = altAxis.majorAngles();
                var center = altAxis.box.center();
                var gridLines = [];
                if (options.majorGridLines.visible) {
                    gridLines = this.renderGridLines(center, majorTicks, majorAngles, options.majorGridLines);
                }
                if (options.minorGridLines.visible) {
                    var minorTicks = this.radarMinorGridLinePositions();
                    append(gridLines, this.renderGridLines(center, minorTicks, majorAngles, options.minorGridLines));
                }
                return gridLines;
            },
            renderGridLines: function (center, ticks, angles, options) {
                var style = {
                    stroke: {
                        width: options.width,
                        color: options.color,
                        dashType: options.dashType
                    }
                };
                var skip = options.skip;
                if (skip === void 0) {
                    skip = 0;
                }
                var step = options.step;
                if (step === void 0) {
                    step = 0;
                }
                var container = this.gridLinesVisual();
                for (var tickIx = skip; tickIx < ticks.length; tickIx += step) {
                    var tickRadius = center.y - ticks[tickIx];
                    if (tickRadius > 0) {
                        var circle = new Circle([
                            center.x,
                            center.y
                        ], tickRadius);
                        if (options.type === ARC) {
                            container.append(new drawing.Circle(circle, style));
                        } else {
                            var line = new Path(style);
                            for (var angleIx = 0; angleIx < angles.length; angleIx++) {
                                line.lineTo(circle.pointAt(angles[angleIx] + 180));
                            }
                            line.close();
                            container.append(line);
                        }
                    }
                }
                return container.children;
            },
            getValue: function (point) {
                var lineBox = this.lineBox();
                var altAxis = this.plotArea.polarAxis;
                var majorAngles = altAxis.majorAngles();
                var center = altAxis.box.center();
                var radius = point.distanceTo(center);
                var distance = radius;
                if (this.options.majorGridLines.type !== ARC && majorAngles.length > 1) {
                    var dx = point.x - center.x;
                    var dy = point.y - center.y;
                    var theta = (deg(Math.atan2(dy, dx)) + 540) % 360;
                    majorAngles.sort(function (a, b) {
                        return angularDistance(a, theta) - angularDistance(b, theta);
                    });
                    var midAngle = angularDistance(majorAngles[0], majorAngles[1]) / 2;
                    var alpha = angularDistance(theta, majorAngles[0]);
                    var gamma = 90 - midAngle;
                    var beta = 180 - alpha - gamma;
                    distance = radius * (Math.sin(rad(beta)) / Math.sin(rad(gamma)));
                }
                return this.axisType().prototype.getValue.call(this, new Point(lineBox.x1, lineBox.y2 - distance));
            }
        };
        function angularDistance(a, b) {
            return 180 - Math.abs(Math.abs(a - b) - 180);
        }
        var RadarNumericAxis = NumericAxis.extend({
            radarMajorGridLinePositions: function () {
                return this.getTickPositions(this.options.majorUnit);
            },
            radarMinorGridLinePositions: function () {
                var options = this.options;
                var minorSkipStep = 0;
                if (options.majorGridLines.visible) {
                    minorSkipStep = options.majorUnit;
                }
                return this.getTickPositions(options.minorUnit, minorSkipStep);
            },
            axisType: function () {
                return NumericAxis;
            }
        });
        deepExtend(RadarNumericAxis.prototype, RadarNumericAxisMixin);
        var RadarLogarithmicAxis = LogarithmicAxis.extend({
            radarMajorGridLinePositions: function () {
                var positions = [];
                this.traverseMajorTicksPositions(function (position) {
                    positions.push(position);
                }, this.options.majorGridLines);
                return positions;
            },
            radarMinorGridLinePositions: function () {
                var positions = [];
                this.traverseMinorTicksPositions(function (position) {
                    positions.push(position);
                }, this.options.minorGridLines);
                return positions;
            },
            axisType: function () {
                return LogarithmicAxis;
            }
        });
        deepExtend(RadarLogarithmicAxis.prototype, RadarNumericAxisMixin);
        var WEIGHT = 0.333;
        var EXTREMUM_ALLOWED_DEVIATION = 0.01;
        var CurveProcessor = Class.extend({
            init: function (closed) {
                this.closed = closed;
            },
            process: function (dataPoints) {
                var this$1 = this;
                var points = dataPoints.slice(0);
                var segments = [];
                var closed = this.closed;
                var length = points.length;
                if (length > 2) {
                    this.removeDuplicates(0, points);
                    length = points.length;
                }
                if (length < 2 || length === 2 && points[0].equals(points[1])) {
                    return segments;
                }
                var p0 = points[0];
                var p1 = points[1];
                var p2 = points[2];
                segments.push(new Segment(p0));
                while (p0.equals(points[length - 1])) {
                    closed = true;
                    points.pop();
                    length--;
                }
                if (length === 2) {
                    var tangent = this.tangent(p0, p1, X, Y);
                    last(segments).controlOut(this.firstControlPoint(tangent, p0, p1, X, Y));
                    segments.push(new Segment(p1, this.secondControlPoint(tangent, p0, p1, X, Y)));
                    return segments;
                }
                var initialControlPoint, lastControlPoint;
                if (closed) {
                    p0 = points[length - 1];
                    p1 = points[0];
                    p2 = points[1];
                    var controlPoints = this.controlPoints(p0, p1, p2);
                    initialControlPoint = controlPoints[1];
                    lastControlPoint = controlPoints[0];
                } else {
                    var tangent$1 = this.tangent(p0, p1, X, Y);
                    initialControlPoint = this.firstControlPoint(tangent$1, p0, p1, X, Y);
                }
                var cp0 = initialControlPoint;
                for (var idx = 0; idx <= length - 3; idx++) {
                    this$1.removeDuplicates(idx, points);
                    length = points.length;
                    if (idx + 3 <= length) {
                        p0 = points[idx];
                        p1 = points[idx + 1];
                        p2 = points[idx + 2];
                        var controlPoints$1 = this$1.controlPoints(p0, p1, p2);
                        last(segments).controlOut(cp0);
                        cp0 = controlPoints$1[1];
                        var cp1 = controlPoints$1[0];
                        segments.push(new Segment(p1, cp1));
                    }
                }
                if (closed) {
                    p0 = points[length - 2];
                    p1 = points[length - 1];
                    p2 = points[0];
                    var controlPoints$2 = this.controlPoints(p0, p1, p2);
                    last(segments).controlOut(cp0);
                    segments.push(new Segment(p1, controlPoints$2[0]));
                    last(segments).controlOut(controlPoints$2[1]);
                    segments.push(new Segment(p2, lastControlPoint));
                } else {
                    var tangent$2 = this.tangent(p1, p2, X, Y);
                    last(segments).controlOut(cp0);
                    segments.push(new Segment(p2, this.secondControlPoint(tangent$2, p1, p2, X, Y)));
                }
                return segments;
            },
            removeDuplicates: function (idx, points) {
                while (points[idx + 1] && (points[idx].equals(points[idx + 1]) || points[idx + 1].equals(points[idx + 2]))) {
                    points.splice(idx + 1, 1);
                }
            },
            invertAxis: function (p0, p1, p2) {
                var invertAxis = false;
                if (p0.x === p1.x) {
                    invertAxis = true;
                } else if (p1.x === p2.x) {
                    if (p1.y < p2.y && p0.y <= p1.y || p2.y < p1.y && p1.y <= p0.y) {
                        invertAxis = true;
                    }
                } else {
                    var fn = this.lineFunction(p0, p1);
                    var y2 = this.calculateFunction(fn, p2.x);
                    if (!(p0.y <= p1.y && p2.y <= y2) && !(p1.y <= p0.y && p2.y >= y2)) {
                        invertAxis = true;
                    }
                }
                return invertAxis;
            },
            isLine: function (p0, p1, p2) {
                var fn = this.lineFunction(p0, p1);
                var y2 = this.calculateFunction(fn, p2.x);
                return p0.x === p1.x && p1.x === p2.x || round(y2, 1) === round(p2.y, 1);
            },
            lineFunction: function (p1, p2) {
                var a = (p2.y - p1.y) / (p2.x - p1.x);
                var b = p1.y - a * p1.x;
                return [
                    b,
                    a
                ];
            },
            controlPoints: function (p0, p1, p2) {
                var xField = X;
                var yField = Y;
                var restrict = false;
                var switchOrientation = false;
                var tangent;
                if (this.isLine(p0, p1, p2)) {
                    tangent = this.tangent(p0, p1, X, Y);
                } else {
                    var monotonic = {
                        x: this.isMonotonicByField(p0, p1, p2, X),
                        y: this.isMonotonicByField(p0, p1, p2, Y)
                    };
                    if (monotonic.x && monotonic.y) {
                        tangent = this.tangent(p0, p2, X, Y);
                        restrict = true;
                    } else {
                        if (this.invertAxis(p0, p1, p2)) {
                            xField = Y;
                            yField = X;
                        }
                        if (monotonic[xField]) {
                            tangent = 0;
                        } else {
                            var sign;
                            if (p2[yField] < p0[yField] && p0[yField] <= p1[yField] || p0[yField] < p2[yField] && p1[yField] <= p0[yField]) {
                                sign = numberSign((p2[yField] - p0[yField]) * (p1[xField] - p0[xField]));
                            } else {
                                sign = -numberSign((p2[xField] - p0[xField]) * (p1[yField] - p0[yField]));
                            }
                            tangent = EXTREMUM_ALLOWED_DEVIATION * sign;
                            switchOrientation = true;
                        }
                    }
                }
                var secondControlPoint = this.secondControlPoint(tangent, p0, p1, xField, yField);
                if (switchOrientation) {
                    var oldXField = xField;
                    xField = yField;
                    yField = oldXField;
                }
                var firstControlPoint = this.firstControlPoint(tangent, p1, p2, xField, yField);
                if (restrict) {
                    this.restrictControlPoint(p0, p1, secondControlPoint, tangent);
                    this.restrictControlPoint(p1, p2, firstControlPoint, tangent);
                }
                return [
                    secondControlPoint,
                    firstControlPoint
                ];
            },
            restrictControlPoint: function (p1, p2, cp, tangent) {
                if (p1.y < p2.y) {
                    if (p2.y < cp.y) {
                        cp.x = p1.x + (p2.y - p1.y) / tangent;
                        cp.y = p2.y;
                    } else if (cp.y < p1.y) {
                        cp.x = p2.x - (p2.y - p1.y) / tangent;
                        cp.y = p1.y;
                    }
                } else {
                    if (cp.y < p2.y) {
                        cp.x = p1.x - (p1.y - p2.y) / tangent;
                        cp.y = p2.y;
                    } else if (p1.y < cp.y) {
                        cp.x = p2.x + (p1.y - p2.y) / tangent;
                        cp.y = p1.y;
                    }
                }
            },
            tangent: function (p0, p1, xField, yField) {
                var x = p1[xField] - p0[xField];
                var y = p1[yField] - p0[yField];
                var tangent;
                if (x === 0) {
                    tangent = 0;
                } else {
                    tangent = y / x;
                }
                return tangent;
            },
            isMonotonicByField: function (p0, p1, p2, field) {
                return p2[field] > p1[field] && p1[field] > p0[field] || p2[field] < p1[field] && p1[field] < p0[field];
            },
            firstControlPoint: function (tangent, p0, p3, xField, yField) {
                var t1 = p0[xField];
                var t2 = p3[xField];
                var distance = (t2 - t1) * WEIGHT;
                return this.point(t1 + distance, p0[yField] + distance * tangent, xField, yField);
            },
            secondControlPoint: function (tangent, p0, p3, xField, yField) {
                var t1 = p0[xField];
                var t2 = p3[xField];
                var distance = (t2 - t1) * WEIGHT;
                return this.point(t2 - distance, p3[yField] - distance * tangent, xField, yField);
            },
            point: function (xValue, yValue, xField, yField) {
                var controlPoint = new geometry.Point();
                controlPoint[xField] = xValue;
                controlPoint[yField] = yValue;
                return controlPoint;
            },
            calculateFunction: function (fn, x) {
                var length = fn.length;
                var result = 0;
                for (var i = 0; i < length; i++) {
                    result += Math.pow(x, i) * fn[i];
                }
                return result;
            }
        });
        function numberSign(value) {
            return value <= 0 ? -1 : 1;
        }
        dataviz.Gradients = GRADIENTS;
        kendo.deepExtend(kendo.dataviz, {
            constants: constants,
            services: services,
            autoMajorUnit: autoMajorUnit,
            Point: Point,
            Box: Box,
            Ring: Ring,
            Sector: Sector,
            ShapeBuilder: ShapeBuilder,
            ShapeElement: ShapeElement,
            ChartElement: ChartElement,
            BoxElement: BoxElement,
            RootElement: RootElement,
            FloatElement: FloatElement,
            Text: Text,
            TextBox: TextBox,
            Title: Title,
            AxisLabel: AxisLabel,
            Axis: Axis,
            Note: Note,
            CategoryAxis: CategoryAxis,
            DateCategoryAxis: DateCategoryAxis,
            DateValueAxis: DateValueAxis,
            NumericAxis: NumericAxis,
            LogarithmicAxis: LogarithmicAxis,
            PolarAxis: PolarAxis,
            RadarCategoryAxis: RadarCategoryAxis,
            RadarNumericAxis: RadarNumericAxis,
            RadarLogarithmicAxis: RadarLogarithmicAxis,
            CurveProcessor: CurveProcessor,
            rectToBox: rectToBox,
            addClass: addClass,
            removeClass: removeClass,
            alignPathToPixel: alignPathToPixel,
            clockwise: clockwise,
            deepExtend: deepExtend,
            elementStyles: elementStyles,
            getSpacing: getSpacing,
            getter: __common_getter_js,
            grep: grep,
            hasClasses: hasClasses,
            inArray: inArray,
            interpolateValue: interpolateValue,
            InstanceObserver: InstanceObserver,
            isArray: isArray,
            isFunction: isFunction,
            isNumber: isNumber,
            isObject: isObject,
            isString: isString,
            map: map,
            mousewheelDelta: mousewheelDelta,
            FontLoader: FontLoader,
            setDefaultOptions: setDefaultOptions,
            sparseArrayLimits: sparseArrayLimits,
            styleValue: styleValue,
            append: append,
            bindEvents: bindEvents,
            Class: Class,
            defined: defined,
            deg: deg,
            elementOffset: elementOffset,
            elementSize: elementSize,
            eventElement: eventElement,
            eventCoordinates: eventCoordinates,
            last: last,
            limitValue: limitValue,
            logToConsole: kendo.logToConsole,
            objectKey: objectKey,
            rad: rad,
            round: round,
            unbindEvents: unbindEvents,
            valueOrDefault: valueOrDefault,
            absoluteDateDiff: absoluteDateDiff,
            addDuration: addDuration,
            addTicks: addTicks,
            ceilDate: ceilDate,
            dateComparer: dateComparer,
            dateDiff: dateDiff,
            dateEquals: dateEquals,
            dateIndex: dateIndex,
            duration: duration,
            floorDate: floorDate,
            lteDateIndex: lteDateIndex,
            startOfWeek: startOfWeek,
            toDate: toDate,
            parseDate: parseDate,
            parseDates: parseDates,
            toTime: toTime
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/core/core', ['dataviz/core/kendo-core'], f);
}(function () {
    (function ($) {
        var dataviz = kendo.dataviz;
        var services = dataviz.services;
        var draw = kendo.drawing;
        dataviz.ExportMixin = {
            extend: function (proto, skipLegacy) {
                if (!proto.exportVisual) {
                    throw new Error('Mixin target has no exportVisual method defined.');
                }
                proto.exportSVG = this.exportSVG;
                proto.exportImage = this.exportImage;
                proto.exportPDF = this.exportPDF;
                if (!skipLegacy) {
                    proto.svg = this.svg;
                    proto.imageDataURL = this.imageDataURL;
                }
            },
            exportSVG: function (options) {
                return draw.exportSVG(this.exportVisual(), options);
            },
            exportImage: function (options) {
                return draw.exportImage(this.exportVisual(options), options);
            },
            exportPDF: function (options) {
                return draw.exportPDF(this.exportVisual(), options);
            },
            svg: function () {
                if (draw.svg.Surface) {
                    return draw.svg.exportGroup(this.exportVisual());
                } else {
                    throw new Error('SVG Export failed. Unable to export instantiate kendo.drawing.svg.Surface');
                }
            },
            imageDataURL: function () {
                if (!kendo.support.canvas) {
                    return null;
                }
                if (draw.canvas.Surface) {
                    var container = $('<div />').css({
                        display: 'none',
                        width: this.element.width(),
                        height: this.element.height()
                    }).appendTo(document.body);
                    var surface = new draw.canvas.Surface(container[0]);
                    surface.draw(this.exportVisual());
                    var image = surface._rootElement.toDataURL();
                    surface.destroy();
                    container.remove();
                    return image;
                } else {
                    throw new Error('Image Export failed. Unable to export instantiate kendo.drawing.canvas.Surface');
                }
            }
        };
        services.IntlService.register({
            format: function (format) {
                return kendo.format.apply(null, [format].concat(Array.prototype.slice.call(arguments, 1)));
            },
            toString: kendo.toString,
            parseDate: kendo.parseDate
        });
        services.TemplateService.register({ compile: kendo.template });
        dataviz.Point2D = dataviz.Point;
        dataviz.Box2D = dataviz.Box;
        dataviz.mwDelta = function (e) {
            return dataviz.mousewheelDelta(e.originalEvent);
        };
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.core', [
        'dataviz/core/kendo-core',
        'dataviz/core/core'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.core',
        name: 'Core',
        description: 'The DataViz core functions',
        category: 'dataviz',
        depends: [
            'core',
            'drawing'
        ],
        hidden: true
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/themes/chart-base-theme', ['kendo.dataviz.core'], f);
}(function () {
    (function () {
        window.kendo.dataviz = window.kendo.dataviz || {};
        var BAR_GAP = 1.5;
        var BAR_SPACING = 0.4;
        var BLACK = '#000';
        var SANS = 'Arial, Helvetica, sans-serif';
        var SANS11 = '11px ' + SANS;
        var SANS12 = '12px ' + SANS;
        var SANS16 = '16px ' + SANS;
        var TRANSPARENT = 'transparent';
        var WHITE = '#fff';
        var notes = function () {
            return {
                icon: { border: { width: 1 } },
                label: {
                    font: SANS12,
                    padding: 3
                },
                line: {
                    length: 10,
                    width: 2
                },
                visible: true
            };
        };
        var axisDefaults = function () {
            return {
                labels: { font: SANS12 },
                notes: notes(),
                title: {
                    font: SANS16,
                    margin: 5
                }
            };
        };
        var areaSeries = function () {
            return {
                highlight: { markers: { border: {} } },
                line: {
                    opacity: 1,
                    width: 0
                },
                markers: {
                    size: 6,
                    visible: false
                },
                opacity: 0.4
            };
        };
        var barSeries = function () {
            return {
                gap: BAR_GAP,
                spacing: BAR_SPACING
            };
        };
        var boxPlotSeries = function () {
            return {
                outliersField: '',
                meanField: '',
                border: {
                    _brightness: 0.8,
                    width: 1
                },
                downColor: WHITE,
                gap: 1,
                highlight: {
                    border: {
                        opacity: 1,
                        width: 2
                    },
                    whiskers: { width: 3 },
                    mean: { width: 2 },
                    median: { width: 2 }
                },
                mean: { width: 2 },
                median: { width: 2 },
                spacing: 0.3,
                whiskers: { width: 2 }
            };
        };
        var bubbleSeries = function () {
            return {
                border: { width: 0 },
                labels: { background: TRANSPARENT },
                opacity: 0.6
            };
        };
        var bulletSeries = function () {
            return {
                gap: BAR_GAP,
                spacing: BAR_SPACING,
                target: { color: '#ff0000' }
            };
        };
        var candlestickSeries = function () {
            return {
                border: {
                    _brightness: 0.8,
                    width: 1
                },
                downColor: WHITE,
                gap: 1,
                highlight: {
                    border: {
                        opacity: 1,
                        width: 2
                    },
                    line: { width: 2 }
                },
                line: {
                    color: BLACK,
                    width: 1
                },
                spacing: 0.3
            };
        };
        var columnSeries = function () {
            return {
                gap: BAR_GAP,
                spacing: BAR_SPACING
            };
        };
        var donutSeries = function () {
            return { margin: 1 };
        };
        var lineSeries = function () {
            return { width: 2 };
        };
        var ohlcSeries = function () {
            return {
                gap: 1,
                highlight: {
                    line: {
                        opacity: 1,
                        width: 3
                    }
                },
                line: { width: 1 },
                spacing: 0.3
            };
        };
        var radarAreaSeries = function () {
            return {
                line: {
                    opacity: 1,
                    width: 0
                },
                markers: {
                    size: 6,
                    visible: false
                },
                opacity: 0.5
            };
        };
        var radarLineSeries = function () {
            return {
                markers: { visible: false },
                width: 2
            };
        };
        var rangeBarSeries = function () {
            return {
                gap: BAR_GAP,
                spacing: BAR_SPACING
            };
        };
        var rangeColumnSeries = function () {
            return {
                gap: BAR_GAP,
                spacing: BAR_SPACING
            };
        };
        var scatterLineSeries = function () {
            return { width: 1 };
        };
        var waterfallSeries = function () {
            return {
                gap: 0.5,
                line: {
                    color: BLACK,
                    width: 1
                },
                spacing: BAR_SPACING
            };
        };
        var pieSeries = function () {
            return {
                labels: {
                    background: '',
                    color: '',
                    padding: {
                        top: 5,
                        bottom: 5,
                        left: 7,
                        right: 7
                    }
                }
            };
        };
        var funnelSeries = function () {
            return {
                labels: {
                    background: '',
                    color: '',
                    padding: {
                        top: 5,
                        bottom: 5,
                        left: 7,
                        right: 7
                    }
                }
            };
        };
        var seriesDefaults = function (options) {
            return {
                visible: true,
                labels: { font: SANS11 },
                overlay: options.gradients ? {} : { gradient: 'none' },
                area: areaSeries(),
                bar: barSeries(),
                boxPlot: boxPlotSeries(),
                bubble: bubbleSeries(),
                bullet: bulletSeries(),
                candlestick: candlestickSeries(),
                column: columnSeries(),
                pie: pieSeries(),
                donut: donutSeries(),
                funnel: funnelSeries(),
                horizontalWaterfall: waterfallSeries(),
                line: lineSeries(),
                notes: notes(),
                ohlc: ohlcSeries(),
                radarArea: radarAreaSeries(),
                radarLine: radarLineSeries(),
                polarArea: radarAreaSeries(),
                polarLine: radarLineSeries(),
                rangeBar: rangeBarSeries(),
                rangeColumn: rangeColumnSeries(),
                scatterLine: scatterLineSeries(),
                verticalArea: areaSeries(),
                verticalBoxPlot: boxPlotSeries(),
                verticalBullet: bulletSeries(),
                verticalLine: lineSeries(),
                waterfall: waterfallSeries()
            };
        };
        var title = function () {
            return { font: SANS16 };
        };
        var legend = function () {
            return { labels: { font: SANS12 } };
        };
        var baseTheme = function (options) {
            if (options === void 0) {
                options = {};
            }
            return {
                axisDefaults: axisDefaults(),
                categoryAxis: { majorGridLines: { visible: true } },
                navigator: {
                    pane: {
                        height: 90,
                        margin: { top: 10 }
                    }
                },
                seriesDefaults: seriesDefaults(options),
                title: title(),
                legend: legend()
            };
        };
        kendo.deepExtend(kendo.dataviz, { chartBaseTheme: baseTheme });
    }());
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/themes/auto-theme', ['kendo.dataviz.core'], f);
}(function () {
    var cache;
    function autoTheme(force) {
        if (!force && cache) {
            return cache;
        }
        var theme = { chart: kendo.dataviz.chartBaseTheme() };
        var hook = $('<div style="display: none">' + '  <div class="k-var--accent"></div>' + '  <div class="k-var--base"></div>' + '  <div class="k-var--background"></div>' + '  <div class="k-var--normal-background"></div>' + '  <div class="k-var--normal-text-color"></div>' + '  <div class="k-var--hover-background"></div>' + '  <div class="k-var--hover-text-color"></div>' + '  <div class="k-var--selected-background"></div>' + '  <div class="k-var--selected-text-color"></div>' + '  <div class="k-var--chart-error-bars-background"></div>' + '  <div class="k-var--chart-notes-background"></div>' + '  <div class="k-var--chart-notes-border"></div>' + '  <div class="k-var--chart-notes-lines"></div>' + '  <div class="k-var--chart-crosshair-background"></div>' + '  <div class="k-var--chart-inactive"></div>' + '  <div class="k-var--chart-major-lines"></div>' + '  <div class="k-var--chart-minor-lines"></div>' + '  <div class="k-var--chart-area-opacity"></div>' + '  <div class="k-widget">' + '      <div class="k-var--chart-font"></div>' + '      <div class="k-var--chart-title-font"></div>' + '      <div class="k-var--chart-label-font"></div>' + '  </div>' + '  <div class="k-var--series">' + '    <div class="k-var--series-a"></div>' + '    <div class="k-var--series-b"></div>' + '    <div class="k-var--series-c"></div>' + '    <div class="k-var--series-d"></div>' + '    <div class="k-var--series-e"></div>' + '    <div class="k-var--series-f"></div>' + '  </div>' + '</div>').appendTo(document.body);
        function mapColor(key, varName) {
            set(key, queryStyle(varName, 'backgroundColor'));
        }
        function queryStyle(varName, prop) {
            return hook.find('.k-var--' + varName).css(prop);
        }
        function set(path, value) {
            var store = theme;
            var parts = path.split('.');
            var key = parts.shift();
            while (parts.length > 0) {
                store = store[key] = store[key] || {};
                key = parts.shift();
            }
            store[key] = value;
        }
        (function setColors() {
            mapColor('chart.axisDefaults.crosshair.color', 'chart-crosshair-background');
            mapColor('chart.axisDefaults.labels.color', 'normal-text-color');
            mapColor('chart.axisDefaults.line.color', 'chart-major-lines');
            mapColor('chart.axisDefaults.majorGridLines.color', 'chart-major-lines');
            mapColor('chart.axisDefaults.minorGridLines.color', 'chart-minor-lines');
            mapColor('chart.axisDefaults.notes.icon.background', 'chart-notes-background');
            mapColor('chart.axisDefaults.notes.icon.border.color', 'chart-notes-border');
            mapColor('chart.axisDefaults.notes.line.color', 'chart-notes-lines');
            mapColor('chart.axisDefaults.title.color', 'normal-text-color');
            mapColor('chart.chartArea.background', 'background');
            mapColor('chart.legend.inactiveItems.labels.color', 'chart-inactive');
            mapColor('chart.legend.inactiveItems.markers.color', 'chart-inactive');
            mapColor('chart.legend.labels.color', 'normal-text-color');
            mapColor('chart.seriesDefaults.boxPlot.downColor', 'chart-major-lines');
            mapColor('chart.seriesDefaults.boxPlot.mean.color', 'base');
            mapColor('chart.seriesDefaults.boxPlot.median.color', 'base');
            mapColor('chart.seriesDefaults.boxPlot.whiskers.color', 'accent');
            mapColor('chart.seriesDefaults.bullet.target.color', 'accent');
            mapColor('chart.seriesDefaults.candlestick.downColor', 'normal-text-color');
            mapColor('chart.seriesDefaults.candlestick.line.color', 'normal-text-color');
            mapColor('chart.seriesDefaults.errorBars.color', 'chart-error-bars-background');
            mapColor('chart.seriesDefaults.horizontalWaterfall.line.color', 'chart-major-lines');
            mapColor('chart.seriesDefaults.icon.border.color', 'chart-major-lines');
            mapColor('chart.seriesDefaults.labels.background', 'background');
            mapColor('chart.seriesDefaults.labels.color', 'normal-text-color');
            mapColor('chart.seriesDefaults.notes.icon.background', 'chart-notes-background');
            mapColor('chart.seriesDefaults.notes.icon.border.color', 'chart-notes-border');
            mapColor('chart.seriesDefaults.notes.line.color', 'chart-notes-lines');
            mapColor('chart.seriesDefaults.verticalBoxPlot.downColor', 'chart-major-lines');
            mapColor('chart.seriesDefaults.verticalBoxPlot.mean.color', 'base');
            mapColor('chart.seriesDefaults.verticalBoxPlot.median.color', 'base');
            mapColor('chart.seriesDefaults.verticalBoxPlot.whiskers.color', 'accent');
            mapColor('chart.seriesDefaults.verticalBullet.target.color', 'accent');
            mapColor('chart.seriesDefaults.waterfall.line.color', 'chart-major-lines');
            mapColor('chart.title.color', 'normal-text-color');
            set('chart.seriesDefaults.labels.opacity', queryStyle('chart-area-opacity', 'opacity'));
        }());
        (function setFonts() {
            function font(varName) {
                return queryStyle(varName, 'fontSize') + ' ' + queryStyle(varName, 'fontFamily');
            }
            var defaultFont = font('chart-font');
            var titleFont = font('chart-title-font');
            var labelFont = font('chart-label-font');
            set('chart.axisDefaults.labels.font', labelFont);
            set('chart.axisDefaults.notes.label.font', defaultFont);
            set('chart.axisDefaults.title.font', defaultFont);
            set('chart.legend.labels.font', defaultFont);
            set('chart.seriesDefaults.labels.font', labelFont);
            set('chart.seriesDefaults.notes.label.font', defaultFont);
            set('chart.title.font', titleFont);
        }());
        (function setSeriesColors() {
            function letterPos(letter) {
                return letter.toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0);
            }
            function seriesPos(name) {
                return letterPos(name.match(/series-([a-z])$/)[1]);
            }
            var series = $('.k-var--series div').toArray();
            var seriesColors = series.reduce(function (arr, el) {
                var pos = seriesPos(el.className);
                arr[pos] = $(el).css('backgroundColor');
                return arr;
            }, []);
            set('chart.seriesColors', seriesColors);
        }());
        hook.remove();
        cache = theme;
        return theme;
    }
    kendo.dataviz.autoTheme = autoTheme;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/themes/themes', ['dataviz/themes/chart-base-theme'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo, ui = kendo.dataviz.ui, deepExtend = kendo.deepExtend;
        var BLACK = '#000', SANS = 'Arial,Helvetica,sans-serif', SANS12 = '12px ' + SANS, WHITE = '#fff';
        var chartBaseTheme = kendo.dataviz.chartBaseTheme({ gradients: true });
        var gaugeBaseTheme = { scale: { labels: { font: SANS12 } } };
        var diagramBaseTheme = {
            shapeDefaults: {
                hover: { opacity: 0.2 },
                stroke: { width: 0 }
            },
            editable: {
                resize: {
                    handles: {
                        width: 7,
                        height: 7
                    }
                }
            },
            selectable: {
                stroke: {
                    width: 1,
                    dashType: 'dot'
                }
            },
            connectionDefaults: {
                stroke: { width: 2 },
                selection: {
                    handles: {
                        width: 8,
                        height: 8
                    }
                },
                editable: {
                    tools: [
                        'edit',
                        'delete'
                    ]
                }
            }
        };
        var themes = ui.themes, registerTheme = ui.registerTheme = function (themeName, options) {
                var result = {};
                result.chart = deepExtend({}, chartBaseTheme, options.chart);
                result.gauge = deepExtend({}, gaugeBaseTheme, options.gauge);
                result.diagram = deepExtend({}, diagramBaseTheme, options.diagram);
                result.treeMap = deepExtend({}, options.treeMap);
                var defaults = result.chart.seriesDefaults;
                defaults.verticalLine = deepExtend({}, defaults.line);
                defaults.verticalArea = deepExtend({}, defaults.area);
                defaults.verticalBoxPlot = deepExtend({}, defaults.boxPlot);
                defaults.polarArea = deepExtend({}, defaults.radarArea);
                defaults.polarLine = deepExtend({}, defaults.radarLine);
                themes[themeName] = result;
            };
        registerTheme('black', {
            chart: {
                title: { color: WHITE },
                legend: {
                    labels: { color: WHITE },
                    inactiveItems: {
                        labels: { color: '#919191' },
                        markers: { color: '#919191' }
                    }
                },
                seriesDefaults: {
                    labels: { color: WHITE },
                    errorBars: { color: WHITE },
                    notes: {
                        icon: {
                            background: '#3b3b3b',
                            border: { color: '#8e8e8e' }
                        },
                        label: { color: WHITE },
                        line: { color: '#8e8e8e' }
                    },
                    pie: { overlay: { gradient: 'sharpBevel' } },
                    donut: { overlay: { gradient: 'sharpGlass' } },
                    line: { markers: { background: '#3d3d3d' } },
                    scatter: { markers: { background: '#3d3d3d' } },
                    scatterLine: { markers: { background: '#3d3d3d' } },
                    waterfall: { line: { color: '#8e8e8e' } },
                    horizontalWaterfall: { line: { color: '#8e8e8e' } },
                    candlestick: {
                        downColor: '#555',
                        line: { color: WHITE },
                        border: {
                            _brightness: 1.5,
                            opacity: 1
                        },
                        highlight: {
                            border: {
                                color: WHITE,
                                opacity: 0.2
                            }
                        }
                    },
                    ohlc: { line: { color: WHITE } }
                },
                chartArea: { background: '#3d3d3d' },
                seriesColors: [
                    '#0081da',
                    '#3aafff',
                    '#99c900',
                    '#ffeb3d',
                    '#b20753',
                    '#ff4195'
                ],
                axisDefaults: {
                    line: { color: '#8e8e8e' },
                    labels: { color: WHITE },
                    majorGridLines: { color: '#545454' },
                    minorGridLines: { color: '#454545' },
                    title: { color: WHITE },
                    crosshair: { color: '#8e8e8e' },
                    notes: {
                        icon: {
                            background: '#3b3b3b',
                            border: { color: '#8e8e8e' }
                        },
                        label: { color: WHITE },
                        line: { color: '#8e8e8e' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#0070e4' },
                scale: {
                    rangePlaceholderColor: '#1d1d1d',
                    labels: { color: WHITE },
                    minorTicks: { color: WHITE },
                    majorTicks: { color: WHITE },
                    line: { color: WHITE }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#0066cc' },
                    connectorDefaults: {
                        fill: { color: WHITE },
                        stroke: { color: '#384049' },
                        hover: {
                            fill: { color: '#3d3d3d' },
                            stroke: { color: '#efefef' }
                        }
                    },
                    content: { color: WHITE }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: '#3d3d3d' },
                            stroke: { color: WHITE },
                            hover: {
                                fill: { color: WHITE },
                                stroke: { color: WHITE }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: WHITE },
                            fill: { color: WHITE }
                        }
                    }
                },
                selectable: { stroke: { color: WHITE } },
                connectionDefaults: {
                    stroke: { color: WHITE },
                    content: { color: WHITE },
                    selection: {
                        handles: {
                            fill: { color: '#3d3d3d' },
                            stroke: { color: '#efefef' }
                        }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#0081da',
                        '#314b5c'
                    ],
                    [
                        '#3aafff',
                        '#3c5464'
                    ],
                    [
                        '#99c900',
                        '#4f5931'
                    ],
                    [
                        '#ffeb3d',
                        '#64603d'
                    ],
                    [
                        '#b20753',
                        '#543241'
                    ],
                    [
                        '#ff4195',
                        '#643e4f'
                    ]
                ]
            }
        });
        registerTheme('blueopal', {
            chart: {
                title: { color: '#293135' },
                legend: {
                    labels: { color: '#293135' },
                    inactiveItems: {
                        labels: { color: '#27A5BA' },
                        markers: { color: '#27A5BA' }
                    }
                },
                seriesDefaults: {
                    labels: {
                        color: BLACK,
                        background: WHITE,
                        opacity: 0.5
                    },
                    errorBars: { color: '#293135' },
                    candlestick: {
                        downColor: '#c4d0d5',
                        line: { color: '#9aabb2' }
                    },
                    waterfall: { line: { color: '#9aabb2' } },
                    horizontalWaterfall: { line: { color: '#9aabb2' } },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#9aabb2' }
                        },
                        label: { color: '#293135' },
                        line: { color: '#9aabb2' }
                    }
                },
                seriesColors: [
                    '#0069a5',
                    '#0098ee',
                    '#7bd2f6',
                    '#ffb800',
                    '#ff8517',
                    '#e34a00'
                ],
                axisDefaults: {
                    line: { color: '#9aabb2' },
                    labels: { color: '#293135' },
                    majorGridLines: { color: '#c4d0d5' },
                    minorGridLines: { color: '#edf1f2' },
                    title: { color: '#293135' },
                    crosshair: { color: '#9aabb2' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#9aabb2' }
                        },
                        label: { color: '#293135' },
                        line: { color: '#9aabb2' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#005c83' },
                scale: {
                    rangePlaceholderColor: '#daecf4',
                    labels: { color: '#293135' },
                    minorTicks: { color: '#293135' },
                    majorTicks: { color: '#293135' },
                    line: { color: '#293135' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#7ec6e3' },
                    connectorDefaults: {
                        fill: { color: '#003f59' },
                        stroke: { color: WHITE },
                        hover: {
                            fill: { color: WHITE },
                            stroke: { color: '#003f59' }
                        }
                    },
                    content: { color: '#293135' }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#003f59' },
                            hover: {
                                fill: { color: '#003f59' },
                                stroke: { color: '#003f59' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: '#003f59' },
                            fill: { color: '#003f59' }
                        }
                    }
                },
                selectable: { stroke: { color: '#003f59' } },
                connectionDefaults: {
                    stroke: { color: '#003f59' },
                    content: { color: '#293135' },
                    selection: {
                        handles: {
                            fill: { color: '#3d3d3d' },
                            stroke: { color: '#efefef' }
                        }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#0069a5',
                        '#bad7e7'
                    ],
                    [
                        '#0098ee',
                        '#b9e0f5'
                    ],
                    [
                        '#7bd2f6',
                        '#ceeaf6'
                    ],
                    [
                        '#ffb800',
                        '#e6e3c4'
                    ],
                    [
                        '#ff8517',
                        '#e4d8c8'
                    ],
                    [
                        '#e34a00',
                        '#ddccc2'
                    ]
                ]
            }
        });
        registerTheme('highcontrast', {
            chart: {
                title: { color: '#ffffff' },
                legend: {
                    labels: { color: '#ffffff' },
                    inactiveItems: {
                        labels: { color: '#66465B' },
                        markers: { color: '#66465B' }
                    }
                },
                seriesDefaults: {
                    labels: { color: '#ffffff' },
                    errorBars: { color: '#ffffff' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#ffffff' }
                        },
                        label: { color: '#ffffff' },
                        line: { color: '#ffffff' }
                    },
                    pie: { overlay: { gradient: 'sharpGlass' } },
                    donut: { overlay: { gradient: 'sharpGlass' } },
                    line: { markers: { background: '#2c232b' } },
                    scatter: { markers: { background: '#2c232b' } },
                    scatterLine: { markers: { background: '#2c232b' } },
                    area: { opacity: 0.5 },
                    waterfall: { line: { color: '#ffffff' } },
                    horizontalWaterfall: { line: { color: '#ffffff' } },
                    candlestick: {
                        downColor: '#664e62',
                        line: { color: '#ffffff' },
                        border: {
                            _brightness: 1.5,
                            opacity: 1
                        },
                        highlight: {
                            border: {
                                color: '#ffffff',
                                opacity: 1
                            }
                        }
                    },
                    ohlc: { line: { color: '#ffffff' } }
                },
                chartArea: { background: '#2c232b' },
                seriesColors: [
                    '#a7008f',
                    '#ffb800',
                    '#3aafff',
                    '#99c900',
                    '#b20753',
                    '#ff4195'
                ],
                axisDefaults: {
                    line: { color: '#ffffff' },
                    labels: { color: '#ffffff' },
                    majorGridLines: { color: '#664e62' },
                    minorGridLines: { color: '#4f394b' },
                    title: { color: '#ffffff' },
                    crosshair: { color: '#ffffff' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#ffffff' }
                        },
                        label: { color: '#ffffff' },
                        line: { color: '#ffffff' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#a7008f' },
                scale: {
                    rangePlaceholderColor: '#2c232b',
                    labels: { color: '#ffffff' },
                    minorTicks: { color: '#2c232b' },
                    majorTicks: { color: '#664e62' },
                    line: { color: '#ffffff' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#a7018f' },
                    connectorDefaults: {
                        fill: { color: WHITE },
                        stroke: { color: '#2c232b' },
                        hover: {
                            fill: { color: '#2c232b' },
                            stroke: { color: WHITE }
                        }
                    },
                    content: { color: WHITE }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: '#2c232b' },
                            stroke: { color: WHITE },
                            hover: {
                                fill: { color: WHITE },
                                stroke: { color: WHITE }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: WHITE },
                            fill: { color: WHITE }
                        }
                    }
                },
                selectable: { stroke: { color: WHITE } },
                connectionDefaults: {
                    stroke: { color: WHITE },
                    content: { color: WHITE },
                    selection: {
                        handles: {
                            fill: { color: '#2c232b' },
                            stroke: { color: WHITE }
                        }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#a7008f',
                        '#451c3f'
                    ],
                    [
                        '#ffb800',
                        '#564122'
                    ],
                    [
                        '#3aafff',
                        '#2f3f55'
                    ],
                    [
                        '#99c900',
                        '#424422'
                    ],
                    [
                        '#b20753',
                        '#471d33'
                    ],
                    [
                        '#ff4195',
                        '#562940'
                    ]
                ]
            }
        });
        registerTheme('default', {
            chart: {
                title: { color: '#8e8e8e' },
                legend: {
                    labels: { color: '#232323' },
                    inactiveItems: {
                        labels: { color: '#919191' },
                        markers: { color: '#919191' }
                    }
                },
                seriesDefaults: {
                    labels: {
                        color: BLACK,
                        background: WHITE,
                        opacity: 0.5
                    },
                    errorBars: { color: '#232323' },
                    candlestick: {
                        downColor: '#dedede',
                        line: { color: '#8d8d8d' }
                    },
                    waterfall: { line: { color: '#8e8e8e' } },
                    horizontalWaterfall: { line: { color: '#8e8e8e' } },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#8e8e8e' }
                        },
                        label: { color: '#232323' },
                        line: { color: '#8e8e8e' }
                    }
                },
                seriesColors: [
                    '#ff6800',
                    '#a0a700',
                    '#ff8d00',
                    '#678900',
                    '#ffb53c',
                    '#396000'
                ],
                axisDefaults: {
                    line: { color: '#8e8e8e' },
                    labels: { color: '#232323' },
                    minorGridLines: { color: '#f0f0f0' },
                    majorGridLines: { color: '#dfdfdf' },
                    title: { color: '#232323' },
                    crosshair: { color: '#8e8e8e' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#8e8e8e' }
                        },
                        label: { color: '#232323' },
                        line: { color: '#8e8e8e' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#ea7001' },
                scale: {
                    rangePlaceholderColor: '#dedede',
                    labels: { color: '#2e2e2e' },
                    minorTicks: { color: '#2e2e2e' },
                    majorTicks: { color: '#2e2e2e' },
                    line: { color: '#2e2e2e' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#e15613' },
                    connectorDefaults: {
                        fill: { color: '#282828' },
                        stroke: { color: WHITE },
                        hover: {
                            fill: { color: WHITE },
                            stroke: { color: '#282828' }
                        }
                    },
                    content: { color: '#2e2e2e' }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#282828' },
                            hover: {
                                fill: { color: '#282828' },
                                stroke: { color: '#282828' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: '#282828' },
                            fill: { color: '#282828' }
                        }
                    }
                },
                selectable: { stroke: { color: '#a7018f' } },
                connectionDefaults: {
                    stroke: { color: '#282828' },
                    content: { color: '#2e2e2e' },
                    selection: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#282828' }
                        }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#ff6800',
                        '#edcfba'
                    ],
                    [
                        '#a0a700',
                        '#dadcba'
                    ],
                    [
                        '#ff8d00',
                        '#edd7ba'
                    ],
                    [
                        '#678900',
                        '#cfd6ba'
                    ],
                    [
                        '#ffb53c',
                        '#eddfc6'
                    ],
                    [
                        '#396000',
                        '#c6ceba'
                    ]
                ]
            }
        });
        registerTheme('silver', {
            chart: {
                title: { color: '#4e5968' },
                legend: {
                    labels: { color: '#4e5968' },
                    inactiveItems: {
                        labels: { color: '#B1BCC8' },
                        markers: { color: '#B1BCC8' }
                    }
                },
                seriesDefaults: {
                    labels: {
                        color: '#293135',
                        background: '#eaeaec',
                        opacity: 0.5
                    },
                    errorBars: { color: '#4e5968' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#4e5968' }
                        },
                        label: { color: '#4e5968' },
                        line: { color: '#4e5968' }
                    },
                    line: { markers: { background: '#eaeaec' } },
                    scatter: { markers: { background: '#eaeaec' } },
                    scatterLine: { markers: { background: '#eaeaec' } },
                    pie: { connectors: { color: '#A6B1C0' } },
                    donut: { connectors: { color: '#A6B1C0' } },
                    waterfall: { line: { color: '#a6b1c0' } },
                    horizontalWaterfall: { line: { color: '#a6b1c0' } },
                    candlestick: { downColor: '#a6afbe' }
                },
                chartArea: { background: '#eaeaec' },
                seriesColors: [
                    '#007bc3',
                    '#76b800',
                    '#ffae00',
                    '#ef4c00',
                    '#a419b7',
                    '#430B62'
                ],
                axisDefaults: {
                    line: { color: '#a6b1c0' },
                    labels: { color: '#4e5968' },
                    majorGridLines: { color: '#dcdcdf' },
                    minorGridLines: { color: '#eeeeef' },
                    title: { color: '#4e5968' },
                    crosshair: { color: '#a6b1c0' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#4e5968' }
                        },
                        label: { color: '#4e5968' },
                        line: { color: '#4e5968' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#0879c0' },
                scale: {
                    rangePlaceholderColor: '#f3f3f4',
                    labels: { color: '#515967' },
                    minorTicks: { color: '#515967' },
                    majorTicks: { color: '#515967' },
                    line: { color: '#515967' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#1c82c2' },
                    connectorDefaults: {
                        fill: { color: '#515967' },
                        stroke: { color: WHITE },
                        hover: {
                            fill: { color: WHITE },
                            stroke: { color: '#282828' }
                        }
                    },
                    content: { color: '#515967' }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#515967' },
                            hover: {
                                fill: { color: '#515967' },
                                stroke: { color: '#515967' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: '#515967' },
                            fill: { color: '#515967' }
                        }
                    }
                },
                selectable: { stroke: { color: '#515967' } },
                connectionDefaults: {
                    stroke: { color: '#515967' },
                    content: { color: '#515967' },
                    selection: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#515967' }
                        }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#007bc3',
                        '#c2dbea'
                    ],
                    [
                        '#76b800',
                        '#dae7c3'
                    ],
                    [
                        '#ffae00',
                        '#f5e5c3'
                    ],
                    [
                        '#ef4c00',
                        '#f2d2c3'
                    ],
                    [
                        '#a419b7',
                        '#e3c7e8'
                    ],
                    [
                        '#430b62',
                        '#d0c5d7'
                    ]
                ]
            }
        });
        registerTheme('metro', {
            chart: {
                title: { color: '#777777' },
                legend: {
                    labels: { color: '#777777' },
                    inactiveItems: {
                        labels: { color: '#CBCBCB' },
                        markers: { color: '#CBCBCB' }
                    }
                },
                seriesDefaults: {
                    labels: { color: BLACK },
                    errorBars: { color: '#777777' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#777777' }
                        },
                        label: { color: '#777777' },
                        line: { color: '#777777' }
                    },
                    candlestick: {
                        downColor: '#c7c7c7',
                        line: { color: '#787878' }
                    },
                    waterfall: { line: { color: '#c7c7c7' } },
                    horizontalWaterfall: { line: { color: '#c7c7c7' } },
                    overlay: { gradient: 'none' },
                    border: { _brightness: 1 }
                },
                seriesColors: [
                    '#8ebc00',
                    '#309b46',
                    '#25a0da',
                    '#ff6900',
                    '#e61e26',
                    '#d8e404',
                    '#16aba9',
                    '#7e51a1',
                    '#313131',
                    '#ed1691'
                ],
                axisDefaults: {
                    line: { color: '#c7c7c7' },
                    labels: { color: '#777777' },
                    minorGridLines: { color: '#c7c7c7' },
                    majorGridLines: { color: '#c7c7c7' },
                    title: { color: '#777777' },
                    crosshair: { color: '#c7c7c7' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#777777' }
                        },
                        label: { color: '#777777' },
                        line: { color: '#777777' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#8ebc00' },
                scale: {
                    rangePlaceholderColor: '#e6e6e6',
                    labels: { color: '#777' },
                    minorTicks: { color: '#777' },
                    majorTicks: { color: '#777' },
                    line: { color: '#777' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#8ebc00' },
                    connectorDefaults: {
                        fill: { color: BLACK },
                        stroke: { color: WHITE },
                        hover: {
                            fill: { color: WHITE },
                            stroke: { color: BLACK }
                        }
                    },
                    content: { color: '#777' }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#787878' },
                            hover: {
                                fill: { color: '#787878' },
                                stroke: { color: '#787878' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: '#787878' },
                            fill: { color: '#787878' }
                        }
                    }
                },
                selectable: { stroke: { color: '#515967' } },
                connectionDefaults: {
                    stroke: { color: '#787878' },
                    content: { color: '#777' },
                    selection: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#787878' }
                        }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#8ebc00',
                        '#e8f2cc'
                    ],
                    [
                        '#309b46',
                        '#d6ebda'
                    ],
                    [
                        '#25a0da',
                        '#d3ecf8'
                    ],
                    [
                        '#ff6900',
                        '#ffe1cc'
                    ],
                    [
                        '#e61e26',
                        '#fad2d4'
                    ],
                    [
                        '#d8e404',
                        '#f7facd'
                    ],
                    [
                        '#16aba9',
                        '#d0eeee'
                    ],
                    [
                        '#7e51a1',
                        '#e5dcec'
                    ],
                    [
                        '#313131',
                        '#d6d6d6'
                    ],
                    [
                        '#ed1691',
                        '#fbd0e9'
                    ]
                ]
            }
        });
        registerTheme('metroblack', {
            chart: {
                title: { color: '#ffffff' },
                legend: {
                    labels: { color: '#ffffff' },
                    inactiveItems: {
                        labels: { color: '#797979' },
                        markers: { color: '#797979' }
                    }
                },
                seriesDefaults: {
                    border: { _brightness: 1 },
                    labels: { color: '#ffffff' },
                    errorBars: { color: '#ffffff' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#cecece' }
                        },
                        label: { color: '#ffffff' },
                        line: { color: '#cecece' }
                    },
                    line: { markers: { background: '#0e0e0e' } },
                    bubble: { opacity: 0.6 },
                    scatter: { markers: { background: '#0e0e0e' } },
                    scatterLine: { markers: { background: '#0e0e0e' } },
                    candlestick: {
                        downColor: '#828282',
                        line: { color: '#ffffff' }
                    },
                    waterfall: { line: { color: '#cecece' } },
                    horizontalWaterfall: { line: { color: '#cecece' } },
                    overlay: { gradient: 'none' }
                },
                chartArea: { background: '#0e0e0e' },
                seriesColors: [
                    '#00aba9',
                    '#309b46',
                    '#8ebc00',
                    '#ff6900',
                    '#e61e26',
                    '#d8e404',
                    '#25a0da',
                    '#7e51a1',
                    '#313131',
                    '#ed1691'
                ],
                axisDefaults: {
                    line: { color: '#cecece' },
                    labels: { color: '#ffffff' },
                    minorGridLines: { color: '#2d2d2d' },
                    majorGridLines: { color: '#333333' },
                    title: { color: '#ffffff' },
                    crosshair: { color: '#cecece' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#cecece' }
                        },
                        label: { color: '#ffffff' },
                        line: { color: '#cecece' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#00aba9' },
                scale: {
                    rangePlaceholderColor: '#2d2d2d',
                    labels: { color: '#ffffff' },
                    minorTicks: { color: '#333333' },
                    majorTicks: { color: '#cecece' },
                    line: { color: '#cecece' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#00aba9' },
                    connectorDefaults: {
                        fill: { color: WHITE },
                        stroke: { color: '#0e0e0e' },
                        hover: {
                            fill: { color: '#0e0e0e' },
                            stroke: { color: WHITE }
                        }
                    },
                    content: { color: WHITE }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: '#0e0e0e' },
                            stroke: { color: '#787878' },
                            hover: {
                                fill: { color: '#787878' },
                                stroke: { color: '#787878' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: WHITE },
                            fill: { color: WHITE }
                        }
                    }
                },
                selectable: { stroke: { color: '#787878' } },
                connectionDefaults: {
                    stroke: { color: WHITE },
                    content: { color: WHITE },
                    selection: {
                        handles: {
                            fill: { color: '#0e0e0e' },
                            stroke: { color: WHITE }
                        }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#00aba9',
                        '#0b2d2d'
                    ],
                    [
                        '#309b46',
                        '#152a19'
                    ],
                    [
                        '#8ebc00',
                        '#28310b'
                    ],
                    [
                        '#ff6900',
                        '#3e200b'
                    ],
                    [
                        '#e61e26',
                        '#391113'
                    ],
                    [
                        '#d8e404',
                        '#36390c'
                    ],
                    [
                        '#25a0da',
                        '#132b37'
                    ],
                    [
                        '#7e51a1',
                        '#241b2b'
                    ],
                    [
                        '#313131',
                        '#151515'
                    ],
                    [
                        '#ed1691',
                        '#3b1028'
                    ]
                ]
            }
        });
        registerTheme('moonlight', {
            chart: {
                title: { color: '#ffffff' },
                legend: {
                    labels: { color: '#ffffff' },
                    inactiveItems: {
                        labels: { color: '#A1A7AB' },
                        markers: { color: '#A1A7AB' }
                    }
                },
                seriesDefaults: {
                    labels: { color: '#ffffff' },
                    errorBars: { color: '#ffffff' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#8c909e' }
                        },
                        label: { color: '#ffffff' },
                        line: { color: '#8c909e' }
                    },
                    pie: { overlay: { gradient: 'sharpBevel' } },
                    donut: { overlay: { gradient: 'sharpGlass' } },
                    line: { markers: { background: '#212a33' } },
                    bubble: { opacity: 0.6 },
                    scatter: { markers: { background: '#212a33' } },
                    scatterLine: { markers: { background: '#212a33' } },
                    area: { opacity: 0.3 },
                    candlestick: {
                        downColor: '#757d87',
                        line: { color: '#ea9d06' },
                        border: {
                            _brightness: 1.5,
                            opacity: 1
                        },
                        highlight: {
                            border: {
                                color: WHITE,
                                opacity: 0.2
                            }
                        }
                    },
                    waterfall: { line: { color: '#8c909e' } },
                    horizontalWaterfall: { line: { color: '#8c909e' } },
                    ohlc: { line: { color: '#ea9d06' } }
                },
                chartArea: { background: '#212a33' },
                seriesColors: [
                    '#ffca08',
                    '#ff710f',
                    '#ed2e24',
                    '#ff9f03',
                    '#e13c02',
                    '#a00201'
                ],
                axisDefaults: {
                    line: { color: '#8c909e' },
                    minorTicks: { color: '#8c909e' },
                    majorTicks: { color: '#8c909e' },
                    labels: { color: '#ffffff' },
                    majorGridLines: { color: '#3e424d' },
                    minorGridLines: { color: '#2f3640' },
                    title: { color: '#ffffff' },
                    crosshair: { color: '#8c909e' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#8c909e' }
                        },
                        label: { color: '#ffffff' },
                        line: { color: '#8c909e' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#f4af03' },
                scale: {
                    rangePlaceholderColor: '#2f3640',
                    labels: { color: WHITE },
                    minorTicks: { color: '#8c909e' },
                    majorTicks: { color: '#8c909e' },
                    line: { color: '#8c909e' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#f3ae03' },
                    connectorDefaults: {
                        fill: { color: WHITE },
                        stroke: { color: '#414550' },
                        hover: {
                            fill: { color: '#414550' },
                            stroke: { color: WHITE }
                        }
                    },
                    content: { color: WHITE }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: '#414550' },
                            stroke: { color: WHITE },
                            hover: {
                                fill: { color: WHITE },
                                stroke: { color: WHITE }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: WHITE },
                            fill: { color: WHITE }
                        }
                    }
                },
                selectable: { stroke: { color: WHITE } },
                connectionDefaults: {
                    stroke: { color: WHITE },
                    content: { color: WHITE },
                    selection: {
                        handles: {
                            fill: { color: '#414550' },
                            stroke: { color: WHITE }
                        }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#ffca08',
                        '#4e4b2b'
                    ],
                    [
                        '#ff710f',
                        '#4e392d'
                    ],
                    [
                        '#ed2e24',
                        '#4b2c31'
                    ],
                    [
                        '#ff9f03',
                        '#4e422a'
                    ],
                    [
                        '#e13c02',
                        '#482e2a'
                    ],
                    [
                        '#a00201',
                        '#3b232a'
                    ]
                ]
            }
        });
        registerTheme('uniform', {
            chart: {
                title: { color: '#686868' },
                legend: {
                    labels: { color: '#686868' },
                    inactiveItems: {
                        labels: { color: '#B6B6B6' },
                        markers: { color: '#B6B6B6' }
                    }
                },
                seriesDefaults: {
                    labels: { color: '#686868' },
                    errorBars: { color: '#686868' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#9e9e9e' }
                        },
                        label: { color: '#686868' },
                        line: { color: '#9e9e9e' }
                    },
                    pie: { overlay: { gradient: 'sharpBevel' } },
                    donut: { overlay: { gradient: 'sharpGlass' } },
                    line: { markers: { background: '#ffffff' } },
                    bubble: { opacity: 0.6 },
                    scatter: { markers: { background: '#ffffff' } },
                    scatterLine: { markers: { background: '#ffffff' } },
                    area: { opacity: 0.3 },
                    candlestick: {
                        downColor: '#cccccc',
                        line: { color: '#cccccc' },
                        border: {
                            _brightness: 1.5,
                            opacity: 1
                        },
                        highlight: {
                            border: {
                                color: '#cccccc',
                                opacity: 0.2
                            }
                        }
                    },
                    waterfall: { line: { color: '#9e9e9e' } },
                    horizontalWaterfall: { line: { color: '#9e9e9e' } },
                    ohlc: { line: { color: '#cccccc' } }
                },
                chartArea: { background: '#ffffff' },
                seriesColors: [
                    '#527aa3',
                    '#6f91b3',
                    '#8ca7c2',
                    '#a8bdd1',
                    '#c5d3e0',
                    '#e2e9f0'
                ],
                axisDefaults: {
                    line: { color: '#9e9e9e' },
                    minorTicks: { color: '#aaaaaa' },
                    majorTicks: { color: '#888888' },
                    labels: { color: '#686868' },
                    majorGridLines: { color: '#dadada' },
                    minorGridLines: { color: '#e7e7e7' },
                    title: { color: '#686868' },
                    crosshair: { color: '#9e9e9e' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#9e9e9e' }
                        },
                        label: { color: '#686868' },
                        line: { color: '#9e9e9e' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#527aa3' },
                scale: {
                    rangePlaceholderColor: '#e7e7e7',
                    labels: { color: '#686868' },
                    minorTicks: { color: '#aaaaaa' },
                    majorTicks: { color: '#888888' },
                    line: { color: '#9e9e9e' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#d1d1d1' },
                    connectorDefaults: {
                        fill: { color: '#686868' },
                        stroke: { color: WHITE },
                        hover: {
                            fill: { color: WHITE },
                            stroke: { color: '#686868' }
                        }
                    },
                    content: { color: '#686868' }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#686868' },
                            hover: {
                                fill: { color: '#686868' },
                                stroke: { color: '#686868' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: '#686868' },
                            fill: { color: '#686868' }
                        }
                    }
                },
                selectable: { stroke: { color: '#686868' } },
                connectionDefaults: {
                    stroke: { color: '#686868' },
                    content: { color: '#686868' },
                    selection: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#686868' }
                        }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#527aa3',
                        '#d0d8e1'
                    ],
                    [
                        '#6f91b3',
                        '#d6dde4'
                    ],
                    [
                        '#8ca7c2',
                        '#dce1e7'
                    ],
                    [
                        '#a8bdd1',
                        '#e2e6ea'
                    ],
                    [
                        '#c5d3e0',
                        '#e7eaed'
                    ],
                    [
                        '#e2e9f0',
                        '#edeff0'
                    ]
                ]
            }
        });
        registerTheme('bootstrap', {
            chart: {
                title: { color: '#333333' },
                legend: {
                    labels: { color: '#333333' },
                    inactiveItems: {
                        labels: { color: '#999999' },
                        markers: { color: '#9A9A9A' }
                    }
                },
                seriesDefaults: {
                    labels: { color: '#333333' },
                    overlay: { gradient: 'none' },
                    errorBars: { color: '#343434' },
                    notes: {
                        icon: {
                            background: '#000000',
                            border: { color: '#000000' }
                        },
                        label: { color: '#333333' },
                        line: { color: '#000000' }
                    },
                    pie: { overlay: { gradient: 'none' } },
                    donut: { overlay: { gradient: 'none' } },
                    line: { markers: { background: '#ffffff' } },
                    bubble: { opacity: 0.6 },
                    scatter: { markers: { background: '#ffffff' } },
                    scatterLine: { markers: { background: '#ffffff' } },
                    area: { opacity: 0.8 },
                    candlestick: {
                        downColor: '#d0d0d0',
                        line: { color: '#333333' },
                        border: {
                            _brightness: 1.5,
                            opacity: 1
                        },
                        highlight: {
                            border: {
                                color: '#b8b8b8',
                                opacity: 0.2
                            }
                        }
                    },
                    waterfall: { line: { color: '#cccccc' } },
                    horizontalWaterfall: { line: { color: '#cccccc' } },
                    ohlc: { line: { color: '#333333' } }
                },
                chartArea: { background: '#ffffff' },
                seriesColors: [
                    '#428bca',
                    '#5bc0de',
                    '#5cb85c',
                    '#f2b661',
                    '#e67d4a',
                    '#da3b36'
                ],
                axisDefaults: {
                    line: { color: '#cccccc' },
                    minorTicks: { color: '#ebebeb' },
                    majorTicks: { color: '#cccccc' },
                    labels: { color: '#333333' },
                    majorGridLines: { color: '#cccccc' },
                    minorGridLines: { color: '#ebebeb' },
                    title: { color: '#333333' },
                    crosshair: { color: '#000000' },
                    notes: {
                        icon: {
                            background: '#000000',
                            border: { color: '#000000' }
                        },
                        label: { color: '#ffffff' },
                        line: { color: '#000000' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#428bca' },
                scale: {
                    rangePlaceholderColor: '#cccccc',
                    labels: { color: '#333333' },
                    minorTicks: { color: '#ebebeb' },
                    majorTicks: { color: '#cccccc' },
                    line: { color: '#cccccc' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#428bca' },
                    connectorDefaults: {
                        fill: { color: '#333333' },
                        stroke: { color: WHITE },
                        hover: {
                            fill: { color: WHITE },
                            stroke: { color: '#333333' }
                        }
                    },
                    content: { color: '#333333' }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#333333' },
                            hover: {
                                fill: { color: '#333333' },
                                stroke: { color: '#333333' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: '#333333' },
                            fill: { color: '#333333' }
                        }
                    }
                },
                selectable: { stroke: { color: '#333333' } },
                connectionDefaults: {
                    stroke: { color: '#c4c4c4' },
                    content: { color: '#333333' },
                    selection: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#333333' }
                        },
                        stroke: { color: '#333333' }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#428bca',
                        '#d1e0ec'
                    ],
                    [
                        '#5bc0de',
                        '#d6eaf0'
                    ],
                    [
                        '#5cb85c',
                        '#d6e9d6'
                    ],
                    [
                        '#5cb85c',
                        '#f4e8d7'
                    ],
                    [
                        '#e67d4a',
                        '#f2ddd3'
                    ],
                    [
                        '#da3b36',
                        '#f0d0cf'
                    ]
                ]
            }
        });
        registerTheme('flat', {
            chart: {
                title: { color: '#4c5356' },
                legend: {
                    labels: { color: '#4c5356' },
                    inactiveItems: {
                        labels: { color: '#CBCBCB' },
                        markers: { color: '#CBCBCB' }
                    }
                },
                seriesDefaults: {
                    labels: { color: '#4c5356' },
                    errorBars: { color: '#4c5356' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#cdcdcd' }
                        },
                        label: { color: '#4c5356' },
                        line: { color: '#cdcdcd' }
                    },
                    candlestick: {
                        downColor: '#c7c7c7',
                        line: { color: '#787878' }
                    },
                    area: { opacity: 0.9 },
                    waterfall: { line: { color: '#cdcdcd' } },
                    horizontalWaterfall: { line: { color: '#cdcdcd' } },
                    overlay: { gradient: 'none' },
                    border: { _brightness: 1 }
                },
                seriesColors: [
                    '#10c4b2',
                    '#ff7663',
                    '#ffb74f',
                    '#a2df53',
                    '#1c9ec4',
                    '#ff63a5',
                    '#1cc47b'
                ],
                axisDefaults: {
                    line: { color: '#cdcdcd' },
                    labels: { color: '#4c5356' },
                    minorGridLines: { color: '#cdcdcd' },
                    majorGridLines: { color: '#cdcdcd' },
                    title: { color: '#4c5356' },
                    crosshair: { color: '#cdcdcd' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#cdcdcd' }
                        },
                        label: { color: '#4c5356' },
                        line: { color: '#cdcdcd' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#10c4b2' },
                scale: {
                    rangePlaceholderColor: '#cdcdcd',
                    labels: { color: '#4c5356' },
                    minorTicks: { color: '#4c5356' },
                    majorTicks: { color: '#4c5356' },
                    line: { color: '#4c5356' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#10c4b2' },
                    connectorDefaults: {
                        fill: { color: '#363940' },
                        stroke: { color: WHITE },
                        hover: {
                            fill: { color: WHITE },
                            stroke: { color: '#363940' }
                        }
                    },
                    content: { color: '#4c5356' }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#363940' },
                            hover: {
                                fill: { color: '#363940' },
                                stroke: { color: '#363940' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: '#363940' },
                            fill: { color: '#363940' }
                        }
                    }
                },
                selectable: { stroke: { color: '#363940' } },
                connectionDefaults: {
                    stroke: { color: '#cdcdcd' },
                    content: { color: '#4c5356' },
                    selection: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#363940' }
                        },
                        stroke: { color: '#363940' }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#10c4b2',
                        '#cff3f0'
                    ],
                    [
                        '#ff7663',
                        '#ffe4e0'
                    ],
                    [
                        '#ffb74f',
                        '#fff1dc'
                    ],
                    [
                        '#a2df53',
                        '#ecf9dd'
                    ],
                    [
                        '#1c9ec4',
                        '#d2ecf3'
                    ],
                    [
                        '#ff63a5',
                        '#ffe0ed'
                    ],
                    [
                        '#1cc47b',
                        '#d2f3e5'
                    ]
                ]
            }
        });
        registerTheme('material', {
            chart: {
                title: { color: '#444444' },
                legend: {
                    labels: { color: '#444444' },
                    inactiveItems: {
                        labels: { color: '#CBCBCB' },
                        markers: { color: '#CBCBCB' }
                    }
                },
                seriesDefaults: {
                    labels: { color: '#444444' },
                    errorBars: { color: '#444444' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#e5e5e5' }
                        },
                        label: { color: '#444444' },
                        line: { color: '#e5e5e5' }
                    },
                    candlestick: {
                        downColor: '#c7c7c7',
                        line: { color: '#787878' }
                    },
                    area: { opacity: 0.9 },
                    waterfall: { line: { color: '#e5e5e5' } },
                    horizontalWaterfall: { line: { color: '#e5e5e5' } },
                    overlay: { gradient: 'none' },
                    border: { _brightness: 1 }
                },
                seriesColors: [
                    '#3f51b5',
                    '#03a9f4',
                    '#4caf50',
                    '#f9ce1d',
                    '#ff9800',
                    '#ff5722'
                ],
                axisDefaults: {
                    line: { color: '#e5e5e5' },
                    labels: { color: '#444444' },
                    minorGridLines: { color: '#e5e5e5' },
                    majorGridLines: { color: '#e5e5e5' },
                    title: { color: '#444444' },
                    crosshair: { color: '#7f7f7f' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#e5e5e5' }
                        },
                        label: { color: '#444444' },
                        line: { color: '#e5e5e5' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#3f51b5' },
                scale: {
                    rangePlaceholderColor: '#e5e5e5',
                    labels: { color: '#444444' },
                    minorTicks: { color: '#444444' },
                    majorTicks: { color: '#444444' },
                    line: { color: '#444444' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#3f51b5' },
                    connectorDefaults: {
                        fill: { color: '#7f7f7f' },
                        stroke: { color: WHITE },
                        hover: {
                            fill: { color: WHITE },
                            stroke: { color: '#7f7f7f' }
                        }
                    },
                    content: { color: '#444444' }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#444444' },
                            hover: {
                                fill: { color: '#444444' },
                                stroke: { color: '#444444' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: '#444444' },
                            fill: { color: '#444444' }
                        }
                    }
                },
                selectable: { stroke: { color: '#444444' } },
                connectionDefaults: {
                    stroke: { color: '#7f7f7f' },
                    content: { color: '#444444' },
                    selection: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#444444' }
                        },
                        stroke: { color: '#444444' }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#3f51b5',
                        '#cff3f0'
                    ],
                    [
                        '#03a9f4',
                        '#e5f6fe'
                    ],
                    [
                        '#4caf50',
                        '#edf7ed'
                    ],
                    [
                        '#f9ce1d',
                        '#fefae8'
                    ],
                    [
                        '#ff9800',
                        '#fff4e5'
                    ],
                    [
                        '#ff5722',
                        '#ffeee8'
                    ]
                ]
            }
        });
        registerTheme('materialblack', {
            chart: {
                title: { color: '#fff' },
                legend: {
                    labels: { color: '#fff' },
                    inactiveItems: {
                        labels: { color: '#CBCBCB' },
                        markers: { color: '#CBCBCB' }
                    }
                },
                seriesDefaults: {
                    labels: { color: '#fff' },
                    errorBars: { color: '#fff' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#e5e5e5' }
                        },
                        label: { color: '#fff' },
                        line: { color: '#e5e5e5' }
                    },
                    candlestick: {
                        downColor: '#c7c7c7',
                        line: { color: '#787878' }
                    },
                    area: { opacity: 0.9 },
                    waterfall: { line: { color: '#4d4d4d' } },
                    horizontalWaterfall: { line: { color: '#4d4d4d' } },
                    overlay: { gradient: 'none' },
                    border: { _brightness: 1 }
                },
                chartArea: { background: '#1c1c1c' },
                seriesColors: [
                    '#3f51b5',
                    '#03a9f4',
                    '#4caf50',
                    '#f9ce1d',
                    '#ff9800',
                    '#ff5722'
                ],
                axisDefaults: {
                    line: { color: '#4d4d4d' },
                    labels: { color: '#fff' },
                    minorGridLines: { color: '#4d4d4d' },
                    majorGridLines: { color: '#4d4d4d' },
                    title: { color: '#fff' },
                    crosshair: { color: '#7f7f7f' },
                    notes: {
                        icon: {
                            background: 'transparent',
                            border: { color: '#4d4d4d' }
                        },
                        label: { color: '#fff' },
                        line: { color: '#4d4d4d' }
                    }
                }
            },
            gauge: {
                pointer: { color: '#3f51b5' },
                scale: {
                    rangePlaceholderColor: '#4d4d4d',
                    labels: { color: '#fff' },
                    minorTicks: { color: '#fff' },
                    majorTicks: { color: '#fff' },
                    line: { color: '#fff' }
                }
            },
            diagram: {
                shapeDefaults: {
                    fill: { color: '#3f51b5' },
                    connectorDefaults: {
                        fill: { color: '#7f7f7f' },
                        stroke: { color: WHITE },
                        hover: {
                            fill: { color: WHITE },
                            stroke: { color: '#7f7f7f' }
                        }
                    },
                    content: { color: '#fff' }
                },
                editable: {
                    resize: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#fff' },
                            hover: {
                                fill: { color: '#fff' },
                                stroke: { color: '#fff' }
                            }
                        }
                    },
                    rotate: {
                        thumb: {
                            stroke: { color: '#fff' },
                            fill: { color: '#fff' }
                        }
                    }
                },
                selectable: { stroke: { color: '#fff' } },
                connectionDefaults: {
                    stroke: { color: '#7f7f7f' },
                    content: { color: '#fff' },
                    selection: {
                        handles: {
                            fill: { color: WHITE },
                            stroke: { color: '#fff' }
                        },
                        stroke: { color: '#fff' }
                    }
                }
            },
            treeMap: {
                colors: [
                    [
                        '#3f51b5',
                        '#cff3f0'
                    ],
                    [
                        '#03a9f4',
                        '#e5f6fe'
                    ],
                    [
                        '#4caf50',
                        '#edf7ed'
                    ],
                    [
                        '#f9ce1d',
                        '#fefae8'
                    ],
                    [
                        '#ff9800',
                        '#fff4e5'
                    ],
                    [
                        '#ff5722',
                        '#ffeee8'
                    ]
                ]
            }
        });
        (function () {
            var TEXT = '#333333';
            var INACTIVE = '#7f7f7f';
            var INACTIVE_SHAPE = '#bdbdbd';
            var AXIS = '#c8c8c8';
            var AXIS_MINOR = '#dddddd';
            var SERIES = [
                '#008fd3',
                '#99d101',
                '#f39b02',
                '#f05662',
                '#c03c53',
                '#acacac'
            ];
            var SERIES_LIGHT = [
                '#cbe8f5',
                '#eaf5cb',
                '#fceacc',
                '#fbdcdf',
                '#f2d7dc',
                '#eeeeee'
            ];
            var PRIMARY = SERIES[0];
            var DIAGRAM_HOVER = WHITE;
            function noteStyle() {
                return {
                    icon: {
                        background: '#007cc0',
                        border: { color: '#007cc0' }
                    },
                    label: { color: '#ffffff' },
                    line: { color: AXIS }
                };
            }
            registerTheme('fiori', {
                chart: {
                    title: { color: TEXT },
                    legend: {
                        labels: { color: TEXT },
                        inactiveItems: {
                            labels: { color: INACTIVE },
                            markers: { color: INACTIVE }
                        }
                    },
                    seriesDefaults: {
                        labels: { color: TEXT },
                        errorBars: { color: TEXT },
                        notes: noteStyle(),
                        candlestick: {
                            downColor: AXIS,
                            line: { color: INACTIVE_SHAPE }
                        },
                        area: { opacity: 0.8 },
                        waterfall: { line: { color: AXIS } },
                        horizontalWaterfall: { line: { color: AXIS } },
                        overlay: { gradient: 'none' },
                        border: { _brightness: 1 }
                    },
                    seriesColors: SERIES,
                    axisDefaults: {
                        line: { color: AXIS },
                        labels: { color: TEXT },
                        minorGridLines: { color: AXIS_MINOR },
                        majorGridLines: { color: AXIS },
                        title: { color: TEXT },
                        crosshair: { color: INACTIVE },
                        notes: noteStyle()
                    }
                },
                gauge: {
                    pointer: { color: PRIMARY },
                    scale: {
                        rangePlaceholderColor: AXIS,
                        labels: { color: TEXT },
                        minorTicks: { color: TEXT },
                        majorTicks: { color: TEXT },
                        line: { color: TEXT }
                    }
                },
                diagram: {
                    shapeDefaults: {
                        fill: { color: PRIMARY },
                        connectorDefaults: {
                            fill: { color: TEXT },
                            stroke: { color: DIAGRAM_HOVER },
                            hover: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: TEXT }
                            }
                        },
                        content: { color: TEXT }
                    },
                    editable: {
                        resize: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE },
                                hover: {
                                    fill: { color: INACTIVE_SHAPE },
                                    stroke: { color: INACTIVE_SHAPE }
                                }
                            }
                        },
                        rotate: {
                            thumb: {
                                stroke: { color: INACTIVE_SHAPE },
                                fill: { color: INACTIVE_SHAPE }
                            }
                        }
                    },
                    selectable: { stroke: { color: INACTIVE_SHAPE } },
                    connectionDefaults: {
                        stroke: { color: INACTIVE_SHAPE },
                        content: { color: INACTIVE_SHAPE },
                        selection: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE }
                            },
                            stroke: { color: INACTIVE_SHAPE }
                        }
                    }
                },
                treeMap: { colors: fuse(SERIES, SERIES_LIGHT) }
            });
        }());
        (function () {
            var TEXT = '#4e4e4e';
            var INACTIVE = '#7f7f7f';
            var INACTIVE_SHAPE = '#bdbdbd';
            var AXIS = '#c8c8c8';
            var AXIS_MINOR = '#e5e5e5';
            var SERIES = [
                '#0072c6',
                '#5db2ff',
                '#008a17',
                '#82ba00',
                '#ff8f32',
                '#ac193d'
            ];
            var SERIES_LIGHT = [
                '#cbe2f3',
                '#deeffe',
                '#cbe7d0',
                '#e5f0cb',
                '#fee8d5',
                '#eed0d7'
            ];
            var PRIMARY = SERIES[0];
            var DIAGRAM_HOVER = WHITE;
            function noteStyle() {
                return {
                    icon: {
                        background: '#00b0ff',
                        border: { color: '#00b0ff' }
                    },
                    label: { color: '#ffffff' },
                    line: { color: AXIS }
                };
            }
            registerTheme('office365', {
                chart: {
                    title: { color: TEXT },
                    legend: {
                        labels: { color: TEXT },
                        inactiveItems: {
                            labels: { color: INACTIVE },
                            markers: { color: INACTIVE }
                        }
                    },
                    seriesDefaults: {
                        labels: { color: TEXT },
                        errorBars: { color: TEXT },
                        notes: noteStyle(),
                        candlestick: {
                            downColor: AXIS,
                            line: { color: INACTIVE_SHAPE }
                        },
                        area: { opacity: 0.8 },
                        waterfall: { line: { color: AXIS } },
                        horizontalWaterfall: { line: { color: AXIS } },
                        overlay: { gradient: 'none' },
                        border: { _brightness: 1 }
                    },
                    seriesColors: SERIES,
                    axisDefaults: {
                        line: { color: AXIS },
                        labels: { color: TEXT },
                        minorGridLines: { color: AXIS_MINOR },
                        majorGridLines: { color: AXIS },
                        title: { color: TEXT },
                        crosshair: { color: INACTIVE },
                        notes: noteStyle()
                    }
                },
                gauge: {
                    pointer: { color: PRIMARY },
                    scale: {
                        rangePlaceholderColor: AXIS,
                        labels: { color: TEXT },
                        minorTicks: { color: TEXT },
                        majorTicks: { color: TEXT },
                        line: { color: TEXT }
                    }
                },
                diagram: {
                    shapeDefaults: {
                        fill: { color: PRIMARY },
                        connectorDefaults: {
                            fill: { color: TEXT },
                            stroke: { color: DIAGRAM_HOVER },
                            hover: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: TEXT }
                            }
                        },
                        content: { color: TEXT }
                    },
                    editable: {
                        resize: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE },
                                hover: {
                                    fill: { color: INACTIVE_SHAPE },
                                    stroke: { color: INACTIVE_SHAPE }
                                }
                            }
                        },
                        rotate: {
                            thumb: {
                                stroke: { color: INACTIVE_SHAPE },
                                fill: { color: INACTIVE_SHAPE }
                            }
                        }
                    },
                    selectable: { stroke: { color: INACTIVE_SHAPE } },
                    connectionDefaults: {
                        stroke: { color: INACTIVE_SHAPE },
                        content: { color: INACTIVE_SHAPE },
                        selection: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE }
                            },
                            stroke: { color: INACTIVE_SHAPE }
                        }
                    }
                },
                treeMap: { colors: fuse(SERIES, SERIES_LIGHT) }
            });
        }());
        (function () {
            var TEXT = '#32364c';
            var INACTIVE = '#7f7f7f';
            var INACTIVE_SHAPE = '#bdbdbd';
            var AXIS = '#dfe0e1';
            var AXIS_MINOR = '#dfe0e1';
            var SERIES = [
                '#ff4350',
                '#ff9ea5',
                '#00acc1',
                '#80deea',
                '#ffbf46',
                '#ffd78c'
            ];
            var SERIES_LIGHT = [
                '#ffd9dc',
                '#ffeced',
                '#cceef3',
                '#e6f8fb',
                '#fff2da',
                '#fff7e8'
            ];
            var PRIMARY = SERIES[0];
            var DIAGRAM_HOVER = WHITE;
            function noteStyle() {
                return {
                    icon: {
                        background: '#007cc0',
                        border: { color: '#007cc0' }
                    },
                    label: { color: '#ffffff' },
                    line: { color: AXIS }
                };
            }
            registerTheme('nova', {
                chart: {
                    title: { color: TEXT },
                    legend: {
                        labels: { color: TEXT },
                        inactiveItems: {
                            labels: { color: INACTIVE },
                            markers: { color: INACTIVE }
                        }
                    },
                    seriesDefaults: {
                        labels: { color: TEXT },
                        errorBars: { color: TEXT },
                        notes: noteStyle(),
                        candlestick: {
                            downColor: AXIS,
                            line: { color: INACTIVE_SHAPE }
                        },
                        area: { opacity: 0.8 },
                        waterfall: { line: { color: AXIS } },
                        horizontalWaterfall: { line: { color: AXIS } },
                        overlay: { gradient: 'none' },
                        border: { _brightness: 1 }
                    },
                    seriesColors: SERIES,
                    axisDefaults: {
                        line: { color: AXIS },
                        labels: { color: TEXT },
                        minorGridLines: { color: AXIS_MINOR },
                        majorGridLines: { color: AXIS },
                        title: { color: TEXT },
                        crosshair: { color: TEXT },
                        notes: noteStyle()
                    }
                },
                gauge: {
                    pointer: { color: PRIMARY },
                    scale: {
                        rangePlaceholderColor: AXIS,
                        labels: { color: TEXT },
                        minorTicks: { color: TEXT },
                        majorTicks: { color: TEXT },
                        line: { color: TEXT }
                    }
                },
                diagram: {
                    shapeDefaults: {
                        fill: { color: PRIMARY },
                        connectorDefaults: {
                            fill: { color: TEXT },
                            stroke: { color: DIAGRAM_HOVER },
                            hover: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: TEXT }
                            }
                        },
                        content: { color: TEXT }
                    },
                    editable: {
                        resize: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE },
                                hover: {
                                    fill: { color: INACTIVE_SHAPE },
                                    stroke: { color: INACTIVE_SHAPE }
                                }
                            }
                        },
                        rotate: {
                            thumb: {
                                stroke: { color: INACTIVE_SHAPE },
                                fill: { color: INACTIVE_SHAPE }
                            }
                        }
                    },
                    selectable: { stroke: { color: INACTIVE_SHAPE } },
                    connectionDefaults: {
                        stroke: { color: INACTIVE_SHAPE },
                        content: { color: INACTIVE_SHAPE },
                        selection: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE }
                            },
                            stroke: { color: INACTIVE_SHAPE }
                        }
                    }
                },
                treeMap: { colors: fuse(SERIES, SERIES_LIGHT) }
            });
        }());
        (function () {
            var TEXT = '#656565';
            var INACTIVE_SHAPE = '#bdbdbd';
            var AXIS = 'rgba(0, 0, 0, .04)';
            var SERIES = [
                '#ff6358',
                '#ffd246',
                '#78d237',
                '#28b4c8',
                '#2d73f5',
                '#aa46be'
            ];
            var SERIES_LIGHT = [
                '#ffd9dc',
                '#ffeced',
                '#cceef3',
                '#e6f8fb',
                '#fff2da',
                '#fff7e8'
            ];
            var PRIMARY = SERIES[0];
            var DIAGRAM_HOVER = WHITE;
            registerTheme('default-v2', {
                chart: {},
                gauge: {
                    pointer: { color: PRIMARY },
                    scale: {
                        rangePlaceholderColor: AXIS,
                        labels: { color: TEXT },
                        minorTicks: { color: TEXT },
                        majorTicks: { color: TEXT },
                        line: { color: TEXT }
                    }
                },
                diagram: {
                    shapeDefaults: {
                        fill: { color: PRIMARY },
                        connectorDefaults: {
                            fill: { color: TEXT },
                            stroke: { color: DIAGRAM_HOVER },
                            hover: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: TEXT }
                            }
                        },
                        content: { color: TEXT }
                    },
                    editable: {
                        resize: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE },
                                hover: {
                                    fill: { color: INACTIVE_SHAPE },
                                    stroke: { color: INACTIVE_SHAPE }
                                }
                            }
                        },
                        rotate: {
                            thumb: {
                                stroke: { color: INACTIVE_SHAPE },
                                fill: { color: INACTIVE_SHAPE }
                            }
                        }
                    },
                    selectable: { stroke: { color: INACTIVE_SHAPE } },
                    connectionDefaults: {
                        stroke: { color: INACTIVE_SHAPE },
                        content: { color: INACTIVE_SHAPE },
                        selection: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE }
                            },
                            stroke: { color: INACTIVE_SHAPE }
                        }
                    }
                },
                treeMap: { colors: fuse(SERIES, SERIES_LIGHT) }
            });
            themes.sass = themes['default-v2'];
        }());
        (function () {
            var TEXT = '#292b2c';
            var INACTIVE_SHAPE = '#bdbdbd';
            var AXIS = 'rgba(0, 0, 0, .04)';
            var SERIES = [
                '#0275d8',
                '#5bc0de',
                '#5cb85c',
                '#f0ad4e',
                '#e67d4a',
                '#d9534f'
            ];
            var SERIES_LIGHT = [
                '#ffd9dc',
                '#ffeced',
                '#cceef3',
                '#e6f8fb',
                '#fff2da',
                '#fff7e8'
            ];
            var PRIMARY = SERIES[0];
            var DIAGRAM_HOVER = WHITE;
            registerTheme('bootstrap-v4', {
                chart: {},
                gauge: {
                    pointer: { color: PRIMARY },
                    scale: {
                        rangePlaceholderColor: AXIS,
                        labels: { color: TEXT },
                        minorTicks: { color: TEXT },
                        majorTicks: { color: TEXT },
                        line: { color: TEXT }
                    }
                },
                diagram: {
                    shapeDefaults: {
                        fill: { color: PRIMARY },
                        connectorDefaults: {
                            fill: { color: TEXT },
                            stroke: { color: DIAGRAM_HOVER },
                            hover: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: TEXT }
                            }
                        },
                        content: { color: TEXT }
                    },
                    editable: {
                        resize: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE },
                                hover: {
                                    fill: { color: INACTIVE_SHAPE },
                                    stroke: { color: INACTIVE_SHAPE }
                                }
                            }
                        },
                        rotate: {
                            thumb: {
                                stroke: { color: INACTIVE_SHAPE },
                                fill: { color: INACTIVE_SHAPE }
                            }
                        }
                    },
                    selectable: { stroke: { color: INACTIVE_SHAPE } },
                    connectionDefaults: {
                        stroke: { color: INACTIVE_SHAPE },
                        content: { color: INACTIVE_SHAPE },
                        selection: {
                            handles: {
                                fill: { color: DIAGRAM_HOVER },
                                stroke: { color: INACTIVE_SHAPE }
                            },
                            stroke: { color: INACTIVE_SHAPE }
                        }
                    }
                },
                treeMap: { colors: fuse(SERIES, SERIES_LIGHT) }
            });
        }());
        function fuse(arr1, arr2) {
            return $.map(arr1, function (item, index) {
                return [[
                        item,
                        arr2[index]
                    ]];
            });
        }
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.themes', [
        'kendo.dataviz.core',
        'dataviz/themes/chart-base-theme',
        'dataviz/themes/auto-theme',
        'dataviz/themes/themes'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.themes',
        name: 'Themes',
        description: 'Built-in themes for the DataViz widgets',
        category: 'dataviz',
        depends: ['dataviz.core'],
        hidden: true
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/chart/kendo-chart', [
        'kendo.core',
        'kendo.color',
        'kendo.drawing',
        'kendo.dataviz.core'
    ], f);
}(function () {
    (function ($) {
        window.kendo.dataviz = window.kendo.dataviz || {};
        var dataviz = kendo.dataviz;
        var Class = dataviz.Class;
        var isNumber = dataviz.isNumber;
        var datavizConstants = dataviz.constants;
        var MAX_VALUE = datavizConstants.MAX_VALUE;
        var MIN_VALUE = datavizConstants.MIN_VALUE;
        var VALUE = datavizConstants.VALUE;
        var CENTER = datavizConstants.CENTER;
        var TOP = datavizConstants.TOP;
        var BOTTOM = datavizConstants.BOTTOM;
        var LEFT = datavizConstants.LEFT;
        var WHITE = datavizConstants.WHITE;
        var CIRCLE = datavizConstants.CIRCLE;
        var Y = datavizConstants.Y;
        var X = datavizConstants.X;
        var RIGHT = datavizConstants.RIGHT;
        var BLACK = datavizConstants.BLACK;
        var DATE = datavizConstants.DATE;
        var DEFAULT_PRECISION = datavizConstants.DEFAULT_PRECISION;
        var ARC = datavizConstants.ARC;
        var defined = dataviz.defined;
        var getter = dataviz.getter;
        var isArray = dataviz.isArray;
        var ChartElement = dataviz.ChartElement;
        var Point = dataviz.Point;
        var Box = dataviz.Box;
        var alignPathToPixel = dataviz.alignPathToPixel;
        var setDefaultOptions = dataviz.setDefaultOptions;
        var inArray = dataviz.inArray;
        var isFunction = dataviz.isFunction;
        var valueOrDefault = dataviz.valueOrDefault;
        var isObject = dataviz.isObject;
        var deepExtend = dataviz.deepExtend;
        var eventElement = dataviz.eventElement;
        var services = dataviz.services;
        var TemplateService = services.TemplateService;
        var TextBox = dataviz.TextBox;
        var ShapeElement = dataviz.ShapeElement;
        var getSpacing = dataviz.getSpacing;
        var limitValue = dataviz.limitValue;
        var last = dataviz.last;
        var append = dataviz.append;
        var isString = dataviz.isString;
        var parseDate = dataviz.parseDate;
        var styleValue = dataviz.styleValue;
        var CategoryAxis = dataviz.CategoryAxis;
        var BoxElement = dataviz.BoxElement;
        var round = dataviz.round;
        var grep = dataviz.grep;
        var DateCategoryAxis = dataviz.DateCategoryAxis;
        var elementStyles = dataviz.elementStyles;
        var hasClasses = dataviz.hasClasses;
        var bindEvents = dataviz.bindEvents;
        var unbindEvents = dataviz.unbindEvents;
        var support = kendo.support;
        var drawing = kendo.drawing;
        var Path = drawing.Path;
        var Animation = drawing.Animation;
        var AnimationFactory = drawing.AnimationFactory;
        var Group = drawing.Group;
        var Color = kendo.Color;
        var geometry = kendo.geometry;
        var GeometryPoint = geometry.Point;
        var transform = geometry.transform;
        var ChartAxis = Class.extend({
            init: function (axis) {
                this._axis = axis;
                this.options = axis.options;
            },
            value: function (point) {
                var axis = this._axis;
                var value = axis.getCategory ? axis.getCategory(point) : axis.getValue(point);
                return value;
            },
            slot: function (from, to, limit) {
                if (limit === void 0) {
                    limit = true;
                }
                return this._axis.slot(from, to, limit);
            },
            range: function () {
                return this._axis.range();
            },
            valueRange: function () {
                return this._axis.valueRange();
            }
        });
        var ChartPlotArea = Class.extend({
            init: function (plotArea) {
                this._plotArea = plotArea;
                this.visual = plotArea.visual;
                this.backgroundVisual = plotArea._bgVisual;
            }
        });
        function countNumbers(values) {
            var length = values.length;
            var count = 0;
            for (var i = 0; i < length; i++) {
                var num = values[i];
                if (isNumber(num)) {
                    count++;
                }
            }
            return count;
        }
        var Aggregates = {
            min: function (values) {
                var length = values.length;
                var min = MAX_VALUE;
                for (var i = 0; i < length; i++) {
                    var value = values[i];
                    if (isNumber(value)) {
                        min = Math.min(min, value);
                    }
                }
                return min === MAX_VALUE ? values[0] : min;
            },
            max: function (values) {
                var length = values.length;
                var max = MIN_VALUE;
                for (var i = 0; i < length; i++) {
                    var value = values[i];
                    if (isNumber(value)) {
                        max = Math.max(max, value);
                    }
                }
                return max === MIN_VALUE ? values[0] : max;
            },
            sum: function (values) {
                var length = values.length;
                var sum = 0;
                for (var i = 0; i < length; i++) {
                    var value = values[i];
                    if (isNumber(value)) {
                        sum += value;
                    }
                }
                return sum;
            },
            sumOrNull: function (values) {
                var result = null;
                if (countNumbers(values)) {
                    result = Aggregates.sum(values);
                }
                return result;
            },
            count: function (values) {
                var length = values.length;
                var count = 0;
                for (var i = 0; i < length; i++) {
                    var value = values[i];
                    if (value !== null && defined(value)) {
                        count++;
                    }
                }
                return count;
            },
            avg: function (values) {
                var count = countNumbers(values);
                var result = values[0];
                if (count > 0) {
                    result = Aggregates.sum(values) / count;
                }
                return result;
            },
            first: function (values) {
                var length = values.length;
                for (var i = 0; i < length; i++) {
                    var value = values[i];
                    if (value !== null && defined(value)) {
                        return value;
                    }
                }
                return values[0];
            }
        };
        function getField(field, row) {
            if (row === null) {
                return row;
            }
            var get = getter(field, true);
            return get(row);
        }
        var SeriesBinder = Class.extend({
            init: function () {
                this._valueFields = {};
                this._otherFields = {};
                this._nullValue = {};
                this._undefinedValue = {};
            },
            register: function (seriesTypes, valueFields, otherFields) {
                var this$1 = this;
                if (valueFields === void 0) {
                    valueFields = [VALUE];
                }
                if (otherFields === void 0) {
                    otherFields = {};
                }
                for (var i = 0; i < seriesTypes.length; i++) {
                    var type = seriesTypes[i];
                    this$1._valueFields[type] = valueFields;
                    this$1._otherFields[type] = otherFields;
                    this$1._nullValue[type] = this$1._makeValue(valueFields, null);
                    this$1._undefinedValue[type] = this$1._makeValue(valueFields, undefined);
                }
            },
            canonicalFields: function (series) {
                return this.valueFields(series).concat(this.otherFields(series));
            },
            valueFields: function (series) {
                return this._valueFields[series.type] || [VALUE];
            },
            otherFields: function (series) {
                return this._otherFields[series.type] || [VALUE];
            },
            bindPoint: function (series, pointIx, item) {
                var data = series.data;
                var pointData = defined(item) ? item : data[pointIx];
                var result = { valueFields: { value: pointData } };
                var valueFields = this.valueFields(series);
                var otherFields = this._otherFields[series.type];
                var fields, value;
                if (pointData === null) {
                    value = this._nullValue[series.type];
                } else if (!defined(pointData)) {
                    value = this._undefinedValue[series.type];
                } else if (Array.isArray(pointData)) {
                    var fieldData = pointData.slice(valueFields.length);
                    value = this._bindFromArray(pointData, valueFields);
                    fields = this._bindFromArray(fieldData, otherFields);
                } else if (typeof pointData === 'object') {
                    var srcValueFields = this.sourceFields(series, valueFields);
                    var srcPointFields = this.sourceFields(series, otherFields);
                    value = this._bindFromObject(pointData, valueFields, srcValueFields);
                    fields = this._bindFromObject(pointData, otherFields, srcPointFields);
                }
                if (defined(value)) {
                    if (valueFields.length === 1) {
                        result.valueFields.value = value[valueFields[0]];
                    } else {
                        result.valueFields = value;
                    }
                }
                result.fields = fields || {};
                return result;
            },
            _makeValue: function (fields, initialValue) {
                var value = {};
                var length = fields.length;
                for (var i = 0; i < length; i++) {
                    var fieldName = fields[i];
                    value[fieldName] = initialValue;
                }
                return value;
            },
            _bindFromArray: function (array, fields) {
                var value = {};
                if (fields) {
                    var length = Math.min(fields.length, array.length);
                    for (var i = 0; i < length; i++) {
                        value[fields[i]] = array[i];
                    }
                }
                return value;
            },
            _bindFromObject: function (object, fields, srcFields) {
                if (srcFields === void 0) {
                    srcFields = fields;
                }
                var value = {};
                if (fields) {
                    var length = fields.length;
                    for (var i = 0; i < length; i++) {
                        var fieldName = fields[i];
                        var srcFieldName = srcFields[i];
                        value[fieldName] = getField(srcFieldName, object);
                    }
                }
                return value;
            },
            sourceFields: function (series, canonicalFields) {
                var sourceFields = [];
                if (canonicalFields) {
                    var length = canonicalFields.length;
                    for (var i = 0; i < length; i++) {
                        var fieldName = canonicalFields[i];
                        var sourceFieldName = fieldName === VALUE ? 'field' : fieldName + 'Field';
                        sourceFields.push(series[sourceFieldName] || fieldName);
                    }
                }
                return sourceFields;
            }
        });
        SeriesBinder.current = new SeriesBinder();
        var STD_ERR = 'stderr';
        var STD_DEV = 'stddev';
        var percentRegex = /percent(?:\w*)\((\d+)\)/;
        var standardDeviationRegex = new RegExp('^' + STD_DEV + '(?:\\((\\d+(?:\\.\\d+)?)\\))?$');
        var ErrorRangeCalculator = Class.extend({
            init: function (errorValue, series, field) {
                this.initGlobalRanges(errorValue, series, field);
            },
            initGlobalRanges: function (errorValue, series, field) {
                var data = series.data;
                var deviationMatch = standardDeviationRegex.exec(errorValue);
                if (deviationMatch) {
                    this.valueGetter = this.createValueGetter(series, field);
                    var average = this.getAverage(data);
                    var deviation = this.getStandardDeviation(data, average, false);
                    var multiple = deviationMatch[1] ? parseFloat(deviationMatch[1]) : 1;
                    var errorRange = {
                        low: average.value - deviation * multiple,
                        high: average.value + deviation * multiple
                    };
                    this.globalRange = function () {
                        return errorRange;
                    };
                } else if (errorValue.indexOf && errorValue.indexOf(STD_ERR) >= 0) {
                    this.valueGetter = this.createValueGetter(series, field);
                    var standardError = this.getStandardError(data, this.getAverage(data));
                    this.globalRange = function (value) {
                        return {
                            low: value - standardError,
                            high: value + standardError
                        };
                    };
                }
            },
            createValueGetter: function (series, field) {
                var data = series.data;
                var binder = SeriesBinder.current;
                var valueFields = binder.valueFields(series);
                var item = defined(data[0]) ? data[0] : {};
                var valueGetter;
                if (isArray(item)) {
                    var index = field ? valueFields.indexOf(field) : 0;
                    valueGetter = getter('[' + index + ']');
                } else if (isNumber(item)) {
                    valueGetter = getter();
                } else if (typeof item === datavizConstants.OBJECT) {
                    var srcValueFields = binder.sourceFields(series, valueFields);
                    valueGetter = getter(srcValueFields[valueFields.indexOf(field)]);
                }
                return valueGetter;
            },
            getErrorRange: function (pointValue, errorValue) {
                var low, high, value;
                if (!defined(errorValue)) {
                    return null;
                }
                if (this.globalRange) {
                    return this.globalRange(pointValue);
                }
                if (isArray(errorValue)) {
                    low = pointValue - errorValue[0];
                    high = pointValue + errorValue[1];
                } else if (isNumber(value = parseFloat(errorValue))) {
                    low = pointValue - value;
                    high = pointValue + value;
                } else if (value = percentRegex.exec(errorValue)) {
                    var percentValue = pointValue * (parseFloat(value[1]) / 100);
                    low = pointValue - Math.abs(percentValue);
                    high = pointValue + Math.abs(percentValue);
                } else {
                    throw new Error('Invalid ErrorBar value: ' + errorValue);
                }
                return {
                    low: low,
                    high: high
                };
            },
            getStandardError: function (data, average) {
                return this.getStandardDeviation(data, average, true) / Math.sqrt(average.count);
            },
            getStandardDeviation: function (data, average, isSample) {
                var this$1 = this;
                var length = data.length;
                var total = isSample ? average.count - 1 : average.count;
                var squareDifferenceSum = 0;
                for (var idx = 0; idx < length; idx++) {
                    var value = this$1.valueGetter(data[idx]);
                    if (isNumber(value)) {
                        squareDifferenceSum += Math.pow(value - average.value, 2);
                    }
                }
                return Math.sqrt(squareDifferenceSum / total);
            },
            getAverage: function (data) {
                var this$1 = this;
                var length = data.length;
                var sum = 0;
                var count = 0;
                for (var idx = 0; idx < length; idx++) {
                    var value = this$1.valueGetter(data[idx]);
                    if (isNumber(value)) {
                        sum += value;
                        count++;
                    }
                }
                return {
                    value: sum / count,
                    count: count
                };
            }
        });
        var browser = support.browser || {};
        var INITIAL_ANIMATION_DURATION = 600;
        var FADEIN = 'fadeIn';
        var GLASS = 'glass';
        var BORDER_BRIGHTNESS = 0.8;
        var TOOLTIP_OFFSET = 5;
        var START_SCALE = browser.msie ? 0.001 : 0;
        var ERROR_LOW_FIELD = 'errorLow';
        var ERROR_HIGH_FIELD = 'errorHigh';
        var X_ERROR_LOW_FIELD = 'xErrorLow';
        var X_ERROR_HIGH_FIELD = 'xErrorHigh';
        var Y_ERROR_LOW_FIELD = 'yErrorLow';
        var Y_ERROR_HIGH_FIELD = 'yErrorHigh';
        var LINE_MARKER_SIZE = 8;
        var ZERO = 'zero';
        var INTERPOLATE = 'interpolate';
        var GAP = 'gap';
        var SMOOTH = 'smooth';
        var STEP = 'step';
        var AREA = 'area';
        var BAR = 'bar';
        var BOX_PLOT = 'boxPlot';
        var BUBBLE = 'bubble';
        var BULLET = 'bullet';
        var CANDLESTICK = 'candlestick';
        var COLUMN = 'column';
        var DONUT = 'donut';
        var FUNNEL = 'funnel';
        var HORIZONTAL_WATERFALL = 'horizontalWaterfall';
        var LINE = 'line';
        var OHLC = 'ohlc';
        var PIE = 'pie';
        var POLAR_AREA = 'polarArea';
        var POLAR_LINE = 'polarLine';
        var POLAR_SCATTER = 'polarScatter';
        var RADAR_AREA = 'radarArea';
        var RADAR_COLUMN = 'radarColumn';
        var RADAR_LINE = 'radarLine';
        var RANGE_BAR = 'rangeBar';
        var RANGE_COLUMN = 'rangeColumn';
        var SCATTER = 'scatter';
        var SCATTER_LINE = 'scatterLine';
        var VERTICAL_AREA = 'verticalArea';
        var VERTICAL_BOX_PLOT = 'verticalBoxPlot';
        var VERTICAL_BULLET = 'verticalBullet';
        var VERTICAL_LINE = 'verticalLine';
        var WATERFALL = 'waterfall';
        var EQUALLY_SPACED_SERIES = [
            BAR,
            COLUMN,
            OHLC,
            CANDLESTICK,
            BOX_PLOT,
            VERTICAL_BOX_PLOT,
            BULLET,
            RANGE_COLUMN,
            RANGE_BAR,
            WATERFALL,
            HORIZONTAL_WATERFALL
        ];
        var LEGEND_ITEM_CLICK = 'legendItemClick';
        var LEGEND_ITEM_HOVER = 'legendItemHover';
        var SERIES_CLICK = 'seriesClick';
        var SERIES_HOVER = 'seriesHover';
        var PLOT_AREA_CLICK = 'plotAreaClick';
        var PLOT_AREA_HOVER = 'plotAreaHover';
        var DRAG = 'drag';
        var DRAG_END = 'dragEnd';
        var DRAG_START = 'dragStart';
        var ZOOM_START = 'zoomStart';
        var ZOOM = 'zoom';
        var ZOOM_END = 'zoomEnd';
        var SELECT_START = 'selectStart';
        var SELECT = 'select';
        var SELECT_END = 'selectEnd';
        var RENDER = 'render';
        var SHOW_TOOLTIP = 'showTooltip';
        var HIDE_TOOLTIP = 'hideTooltip';
        var LOGARITHMIC = 'log';
        var CATEGORY = 'category';
        var INSIDE_END = 'insideEnd';
        var INSIDE_BASE = 'insideBase';
        var OUTSIDE_END = 'outsideEnd';
        var MOUSEWHEEL = 'DOMMouseScroll mousewheel';
        var MOUSEWHEEL_DELAY = 150;
        var constants = {
            INITIAL_ANIMATION_DURATION: INITIAL_ANIMATION_DURATION,
            FADEIN: FADEIN,
            LEGEND_ITEM_CLICK: LEGEND_ITEM_CLICK,
            LEGEND_ITEM_HOVER: LEGEND_ITEM_HOVER,
            SERIES_CLICK: SERIES_CLICK,
            SERIES_HOVER: SERIES_HOVER,
            GLASS: GLASS,
            BORDER_BRIGHTNESS: BORDER_BRIGHTNESS,
            TOOLTIP_OFFSET: TOOLTIP_OFFSET,
            START_SCALE: START_SCALE,
            ERROR_LOW_FIELD: ERROR_LOW_FIELD,
            ERROR_HIGH_FIELD: ERROR_HIGH_FIELD,
            X_ERROR_LOW_FIELD: X_ERROR_LOW_FIELD,
            X_ERROR_HIGH_FIELD: X_ERROR_HIGH_FIELD,
            Y_ERROR_LOW_FIELD: Y_ERROR_LOW_FIELD,
            Y_ERROR_HIGH_FIELD: Y_ERROR_HIGH_FIELD,
            LINE_MARKER_SIZE: LINE_MARKER_SIZE,
            INTERPOLATE: INTERPOLATE,
            ZERO: ZERO,
            SMOOTH: SMOOTH,
            STEP: STEP,
            CATEGORY: CATEGORY,
            FUNNEL: FUNNEL,
            BAR: BAR,
            CANDLESTICK: CANDLESTICK,
            PIE: PIE,
            COLUMN: COLUMN,
            AREA: AREA,
            VERTICAL_BULLET: VERTICAL_BULLET,
            BOX_PLOT: BOX_PLOT,
            OHLC: OHLC,
            WATERFALL: WATERFALL,
            LINE: LINE,
            BULLET: BULLET,
            VERTICAL_LINE: VERTICAL_LINE,
            VERTICAL_AREA: VERTICAL_AREA,
            RANGE_COLUMN: RANGE_COLUMN,
            VERTICAL_BOX_PLOT: VERTICAL_BOX_PLOT,
            RANGE_BAR: RANGE_BAR,
            HORIZONTAL_WATERFALL: HORIZONTAL_WATERFALL,
            SCATTER: SCATTER,
            SCATTER_LINE: SCATTER_LINE,
            BUBBLE: BUBBLE,
            RADAR_AREA: RADAR_AREA,
            RADAR_LINE: RADAR_LINE,
            RADAR_COLUMN: RADAR_COLUMN,
            POLAR_LINE: POLAR_LINE,
            POLAR_AREA: POLAR_AREA,
            POLAR_SCATTER: POLAR_SCATTER,
            RENDER: RENDER,
            PLOT_AREA_CLICK: PLOT_AREA_CLICK,
            PLOT_AREA_HOVER: PLOT_AREA_HOVER,
            LOGARITHMIC: LOGARITHMIC,
            DRAG: DRAG,
            DRAG_START: DRAG_START,
            DRAG_END: DRAG_END,
            ZOOM_START: ZOOM_START,
            ZOOM: ZOOM,
            ZOOM_END: ZOOM_END,
            SELECT_START: SELECT_START,
            SELECT: SELECT,
            SELECT_END: SELECT_END,
            GAP: GAP,
            DONUT: DONUT,
            INSIDE_END: INSIDE_END,
            INSIDE_BASE: INSIDE_BASE,
            OUTSIDE_END: OUTSIDE_END,
            MOUSEWHEEL: MOUSEWHEEL,
            MOUSEWHEEL_DELAY: MOUSEWHEEL_DELAY,
            SHOW_TOOLTIP: SHOW_TOOLTIP,
            HIDE_TOOLTIP: HIDE_TOOLTIP,
            EQUALLY_SPACED_SERIES: EQUALLY_SPACED_SERIES
        };
        var DEFAULT_ERROR_BAR_WIDTH = 4;
        var ErrorBarBase = ChartElement.extend({
            init: function (low, high, isVertical, chart, series, options) {
                ChartElement.fn.init.call(this, options);
                this.low = low;
                this.high = high;
                this.isVertical = isVertical;
                this.chart = chart;
                this.series = series;
            },
            reflow: function (targetBox) {
                var endCaps = this.options.endCaps;
                var isVertical = this.isVertical;
                var axis = this.getAxis();
                var valueBox = axis.getSlot(this.low, this.high);
                var centerBox = targetBox.center();
                var capsWidth = this.getCapsWidth(targetBox, isVertical);
                var capValue = isVertical ? centerBox.x : centerBox.y;
                var capStart = capValue - capsWidth;
                var capEnd = capValue + capsWidth;
                var linePoints;
                if (isVertical) {
                    linePoints = [
                        new Point(centerBox.x, valueBox.y1),
                        new Point(centerBox.x, valueBox.y2)
                    ];
                    if (endCaps) {
                        linePoints.push(new Point(capStart, valueBox.y1), new Point(capEnd, valueBox.y1), new Point(capStart, valueBox.y2), new Point(capEnd, valueBox.y2));
                    }
                    this.box = new Box(capStart, valueBox.y1, capEnd, valueBox.y2);
                } else {
                    linePoints = [
                        new Point(valueBox.x1, centerBox.y),
                        new Point(valueBox.x2, centerBox.y)
                    ];
                    if (endCaps) {
                        linePoints.push(new Point(valueBox.x1, capStart), new Point(valueBox.x1, capEnd), new Point(valueBox.x2, capStart), new Point(valueBox.x2, capEnd));
                    }
                    this.box = new Box(valueBox.x1, capStart, valueBox.x2, capEnd);
                }
                this.linePoints = linePoints;
            },
            getCapsWidth: function (box, isVertical) {
                var boxSize = isVertical ? box.width() : box.height();
                var capsWidth = Math.min(Math.floor(boxSize / 2), DEFAULT_ERROR_BAR_WIDTH) || DEFAULT_ERROR_BAR_WIDTH;
                return capsWidth;
            },
            createVisual: function () {
                var this$1 = this;
                var options = this.options;
                var visual = options.visual;
                if (visual) {
                    this.visual = visual({
                        low: this.low,
                        high: this.high,
                        rect: this.box.toRect(),
                        sender: this.getSender(),
                        options: {
                            endCaps: options.endCaps,
                            color: options.color,
                            line: options.line
                        },
                        createVisual: function () {
                            this$1.createDefaultVisual();
                            var defaultVisual = this$1.visual;
                            delete this$1.visual;
                            return defaultVisual;
                        }
                    });
                } else {
                    this.createDefaultVisual();
                }
            },
            createDefaultVisual: function () {
                var this$1 = this;
                var ref = this;
                var options = ref.options;
                var linePoints = ref.linePoints;
                var lineOptions = {
                    stroke: {
                        color: options.color,
                        width: options.line.width,
                        dashType: options.line.dashType
                    }
                };
                ChartElement.fn.createVisual.call(this);
                for (var idx = 0; idx < linePoints.length; idx += 2) {
                    var line = new Path(lineOptions).moveTo(linePoints[idx].x, linePoints[idx].y).lineTo(linePoints[idx + 1].x, linePoints[idx + 1].y);
                    alignPathToPixel(line);
                    this$1.visual.append(line);
                }
            }
        });
        setDefaultOptions(ErrorBarBase, {
            animation: {
                type: FADEIN,
                delay: INITIAL_ANIMATION_DURATION
            },
            endCaps: true,
            line: { width: 2 },
            zIndex: 1
        });
        var CategoricalErrorBar = ErrorBarBase.extend({
            getAxis: function () {
                var axis = this.chart.seriesValueAxis(this.series);
                return axis;
            }
        });
        var MAX_EXPAND_DEPTH = 5;
        function evalOptions(options, context, state, dryRun) {
            if (state === void 0) {
                state = {};
            }
            if (dryRun === void 0) {
                dryRun = false;
            }
            var defaults = state.defaults = state.defaults || {};
            var depth = state.depth = state.depth || 0;
            var needsEval = false;
            state.excluded = state.excluded || [];
            if (depth > MAX_EXPAND_DEPTH) {
                return null;
            }
            for (var property in options) {
                if (!inArray(property, state.excluded) && options.hasOwnProperty(property)) {
                    var propValue = options[property];
                    if (isFunction(propValue)) {
                        needsEval = true;
                        if (!dryRun) {
                            options[property] = valueOrDefault(propValue(context), defaults[property]);
                        }
                    } else if (isObject(propValue)) {
                        if (!dryRun) {
                            state.defaults = defaults[property];
                        }
                        state.depth++;
                        needsEval = evalOptions(propValue, context, state, dryRun) || needsEval;
                        state.depth--;
                    }
                }
            }
            return needsEval;
        }
        function categoriesCount(series) {
            var seriesCount = series.length;
            var categories = 0;
            for (var i = 0; i < seriesCount; i++) {
                categories = Math.max(categories, series[i].data.length);
            }
            return categories;
        }
        var CategoricalChart = ChartElement.extend({
            init: function (plotArea, options) {
                ChartElement.fn.init.call(this, options);
                this.plotArea = plotArea;
                this.chartService = plotArea.chartService;
                this.categoryAxis = plotArea.seriesCategoryAxis(options.series[0]);
                this.valueAxisRanges = {};
                this.points = [];
                this.categoryPoints = [];
                this.seriesPoints = [];
                this.seriesOptions = [];
                this._evalSeries = [];
                this.render();
            },
            render: function () {
                this.traverseDataPoints(this.addValue.bind(this));
            },
            pointOptions: function (series, seriesIx) {
                var options = this.seriesOptions[seriesIx];
                if (!options) {
                    var defaults = this.pointType().prototype.defaults;
                    this.seriesOptions[seriesIx] = options = deepExtend({}, defaults, { vertical: !this.options.invertAxes }, series);
                }
                return options;
            },
            plotValue: function (point) {
                if (!point) {
                    return 0;
                }
                if (this.options.isStacked100 && isNumber(point.value)) {
                    var categoryIx = point.categoryIx;
                    var categoryPoints = this.categoryPoints[categoryIx];
                    var otherValues = [];
                    var categorySum = 0;
                    for (var i = 0; i < categoryPoints.length; i++) {
                        var other = categoryPoints[i];
                        if (other) {
                            var stack = point.series.stack;
                            var otherStack = other.series.stack;
                            if (stack && otherStack && stack.group !== otherStack.group) {
                                continue;
                            }
                            if (isNumber(other.value)) {
                                categorySum += Math.abs(other.value);
                                otherValues.push(Math.abs(other.value));
                            }
                        }
                    }
                    if (categorySum > 0) {
                        return point.value / categorySum;
                    }
                }
                return point.value;
            },
            plotRange: function (point, startValue) {
                var this$1 = this;
                if (startValue === void 0) {
                    startValue = 0;
                }
                var categoryPoints = this.categoryPoints[point.categoryIx];
                if (this.options.isStacked) {
                    var plotValue = this.plotValue(point);
                    var positive = plotValue >= 0;
                    var prevValue = startValue;
                    var isStackedBar = false;
                    for (var i = 0; i < categoryPoints.length; i++) {
                        var other = categoryPoints[i];
                        if (point === other) {
                            break;
                        }
                        var stack = point.series.stack;
                        var otherStack = other.series.stack;
                        if (stack && otherStack) {
                            if (typeof stack === datavizConstants.STRING && stack !== otherStack) {
                                continue;
                            }
                            if (stack.group && stack.group !== otherStack.group) {
                                continue;
                            }
                        }
                        var otherValue = this$1.plotValue(other);
                        if (otherValue >= 0 && positive || otherValue < 0 && !positive) {
                            prevValue += otherValue;
                            plotValue += otherValue;
                            isStackedBar = true;
                            if (this$1.options.isStacked100) {
                                plotValue = Math.min(plotValue, 1);
                            }
                        }
                    }
                    if (isStackedBar) {
                        prevValue -= startValue;
                    }
                    return [
                        prevValue,
                        plotValue
                    ];
                }
                var series = point.series;
                var valueAxis = this.seriesValueAxis(series);
                var axisCrossingValue = this.categoryAxisCrossingValue(valueAxis);
                return [
                    axisCrossingValue,
                    point.value || axisCrossingValue
                ];
            },
            stackLimits: function (axisName, stackName) {
                var this$1 = this;
                var min = MAX_VALUE;
                var max = MIN_VALUE;
                for (var i = 0; i < this.categoryPoints.length; i++) {
                    var categoryPoints = this$1.categoryPoints[i];
                    if (!categoryPoints) {
                        continue;
                    }
                    for (var pIx = 0; pIx < categoryPoints.length; pIx++) {
                        var point = categoryPoints[pIx];
                        if (point) {
                            if (point.series.stack === stackName || point.series.axis === axisName) {
                                var to = this$1.plotRange(point, 0)[1];
                                if (defined(to) && isFinite(to)) {
                                    max = Math.max(max, to);
                                    min = Math.min(min, to);
                                }
                            }
                        }
                    }
                }
                return {
                    min: min,
                    max: max
                };
            },
            updateStackRange: function () {
                var this$1 = this;
                var ref = this.options;
                var isStacked = ref.isStacked;
                var chartSeries = ref.series;
                var limitsCache = {};
                if (isStacked) {
                    for (var i = 0; i < chartSeries.length; i++) {
                        var series = chartSeries[i];
                        var axisName = series.axis;
                        var key = axisName + series.stack;
                        var limits = limitsCache[key];
                        if (!limits) {
                            limits = this$1.stackLimits(axisName, series.stack);
                            var errorTotals = this$1.errorTotals;
                            if (errorTotals) {
                                if (errorTotals.negative.length) {
                                    limits.min = Math.min(limits.min, dataviz.sparseArrayLimits(errorTotals.negative).min);
                                }
                                if (errorTotals.positive.length) {
                                    limits.max = Math.max(limits.max, dataviz.sparseArrayLimits(errorTotals.positive).max);
                                }
                            }
                            if (limits.min !== MAX_VALUE || limits.max !== MIN_VALUE) {
                                limitsCache[key] = limits;
                            } else {
                                limits = null;
                            }
                        }
                        if (limits) {
                            this$1.valueAxisRanges[axisName] = limits;
                        }
                    }
                }
            },
            addErrorBar: function (point, data, categoryIx) {
                var value = point.value;
                var series = point.series;
                var seriesIx = point.seriesIx;
                var errorBars = point.options.errorBars;
                var lowValue = data.fields[ERROR_LOW_FIELD];
                var highValue = data.fields[ERROR_HIGH_FIELD];
                var errorRange;
                if (isNumber(lowValue) && isNumber(highValue)) {
                    errorRange = {
                        low: lowValue,
                        high: highValue
                    };
                } else if (errorBars && defined(errorBars.value)) {
                    this.seriesErrorRanges = this.seriesErrorRanges || [];
                    this.seriesErrorRanges[seriesIx] = this.seriesErrorRanges[seriesIx] || new ErrorRangeCalculator(errorBars.value, series, VALUE);
                    errorRange = this.seriesErrorRanges[seriesIx].getErrorRange(value, errorBars.value);
                }
                if (errorRange) {
                    point.low = errorRange.low;
                    point.high = errorRange.high;
                    this.addPointErrorBar(point, categoryIx);
                }
            },
            addPointErrorBar: function (point, categoryIx) {
                var isVertical = !this.options.invertAxes;
                var options = point.options.errorBars;
                var series = point.series;
                var low = point.low;
                var high = point.high;
                if (this.options.isStacked) {
                    var stackedErrorRange = this.stackedErrorRange(point, categoryIx);
                    low = stackedErrorRange.low;
                    high = stackedErrorRange.high;
                } else {
                    var fields = {
                        categoryIx: categoryIx,
                        series: series
                    };
                    this.updateRange({ value: low }, fields);
                    this.updateRange({ value: high }, fields);
                }
                var errorBar = new CategoricalErrorBar(low, high, isVertical, this, series, options);
                point.errorBars = [errorBar];
                point.append(errorBar);
            },
            stackedErrorRange: function (point, categoryIx) {
                var plotValue = this.plotRange(point, 0)[1] - point.value;
                var low = point.low + plotValue;
                var high = point.high + plotValue;
                this.errorTotals = this.errorTotals || {
                    positive: [],
                    negative: []
                };
                if (low < 0) {
                    this.errorTotals.negative[categoryIx] = Math.min(this.errorTotals.negative[categoryIx] || 0, low);
                }
                if (high > 0) {
                    this.errorTotals.positive[categoryIx] = Math.max(this.errorTotals.positive[categoryIx] || 0, high);
                }
                return {
                    low: low,
                    high: high
                };
            },
            addValue: function (data, fields) {
                var categoryIx = fields.categoryIx;
                var series = fields.series;
                var seriesIx = fields.seriesIx;
                var categoryPoints = this.categoryPoints[categoryIx];
                if (!categoryPoints) {
                    this.categoryPoints[categoryIx] = categoryPoints = [];
                }
                var seriesPoints = this.seriesPoints[seriesIx];
                if (!seriesPoints) {
                    this.seriesPoints[seriesIx] = seriesPoints = [];
                }
                var point = this.createPoint(data, fields);
                if (point) {
                    $.extend(point, fields);
                    point.owner = this;
                    point.dataItem = series.data[categoryIx];
                    point.noteText = data.fields.noteText;
                    this.addErrorBar(point, data, categoryIx);
                }
                this.points.push(point);
                seriesPoints.push(point);
                categoryPoints.push(point);
                this.updateRange(data.valueFields, fields);
            },
            evalPointOptions: function (options, value, category, categoryIx, series, seriesIx) {
                var state = {
                    defaults: series._defaults,
                    excluded: [
                        'data',
                        'aggregate',
                        '_events',
                        'tooltip',
                        'template',
                        'visual',
                        'toggle',
                        '_outOfRangeMinPoint',
                        '_outOfRangeMaxPoint'
                    ]
                };
                var doEval = this._evalSeries[seriesIx];
                if (!defined(doEval)) {
                    this._evalSeries[seriesIx] = doEval = evalOptions(options, {}, state, true);
                }
                var pointOptions = options;
                if (doEval) {
                    pointOptions = deepExtend({}, pointOptions);
                    evalOptions(pointOptions, {
                        value: value,
                        category: category,
                        index: categoryIx,
                        series: series,
                        dataItem: series.data[categoryIx]
                    }, state);
                }
                return pointOptions;
            },
            updateRange: function (data, fields) {
                var axisName = fields.series.axis;
                var value = data.value;
                var axisRange = this.valueAxisRanges[axisName];
                if (isFinite(value) && value !== null) {
                    axisRange = this.valueAxisRanges[axisName] = axisRange || {
                        min: MAX_VALUE,
                        max: MIN_VALUE
                    };
                    axisRange.min = Math.min(axisRange.min, value);
                    axisRange.max = Math.max(axisRange.max, value);
                }
            },
            seriesValueAxis: function (series) {
                var plotArea = this.plotArea;
                var axisName = series.axis;
                var axis = axisName ? plotArea.namedValueAxes[axisName] : plotArea.valueAxis;
                if (!axis) {
                    throw new Error('Unable to locate value axis with name ' + axisName);
                }
                return axis;
            },
            reflow: function (targetBox) {
                var this$1 = this;
                var categorySlots = this.categorySlots = [];
                var chartPoints = this.points;
                var categoryAxis = this.categoryAxis;
                var pointIx = 0;
                this.traverseDataPoints(function (data, fields) {
                    var categoryIx = fields.categoryIx;
                    var currentSeries = fields.series;
                    var valueAxis = this$1.seriesValueAxis(currentSeries);
                    var point = chartPoints[pointIx++];
                    var categorySlot = categorySlots[categoryIx];
                    if (!categorySlot) {
                        categorySlots[categoryIx] = categorySlot = this$1.categorySlot(categoryAxis, categoryIx, valueAxis);
                    }
                    if (point) {
                        var plotRange = this$1.plotRange(point, valueAxis.startValue());
                        var valueSlot = valueAxis.getSlot(plotRange[0], plotRange[1], !this$1.options.clip);
                        if (valueSlot) {
                            var pointSlot = this$1.pointSlot(categorySlot, valueSlot);
                            point.aboveAxis = this$1.aboveAxis(point, valueAxis);
                            point.stackValue = plotRange[1];
                            if (this$1.options.isStacked100) {
                                point.percentage = this$1.plotValue(point);
                            }
                            this$1.reflowPoint(point, pointSlot);
                        } else {
                            point.visible = false;
                        }
                    }
                });
                this.reflowCategories(categorySlots);
                this.box = targetBox;
            },
            aboveAxis: function (point, valueAxis) {
                var axisCrossingValue = this.categoryAxisCrossingValue(valueAxis);
                var value = point.value;
                return valueAxis.options.reverse ? value < axisCrossingValue : value >= axisCrossingValue;
            },
            categoryAxisCrossingValue: function (valueAxis) {
                var categoryAxis = this.categoryAxis;
                var options = valueAxis.options;
                var crossingValues = [].concat(options.axisCrossingValues || options.axisCrossingValue);
                return crossingValues[categoryAxis.axisIndex || 0] || 0;
            },
            reflowPoint: function (point, pointSlot) {
                point.reflow(pointSlot);
            },
            reflowCategories: function () {
            },
            pointSlot: function (categorySlot, valueSlot) {
                var options = this.options;
                var invertAxes = options.invertAxes;
                var slotX = invertAxes ? valueSlot : categorySlot;
                var slotY = invertAxes ? categorySlot : valueSlot;
                return new Box(slotX.x1, slotY.y1, slotX.x2, slotY.y2);
            },
            categorySlot: function (categoryAxis, categoryIx) {
                return categoryAxis.getSlot(categoryIx);
            },
            traverseDataPoints: function (callback) {
                var this$1 = this;
                var series = this.options.series;
                var categories = this.categoryAxis.options.categories || [];
                var count = categoriesCount(series);
                var seriesCount = series.length;
                for (var seriesIx = 0; seriesIx < seriesCount; seriesIx++) {
                    this$1._outOfRangeCallback(series[seriesIx], '_outOfRangeMinPoint', seriesIx, callback);
                }
                for (var categoryIx = 0; categoryIx < count; categoryIx++) {
                    for (var seriesIx$1 = 0; seriesIx$1 < seriesCount; seriesIx$1++) {
                        var currentSeries = series[seriesIx$1];
                        var currentCategory = categories[categoryIx];
                        var pointData = this$1._bindPoint(currentSeries, seriesIx$1, categoryIx);
                        callback(pointData, {
                            category: currentCategory,
                            categoryIx: categoryIx,
                            series: currentSeries,
                            seriesIx: seriesIx$1
                        });
                    }
                }
                for (var seriesIx$2 = 0; seriesIx$2 < seriesCount; seriesIx$2++) {
                    this$1._outOfRangeCallback(series[seriesIx$2], '_outOfRangeMaxPoint', seriesIx$2, callback);
                }
            },
            _outOfRangeCallback: function (series, field, seriesIx, callback) {
                var outOfRangePoint = series[field];
                if (outOfRangePoint) {
                    var categoryIx = outOfRangePoint.categoryIx;
                    var pointData = this._bindPoint(series, seriesIx, categoryIx, outOfRangePoint.item);
                    callback(pointData, {
                        category: outOfRangePoint.category,
                        categoryIx: categoryIx,
                        series: series,
                        seriesIx: seriesIx
                    });
                }
            },
            _bindPoint: function (series, seriesIx, categoryIx, item) {
                if (!this._bindCache) {
                    this._bindCache = [];
                }
                var bindCache = this._bindCache[seriesIx];
                if (!bindCache) {
                    bindCache = this._bindCache[seriesIx] = [];
                }
                var data = bindCache[categoryIx];
                if (!data) {
                    data = bindCache[categoryIx] = SeriesBinder.current.bindPoint(series, categoryIx, item);
                }
                return data;
            },
            formatPointValue: function (point, format) {
                if (point.value === null) {
                    return '';
                }
                return this.chartService.format.auto(format, point.value);
            },
            pointValue: function (data) {
                return data.valueFields.value;
            }
        });
        setDefaultOptions(CategoricalChart, {
            series: [],
            invertAxes: false,
            isStacked: false,
            clip: true
        });
        var PointEventsMixin = {
            click: function (chart, e) {
                return chart.trigger(SERIES_CLICK, this.eventArgs(e));
            },
            hover: function (chart, e) {
                return chart.trigger(SERIES_HOVER, this.eventArgs(e));
            },
            eventArgs: function (e) {
                return {
                    value: this.value,
                    percentage: this.percentage,
                    stackValue: this.stackValue,
                    category: this.category,
                    series: this.series,
                    dataItem: this.dataItem,
                    runningTotal: this.runningTotal,
                    total: this.total,
                    element: eventElement(e),
                    originalEvent: e,
                    point: this
                };
            }
        };
        var NoteMixin = {
            createNote: function () {
                var options = this.options.notes;
                var text = this.noteText || options.label.text;
                if (options.visible !== false && defined(text) && text !== null) {
                    this.note = new dataviz.Note({
                        value: this.value,
                        text: text,
                        dataItem: this.dataItem,
                        category: this.category,
                        series: this.series
                    }, this.options.notes, this.owner.chartService);
                    this.append(this.note);
                }
            }
        };
        var ABOVE = 'above';
        var BELOW = 'below';
        var LinePoint = ChartElement.extend({
            init: function (value, options) {
                ChartElement.fn.init.call(this);
                this.value = value;
                this.options = options;
                this.aboveAxis = valueOrDefault(this.options.aboveAxis, true);
                this.tooltipTracking = true;
            },
            render: function () {
                var ref = this.options;
                var markers = ref.markers;
                var labels = ref.labels;
                if (this._rendered) {
                    return;
                }
                this._rendered = true;
                if (markers.visible && markers.size) {
                    this.marker = this.createMarker();
                    this.append(this.marker);
                }
                if (labels.visible) {
                    var labelText = this.value;
                    if (labels.template) {
                        var labelTemplate = TemplateService.compile(labels.template);
                        labelText = labelTemplate({
                            dataItem: this.dataItem,
                            category: this.category,
                            value: this.value,
                            percentage: this.percentage,
                            stackValue: this.stackValue,
                            series: this.series
                        });
                    } else if (labels.format) {
                        labelText = this.formatValue(labels.format);
                    }
                    this.label = new TextBox(labelText, deepExtend({
                        align: CENTER,
                        vAlign: CENTER,
                        margin: {
                            left: 5,
                            right: 5
                        },
                        zIndex: valueOrDefault(labels.zIndex, this.series.zIndex)
                    }, labels));
                    this.append(this.label);
                }
                this.createNote();
                if (this.errorBar) {
                    this.append(this.errorBar);
                }
            },
            markerBorder: function () {
                var options = this.options.markers;
                var background = options.background;
                var border = deepExtend({ color: this.color }, options.border);
                if (!defined(border.color)) {
                    border.color = new Color(background).brightness(BORDER_BRIGHTNESS).toHex();
                }
                return border;
            },
            createVisual: function () {
            },
            createMarker: function () {
                var options = this.options.markers;
                var marker = new ShapeElement({
                    type: options.type,
                    width: options.size,
                    height: options.size,
                    rotation: options.rotation,
                    background: options.background,
                    border: this.markerBorder(),
                    opacity: options.opacity,
                    zIndex: valueOrDefault(options.zIndex, this.series.zIndex),
                    animation: options.animation,
                    visual: options.visual
                }, {
                    dataItem: this.dataItem,
                    value: this.value,
                    series: this.series,
                    category: this.category
                });
                return marker;
            },
            markerBox: function () {
                if (!this.marker) {
                    this.marker = this.createMarker();
                    this.marker.reflow(this._childBox);
                }
                return this.marker.box;
            },
            reflow: function (targetBox) {
                var this$1 = this;
                var ref = this;
                var options = ref.options;
                var aboveAxis = ref.aboveAxis;
                var vertical = options.vertical;
                this.render();
                this.box = targetBox;
                var childBox = targetBox.clone();
                if (vertical) {
                    if (aboveAxis) {
                        childBox.y1 -= childBox.height();
                    } else {
                        childBox.y2 += childBox.height();
                    }
                } else {
                    if (aboveAxis) {
                        childBox.x1 += childBox.width();
                    } else {
                        childBox.x2 -= childBox.width();
                    }
                }
                this._childBox = childBox;
                if (this.marker) {
                    this.marker.reflow(childBox);
                }
                this.reflowLabel(childBox);
                if (this.errorBars) {
                    for (var i = 0; i < this.errorBars.length; i++) {
                        this$1.errorBars[i].reflow(childBox);
                    }
                }
                if (this.note) {
                    var noteTargetBox = this.markerBox();
                    if (!(options.markers.visible && options.markers.size)) {
                        var center = noteTargetBox.center();
                        noteTargetBox = new Box(center.x, center.y, center.x, center.y);
                    }
                    this.note.reflow(noteTargetBox);
                }
            },
            reflowLabel: function (box) {
                var ref = this;
                var options = ref.options;
                var label = ref.label;
                var anchor = options.labels.position;
                if (label) {
                    anchor = anchor === ABOVE ? TOP : anchor;
                    anchor = anchor === BELOW ? BOTTOM : anchor;
                    label.reflow(box);
                    label.box.alignTo(this.markerBox(), anchor);
                    label.reflow(label.box);
                }
            },
            createHighlight: function () {
                var markers = this.options.highlight.markers;
                var defaultColor = this.markerBorder().color;
                var options = this.options.markers;
                var size = options.size + (options.border.width || 0) + (markers.border.width || 0);
                var shadow = new ShapeElement({
                    type: options.type,
                    width: size,
                    height: size,
                    rotation: options.rotation,
                    background: markers.color || defaultColor,
                    border: {
                        color: markers.border.color,
                        width: markers.border.width,
                        opacity: valueOrDefault(markers.border.opacity, 1)
                    },
                    opacity: valueOrDefault(markers.opacity, 1)
                });
                shadow.reflow(this._childBox);
                return shadow.getElement();
            },
            highlightVisual: function () {
                return (this.marker || {}).visual;
            },
            highlightVisualArgs: function () {
                var marker = this.marker;
                var visual, rect;
                if (marker) {
                    rect = marker.paddingBox.toRect();
                    visual = marker.visual;
                } else {
                    var size = this.options.markers.size;
                    var halfSize = size / 2;
                    var center = this.box.center();
                    rect = new geometry.Rect([
                        center.x - halfSize,
                        center.y - halfSize
                    ], [
                        size,
                        size
                    ]);
                }
                return {
                    options: this.options,
                    rect: rect,
                    visual: visual
                };
            },
            tooltipAnchor: function () {
                var markerBox = this.markerBox();
                var clipBox = this.owner.pane.clipBox();
                var showTooltip = !clipBox || clipBox.overlaps(markerBox);
                if (showTooltip) {
                    var x = markerBox.x2 + TOOLTIP_OFFSET;
                    var horizontalAlign = LEFT;
                    var y, verticalAlign;
                    if (this.aboveAxis) {
                        y = markerBox.y1;
                        verticalAlign = BOTTOM;
                    } else {
                        y = markerBox.y2;
                        verticalAlign = TOP;
                    }
                    return {
                        point: new Point(x, y),
                        align: {
                            horizontal: horizontalAlign,
                            vertical: verticalAlign
                        }
                    };
                }
            },
            formatValue: function (format) {
                return this.owner.formatPointValue(this, format);
            },
            overlapsBox: function (box) {
                var markerBox = this.markerBox();
                return markerBox.overlaps(box);
            }
        });
        LinePoint.prototype.defaults = {
            vertical: true,
            markers: {
                visible: true,
                background: WHITE,
                size: LINE_MARKER_SIZE,
                type: CIRCLE,
                border: { width: 2 },
                opacity: 1
            },
            labels: {
                visible: false,
                position: ABOVE,
                margin: getSpacing(3),
                padding: getSpacing(4),
                animation: {
                    type: FADEIN,
                    delay: INITIAL_ANIMATION_DURATION
                }
            },
            notes: { label: {} },
            highlight: {
                markers: {
                    border: {
                        color: '#fff',
                        width: 2
                    }
                }
            },
            errorBars: { line: { width: 1 } }
        };
        deepExtend(LinePoint.prototype, PointEventsMixin);
        deepExtend(LinePoint.prototype, NoteMixin);
        var LineSegment = ChartElement.extend({
            init: function (linePoints, series, seriesIx) {
                ChartElement.fn.init.call(this);
                this.linePoints = linePoints;
                this.series = series;
                this.seriesIx = seriesIx;
            },
            points: function (visualPoints) {
                var linePoints = this.linePoints.concat(visualPoints || []);
                var points = [];
                for (var i = 0, length = linePoints.length; i < length; i++) {
                    if (linePoints[i].visible !== false) {
                        points.push(linePoints[i]._childBox.toRect().center());
                    }
                }
                return points;
            },
            createVisual: function () {
                var ref = this;
                var options = ref.options;
                var series = ref.series;
                var color = series.color;
                var defaults = series._defaults;
                if (isFunction(color) && defaults) {
                    color = defaults.color;
                }
                var line = Path.fromPoints(this.points(), {
                    stroke: {
                        color: color,
                        width: series.width,
                        opacity: series.opacity,
                        dashType: series.dashType
                    },
                    zIndex: series.zIndex
                });
                if (options.closed) {
                    line.close();
                }
                this.visual = line;
            },
            aliasFor: function (e, coords) {
                return this.parent.getNearestPoint(coords.x, coords.y, this.seriesIx);
            }
        });
        setDefaultOptions(LineSegment, { closed: false });
        var StepLineSegment = LineSegment.extend({
            points: function (visualPoints) {
                var points = this.calculateStepPoints(this.linePoints);
                if (visualPoints && visualPoints.length) {
                    points = points.concat(this.calculateStepPoints(visualPoints).reverse());
                }
                return points;
            },
            calculateStepPoints: function (points) {
                var chart = this.parent;
                var plotArea = chart.plotArea;
                var categoryAxis = plotArea.seriesCategoryAxis(this.series);
                var isInterpolate = chart.seriesMissingValues(this.series) === INTERPOLATE;
                var reverse = categoryAxis.options.reverse;
                var vertical = categoryAxis.options.vertical;
                var dir = reverse ? 2 : 1;
                var revDir = reverse ? 1 : 2;
                var length = points.length;
                var result = [];
                for (var i = 1; i < length; i++) {
                    var prevPoint = points[i - 1];
                    var point = points[i];
                    var prevMarkerBoxCenter = prevPoint.markerBox().center();
                    var markerBoxCenter = point.markerBox().center();
                    if (categoryAxis.options.justified) {
                        result.push(new GeometryPoint(prevMarkerBoxCenter.x, prevMarkerBoxCenter.y));
                        if (vertical) {
                            result.push(new GeometryPoint(prevMarkerBoxCenter.x, markerBoxCenter.y));
                        } else {
                            result.push(new GeometryPoint(markerBoxCenter.x, prevMarkerBoxCenter.y));
                        }
                        result.push(new GeometryPoint(markerBoxCenter.x, markerBoxCenter.y));
                    } else {
                        if (vertical) {
                            result.push(new GeometryPoint(prevMarkerBoxCenter.x, prevPoint.box[Y + dir]));
                            result.push(new GeometryPoint(prevMarkerBoxCenter.x, prevPoint.box[Y + revDir]));
                            if (isInterpolate) {
                                result.push(new GeometryPoint(prevMarkerBoxCenter.x, point.box[Y + dir]));
                            }
                            result.push(new GeometryPoint(markerBoxCenter.x, point.box[Y + dir]));
                            result.push(new GeometryPoint(markerBoxCenter.x, point.box[Y + revDir]));
                        } else {
                            result.push(new GeometryPoint(prevPoint.box[X + dir], prevMarkerBoxCenter.y));
                            result.push(new GeometryPoint(prevPoint.box[X + revDir], prevMarkerBoxCenter.y));
                            if (isInterpolate) {
                                result.push(new GeometryPoint(point.box[X + dir], prevMarkerBoxCenter.y));
                            }
                            result.push(new GeometryPoint(point.box[X + dir], markerBoxCenter.y));
                            result.push(new GeometryPoint(point.box[X + revDir], markerBoxCenter.y));
                        }
                    }
                }
                return result || [];
            }
        });
        var SplineSegment = LineSegment.extend({
            createVisual: function () {
                var series = this.series;
                var defaults = series._defaults;
                var color = series.color;
                if (isFunction(color) && defaults) {
                    color = defaults.color;
                }
                var curveProcessor = new dataviz.CurveProcessor(this.options.closed);
                var segments = curveProcessor.process(this.points());
                var curve = new Path({
                    stroke: {
                        color: color,
                        width: series.width,
                        opacity: series.opacity,
                        dashType: series.dashType
                    },
                    zIndex: series.zIndex
                });
                curve.segments.push.apply(curve.segments, segments);
                this.visual = curve;
            }
        });
        var LineChartMixin = {
            renderSegments: function () {
                var this$1 = this;
                var ref = this;
                var options = ref.options;
                var seriesPoints = ref.seriesPoints;
                var series = options.series;
                var seriesCount = seriesPoints.length;
                var lastSegment;
                this._segments = [];
                for (var seriesIx = 0; seriesIx < seriesCount; seriesIx++) {
                    var currentSeries = series[seriesIx];
                    var sortedPoints = this$1.sortPoints(seriesPoints[seriesIx]);
                    var pointCount = sortedPoints.length;
                    var linePoints = [];
                    for (var pointIx = 0; pointIx < pointCount; pointIx++) {
                        var point = sortedPoints[pointIx];
                        if (point) {
                            linePoints.push(point);
                        } else if (this$1.seriesMissingValues(currentSeries) !== INTERPOLATE) {
                            if (linePoints.length > 1) {
                                lastSegment = this$1.createSegment(linePoints, currentSeries, seriesIx, lastSegment);
                                this$1._addSegment(lastSegment);
                            }
                            linePoints = [];
                        }
                    }
                    if (linePoints.length > 1) {
                        lastSegment = this$1.createSegment(linePoints, currentSeries, seriesIx, lastSegment);
                        this$1._addSegment(lastSegment);
                    }
                }
                this.children.unshift.apply(this.children, this._segments);
            },
            _addSegment: function (segment) {
                this._segments.push(segment);
                segment.parent = this;
            },
            sortPoints: function (points) {
                return points;
            },
            seriesMissingValues: function (series) {
                var missingValues = series.missingValues;
                var assumeZero = !missingValues && this.options.isStacked;
                return assumeZero ? ZERO : missingValues || INTERPOLATE;
            },
            getNearestPoint: function (x, y, seriesIx) {
                var target = new Point(x, y);
                var allPoints = this.seriesPoints[seriesIx];
                var nearestPointDistance = MAX_VALUE;
                var nearestPoint;
                for (var i = 0; i < allPoints.length; i++) {
                    var point = allPoints[i];
                    if (point && defined(point.value) && point.value !== null && point.visible !== false) {
                        var pointBox = point.box;
                        var pointDistance = pointBox.center().distanceTo(target);
                        if (pointDistance < nearestPointDistance) {
                            nearestPoint = point;
                            nearestPointDistance = pointDistance;
                        }
                    }
                }
                return nearestPoint;
            }
        };
        var ClipAnimation = Animation.extend({
            setup: function () {
                this._setEnd(this.options.box.x1);
            },
            step: function (pos) {
                var box = this.options.box;
                this._setEnd(dataviz.interpolateValue(box.x1, box.x2, pos));
            },
            _setEnd: function (x) {
                var element = this.element;
                var segments = element.segments;
                var topRight = segments[1].anchor();
                var bottomRight = segments[2].anchor();
                element.suspend();
                topRight.setX(x);
                element.resume();
                bottomRight.setX(x);
            }
        });
        setDefaultOptions(ClipAnimation, { duration: INITIAL_ANIMATION_DURATION });
        AnimationFactory.current.register('clip', ClipAnimation);
        function anyHasZIndex(elements) {
            for (var idx = 0; idx < elements.length; idx++) {
                if (defined(elements[idx].zIndex)) {
                    return true;
                }
            }
        }
        var ClipAnimationMixin = {
            createAnimation: function () {
                var root = this.getRoot();
                if (root && (root.options || {}).transitions !== false) {
                    var box = root.box;
                    var clipPath = Path.fromRect(box.toRect());
                    this.visual.clip(clipPath);
                    this.animation = new ClipAnimation(clipPath, { box: box });
                    if (anyHasZIndex(this.options.series)) {
                        this._setChildrenAnimation(clipPath);
                    }
                }
            },
            _setChildrenAnimation: function (clipPath) {
                var points = this.animationPoints();
                for (var idx = 0; idx < points.length; idx++) {
                    var point = points[idx];
                    if (point && point.visual && defined(point.visual.options.zIndex)) {
                        point.visual.clip(clipPath);
                    }
                }
            }
        };
        var LineChart = CategoricalChart.extend({
            render: function () {
                CategoricalChart.fn.render.call(this);
                this.updateStackRange();
                this.renderSegments();
            },
            pointType: function () {
                return LinePoint;
            },
            createPoint: function (data, fields) {
                var categoryIx = fields.categoryIx;
                var category = fields.category;
                var series = fields.series;
                var seriesIx = fields.seriesIx;
                var missingValues = this.seriesMissingValues(series);
                var value = data.valueFields.value;
                if (!defined(value) || value === null) {
                    if (missingValues === ZERO) {
                        value = 0;
                    } else {
                        return null;
                    }
                }
                var pointOptions = this.pointOptions(series, seriesIx);
                pointOptions = this.evalPointOptions(pointOptions, value, category, categoryIx, series, seriesIx);
                var color = data.fields.color || series.color;
                if (isFunction(series.color)) {
                    color = pointOptions.color;
                }
                var point = new LinePoint(value, pointOptions);
                point.color = color;
                this.append(point);
                return point;
            },
            plotRange: function (point) {
                var this$1 = this;
                var plotValue = this.plotValue(point);
                if (this.options.isStacked) {
                    var categoryIx = point.categoryIx;
                    var categoryPoints = this.categoryPoints[categoryIx];
                    for (var i = 0; i < categoryPoints.length; i++) {
                        var other = categoryPoints[i];
                        if (point === other) {
                            break;
                        }
                        plotValue += this$1.plotValue(other);
                        if (this$1.options.isStacked100) {
                            plotValue = Math.min(plotValue, 1);
                        }
                    }
                }
                return [
                    plotValue,
                    plotValue
                ];
            },
            createSegment: function (linePoints, currentSeries, seriesIx) {
                var style = currentSeries.style;
                var pointType;
                if (style === STEP) {
                    pointType = StepLineSegment;
                } else if (style === SMOOTH) {
                    pointType = SplineSegment;
                } else {
                    pointType = LineSegment;
                }
                return new pointType(linePoints, currentSeries, seriesIx);
            },
            animationPoints: function () {
                var points = this.points;
                var result = [];
                for (var idx = 0; idx < points.length; idx++) {
                    result.push((points[idx] || {}).marker);
                }
                return result.concat(this._segments);
            }
        });
        deepExtend(LineChart.prototype, LineChartMixin, ClipAnimationMixin);
        var AreaSegmentMixin = {
            points: function () {
                var chart = this.parent;
                var plotArea = chart.plotArea;
                var invertAxes = chart.options.invertAxes;
                var valueAxis = chart.seriesValueAxis(this.series);
                var valueAxisLineBox = valueAxis.lineBox();
                var categoryAxis = plotArea.seriesCategoryAxis(this.series);
                var categoryAxisLineBox = categoryAxis.lineBox();
                var stackPoints = this.stackPoints;
                var points = this._linePoints(stackPoints);
                var pos = invertAxes ? X : Y;
                var end = invertAxes ? categoryAxisLineBox.x1 : categoryAxisLineBox.y1;
                end = limitValue(end, valueAxisLineBox[pos + 1], valueAxisLineBox[pos + 2]);
                if (!this.stackPoints && points.length > 1) {
                    var firstPoint = points[0];
                    var lastPoint = last(points);
                    if (invertAxes) {
                        points.unshift(new GeometryPoint(end, firstPoint.y));
                        points.push(new GeometryPoint(end, lastPoint.y));
                    } else {
                        points.unshift(new GeometryPoint(firstPoint.x, end));
                        points.push(new GeometryPoint(lastPoint.x, end));
                    }
                }
                return points;
            },
            createVisual: function () {
                var series = this.series;
                var defaults = series._defaults;
                var color = series.color;
                if (isFunction(color) && defaults) {
                    color = defaults.color;
                }
                this.visual = new Group({ zIndex: series.zIndex });
                this.createArea(color);
                this.createLine(color);
            },
            createLine: function (color) {
                var series = this.series;
                var lineOptions = deepExtend({
                    color: color,
                    opacity: series.opacity
                }, series.line);
                if (lineOptions.visible !== false && lineOptions.width > 0) {
                    var line = Path.fromPoints(this._linePoints(), {
                        stroke: {
                            color: lineOptions.color,
                            width: lineOptions.width,
                            opacity: lineOptions.opacity,
                            dashType: lineOptions.dashType,
                            lineCap: 'butt'
                        }
                    });
                    this.visual.append(line);
                }
            },
            createArea: function (color) {
                var series = this.series;
                var area = Path.fromPoints(this.points(), {
                    fill: {
                        color: color,
                        opacity: series.opacity
                    },
                    stroke: null
                });
                this.visual.append(area);
            }
        };
        var AreaSegment = LineSegment.extend({
            init: function (linePoints, stackPoints, currentSeries, seriesIx) {
                LineSegment.fn.init.call(this, linePoints, currentSeries, seriesIx);
                this.stackPoints = stackPoints;
            }
        });
        deepExtend(AreaSegment.prototype, AreaSegmentMixin, { _linePoints: LineSegment.prototype.points });
        var StepAreaSegment = StepLineSegment.extend({
            init: function (linePoints, stackPoints, currentSeries, seriesIx) {
                StepLineSegment.fn.init.call(this, linePoints, currentSeries, seriesIx);
                this.stackPoints = stackPoints;
            }
        });
        deepExtend(StepAreaSegment.prototype, AreaSegmentMixin, { _linePoints: StepLineSegment.prototype.points });
        var SplineAreaSegment = AreaSegment.extend({
            init: function (linePoints, prevSegment, isStacked, currentSeries, seriesIx) {
                AreaSegment.fn.init.call(this, linePoints, [], currentSeries, seriesIx);
                this.prevSegment = prevSegment;
                this.isStacked = isStacked;
            },
            strokeSegments: function () {
                var segments = this._strokeSegments;
                if (!segments) {
                    var curveProcessor = new dataviz.CurveProcessor(this.options.closed);
                    var linePoints = LineSegment.prototype.points.call(this);
                    segments = this._strokeSegments = curveProcessor.process(linePoints);
                }
                return segments;
            },
            createVisual: function () {
                var series = this.series;
                var defaults = series._defaults;
                var color = series.color;
                if (isFunction(color) && defaults) {
                    color = defaults.color;
                }
                this.visual = new Group({ zIndex: series.zIndex });
                this.createFill({
                    fill: {
                        color: color,
                        opacity: series.opacity
                    },
                    stroke: null
                });
                this.createStroke({
                    stroke: deepExtend({
                        color: color,
                        opacity: series.opacity,
                        lineCap: 'butt'
                    }, series.line)
                });
            },
            createFill: function (style) {
                var strokeSegments = this.strokeSegments();
                var fillSegments = strokeSegments.slice(0);
                var prevSegment = this.prevSegment;
                if (this.isStacked && prevSegment) {
                    var prevStrokeSegments = prevSegment.strokeSegments();
                    var prevAnchor = last(prevStrokeSegments).anchor();
                    fillSegments.push(new geometry.Segment(prevAnchor, prevAnchor, last(strokeSegments).anchor()));
                    var stackSegments = [];
                    for (var idx = prevStrokeSegments.length - 1; idx >= 0; idx--) {
                        var segment = prevStrokeSegments[idx];
                        stackSegments.push(new geometry.Segment(segment.anchor(), segment.controlOut(), segment.controlIn()));
                    }
                    append(fillSegments, stackSegments);
                    var firstAnchor = fillSegments[0].anchor();
                    fillSegments.push(new geometry.Segment(firstAnchor, firstAnchor, last(stackSegments).anchor()));
                }
                var fill = new Path(style);
                fill.segments.push.apply(fill.segments, fillSegments);
                this.closeFill(fill);
                this.visual.append(fill);
            },
            closeFill: function (fillPath) {
                var chart = this.parent;
                var prevSegment = this.prevSegment;
                var plotArea = chart.plotArea;
                var invertAxes = chart.options.invertAxes;
                var valueAxis = chart.seriesValueAxis(this.series);
                var valueAxisLineBox = valueAxis.lineBox();
                var categoryAxis = plotArea.seriesCategoryAxis(this.series);
                var categoryAxisLineBox = categoryAxis.lineBox();
                var pos = invertAxes ? X : Y;
                var segments = this.strokeSegments();
                var firstPoint = segments[0].anchor();
                var lastPoint = last(segments).anchor();
                var end = invertAxes ? categoryAxisLineBox.x1 : categoryAxisLineBox.y1;
                end = limitValue(end, valueAxisLineBox[pos + 1], valueAxisLineBox[pos + 2]);
                if (!(chart.options.isStacked && prevSegment) && segments.length > 1) {
                    if (invertAxes) {
                        fillPath.lineTo(end, lastPoint.y).lineTo(end, firstPoint.y);
                    } else {
                        fillPath.lineTo(lastPoint.x, end).lineTo(firstPoint.x, end);
                    }
                }
            },
            createStroke: function (style) {
                if (style.stroke.width > 0) {
                    var stroke = new Path(style);
                    stroke.segments.push.apply(stroke.segments, this.strokeSegments());
                    this.visual.append(stroke);
                }
            }
        });
        var AreaChart = LineChart.extend({
            createSegment: function (linePoints, currentSeries, seriesIx, prevSegment) {
                var isStacked = this.options.isStacked;
                var style = (currentSeries.line || {}).style;
                var stackPoints;
                if (isStacked && seriesIx > 0 && prevSegment) {
                    var missingValues = this.seriesMissingValues(currentSeries);
                    if (missingValues !== 'gap') {
                        stackPoints = prevSegment.linePoints;
                    } else {
                        stackPoints = this._gapStackPoints(linePoints, seriesIx, style);
                    }
                    if (style !== STEP) {
                        stackPoints = stackPoints.slice(0).reverse();
                    }
                }
                if (style === SMOOTH) {
                    return new SplineAreaSegment(linePoints, prevSegment, isStacked, currentSeries, seriesIx);
                }
                var pointType;
                if (style === STEP) {
                    pointType = StepAreaSegment;
                } else {
                    pointType = AreaSegment;
                }
                return new pointType(linePoints, stackPoints, currentSeries, seriesIx);
            },
            reflow: function (targetBox) {
                var this$1 = this;
                LineChart.fn.reflow.call(this, targetBox);
                var stackPoints = this._stackPoints;
                if (stackPoints) {
                    for (var idx = 0; idx < stackPoints.length; idx++) {
                        var stackPoint = stackPoints[idx];
                        var pointSlot = this$1.categoryAxis.getSlot(stackPoint.categoryIx);
                        stackPoint.reflow(pointSlot);
                    }
                }
            },
            _gapStackPoints: function (linePoints, seriesIx, style) {
                var this$1 = this;
                var seriesPoints = this.seriesPoints;
                var startIdx = linePoints[0].categoryIx;
                var length = linePoints.length;
                if (startIdx < 0) {
                    startIdx = 0;
                    length--;
                }
                var endIdx = startIdx + length;
                var pointOffset = this.seriesOptions[0]._outOfRangeMinPoint ? 1 : 0;
                var stackPoints = [];
                this._stackPoints = this._stackPoints || [];
                for (var categoryIx = startIdx; categoryIx < endIdx; categoryIx++) {
                    var pointIx = categoryIx + pointOffset;
                    var currentSeriesIx = seriesIx;
                    var point = void 0;
                    do {
                        currentSeriesIx--;
                        point = seriesPoints[currentSeriesIx][pointIx];
                    } while (currentSeriesIx > 0 && !point);
                    if (point) {
                        if (style !== STEP && categoryIx > startIdx && !seriesPoints[currentSeriesIx][pointIx - 1]) {
                            stackPoints.push(this$1._previousSegmentPoint(categoryIx, pointIx, pointIx - 1, currentSeriesIx));
                        }
                        stackPoints.push(point);
                        if (style !== STEP && categoryIx + 1 < endIdx && !seriesPoints[currentSeriesIx][pointIx + 1]) {
                            stackPoints.push(this$1._previousSegmentPoint(categoryIx, pointIx, pointIx + 1, currentSeriesIx));
                        }
                    } else {
                        var gapStackPoint = this$1._createGapStackPoint(categoryIx);
                        this$1._stackPoints.push(gapStackPoint);
                        stackPoints.push(gapStackPoint);
                    }
                }
                return stackPoints;
            },
            _previousSegmentPoint: function (categoryIx, pointIx, segmentIx, seriesIdx) {
                var seriesPoints = this.seriesPoints;
                var index = seriesIdx;
                var point;
                while (index > 0 && !point) {
                    index--;
                    point = seriesPoints[index][segmentIx];
                }
                if (!point) {
                    point = this._createGapStackPoint(categoryIx);
                    this._stackPoints.push(point);
                } else {
                    point = seriesPoints[index][pointIx];
                }
                return point;
            },
            _createGapStackPoint: function (categoryIx) {
                var options = this.pointOptions({}, 0);
                var point = new LinePoint(0, options);
                point.categoryIx = categoryIx;
                point.series = {};
                return point;
            },
            seriesMissingValues: function (series) {
                return series.missingValues || ZERO;
            }
        });
        var AxisGroupRangeTracker = Class.extend({
            init: function () {
                this.axisRanges = {};
            },
            update: function (chartAxisRanges) {
                var axisRanges = this.axisRanges;
                for (var axisName in chartAxisRanges) {
                    var chartRange = chartAxisRanges[axisName];
                    var range = axisRanges[axisName];
                    axisRanges[axisName] = range = range || {
                        min: MAX_VALUE,
                        max: MIN_VALUE
                    };
                    range.min = Math.min(range.min, chartRange.min);
                    range.max = Math.max(range.max, chartRange.max);
                }
            },
            reset: function (axisName) {
                this.axisRanges[axisName] = undefined;
            },
            query: function (axisName) {
                return this.axisRanges[axisName];
            }
        });
        var BarLabel = ChartElement.extend({
            init: function (content, options) {
                ChartElement.fn.init.call(this, options);
                this.textBox = new TextBox(content, this.options);
                this.append(this.textBox);
            },
            createVisual: function () {
                this.textBox.options.noclip = this.options.noclip;
            },
            reflow: function (targetBox) {
                var options = this.options;
                var vertical = options.vertical;
                var aboveAxis = options.aboveAxis;
                var text = this.children[0];
                var textOptions = text.options;
                var box = text.box;
                var padding = text.options.padding;
                var labelBox = targetBox;
                textOptions.align = vertical ? CENTER : LEFT;
                textOptions.vAlign = vertical ? TOP : CENTER;
                if (options.position === INSIDE_END) {
                    if (vertical) {
                        textOptions.vAlign = TOP;
                        if (!aboveAxis && box.height() < targetBox.height()) {
                            textOptions.vAlign = BOTTOM;
                        }
                    } else {
                        textOptions.align = aboveAxis ? RIGHT : LEFT;
                    }
                } else if (options.position === CENTER) {
                    textOptions.vAlign = CENTER;
                    textOptions.align = CENTER;
                } else if (options.position === INSIDE_BASE) {
                    if (vertical) {
                        textOptions.vAlign = aboveAxis ? BOTTOM : TOP;
                    } else {
                        textOptions.align = aboveAxis ? LEFT : RIGHT;
                    }
                } else if (options.position === OUTSIDE_END) {
                    if (vertical) {
                        if (aboveAxis) {
                            labelBox = new Box(targetBox.x1, targetBox.y1 - box.height(), targetBox.x2, targetBox.y1);
                        } else {
                            labelBox = new Box(targetBox.x1, targetBox.y2, targetBox.x2, targetBox.y2 + box.height());
                        }
                    } else {
                        textOptions.align = CENTER;
                        if (aboveAxis) {
                            labelBox = new Box(targetBox.x2, targetBox.y1, targetBox.x2 + box.width(), targetBox.y2);
                        } else {
                            labelBox = new Box(targetBox.x1 - box.width(), targetBox.y1, targetBox.x1, targetBox.y2);
                        }
                    }
                }
                if (!options.rotation) {
                    if (vertical) {
                        padding.left = padding.right = (labelBox.width() - text.contentBox.width()) / 2;
                    } else {
                        padding.top = padding.bottom = (labelBox.height() - text.contentBox.height()) / 2;
                    }
                }
                text.reflow(labelBox);
            },
            alignToClipBox: function (clipBox) {
                var vertical = this.options.vertical;
                var field = vertical ? Y : X;
                var start = field + '1';
                var end = field + '2';
                var text = this.children[0];
                var parentBox = this.parent.box;
                if (parentBox[start] < clipBox[start] || clipBox[end] < parentBox[end]) {
                    var targetBox = text.paddingBox.clone();
                    targetBox[start] = Math.max(parentBox[start], clipBox[start]);
                    targetBox[end] = Math.min(parentBox[end], clipBox[end]);
                    this.reflow(targetBox);
                }
            }
        });
        setDefaultOptions(BarLabel, {
            position: OUTSIDE_END,
            margin: getSpacing(3),
            padding: getSpacing(4),
            color: BLACK,
            background: '',
            border: {
                width: 1,
                color: ''
            },
            aboveAxis: true,
            vertical: false,
            animation: {
                type: FADEIN,
                delay: INITIAL_ANIMATION_DURATION
            },
            zIndex: 2
        });
        function hasGradientOverlay(options) {
            var overlay = options.overlay;
            return overlay && overlay.gradient && overlay.gradient !== 'none';
        }
        var BAR_ALIGN_MIN_WIDTH = 6;
        var Bar = ChartElement.extend({
            init: function (value, options) {
                ChartElement.fn.init.call(this);
                this.options = options;
                this.color = options.color || WHITE;
                this.aboveAxis = valueOrDefault(this.options.aboveAxis, true);
                this.value = value;
            },
            render: function () {
                if (this._rendered) {
                    return;
                }
                this._rendered = true;
                this.createLabel();
                this.createNote();
                if (this.errorBar) {
                    this.append(this.errorBar);
                }
            },
            createLabel: function () {
                var options = this.options;
                var labels = options.labels;
                if (labels.visible) {
                    var labelText;
                    if (labels.template) {
                        var labelTemplate = TemplateService.compile(labels.template);
                        labelText = labelTemplate({
                            dataItem: this.dataItem,
                            category: this.category,
                            value: this.value,
                            percentage: this.percentage,
                            stackValue: this.stackValue,
                            runningTotal: this.runningTotal,
                            total: this.total,
                            series: this.series
                        });
                    } else {
                        labelText = this.formatValue(labels.format);
                    }
                    this.label = new BarLabel(labelText, deepExtend({ vertical: options.vertical }, labels));
                    this.append(this.label);
                }
            },
            formatValue: function (format) {
                return this.owner.formatPointValue(this, format);
            },
            reflow: function (targetBox) {
                var this$1 = this;
                this.render();
                var label = this.label;
                this.box = targetBox;
                if (label) {
                    label.options.aboveAxis = this.aboveAxis;
                    label.reflow(targetBox);
                }
                if (this.note) {
                    this.note.reflow(targetBox);
                }
                if (this.errorBars) {
                    for (var i = 0; i < this.errorBars.length; i++) {
                        this$1.errorBars[i].reflow(targetBox);
                    }
                }
            },
            createVisual: function () {
                var this$1 = this;
                var ref = this;
                var box = ref.box;
                var options = ref.options;
                var customVisual = options.visual;
                if (this.visible !== false) {
                    ChartElement.fn.createVisual.call(this);
                    if (customVisual) {
                        var visual = this.rectVisual = customVisual({
                            category: this.category,
                            dataItem: this.dataItem,
                            value: this.value,
                            sender: this.getSender(),
                            series: this.series,
                            percentage: this.percentage,
                            stackValue: this.stackValue,
                            runningTotal: this.runningTotal,
                            total: this.total,
                            rect: box.toRect(),
                            createVisual: function () {
                                var group = new Group();
                                this$1.createRect(group);
                                return group;
                            },
                            options: options
                        });
                        if (visual) {
                            this.visual.append(visual);
                        }
                    } else if (box.width() > 0 && box.height() > 0) {
                        this.createRect(this.visual);
                    }
                }
            },
            createRect: function (visual) {
                var options = this.options;
                var border = options.border;
                var strokeOpacity = defined(border.opacity) ? border.opacity : options.opacity;
                var rect = this.box.toRect();
                rect.size.width = Math.round(rect.size.width);
                var path = this.rectVisual = Path.fromRect(rect, {
                    fill: {
                        color: this.color,
                        opacity: options.opacity
                    },
                    stroke: {
                        color: this.getBorderColor(),
                        width: border.width,
                        opacity: strokeOpacity,
                        dashType: border.dashType
                    }
                });
                var width = this.box.width();
                var height = this.box.height();
                var size = options.vertical ? width : height;
                if (size > BAR_ALIGN_MIN_WIDTH) {
                    alignPathToPixel(path);
                    if (width < 1 || height < 1) {
                        path.options.stroke.lineJoin = 'round';
                    }
                }
                visual.append(path);
                if (hasGradientOverlay(options)) {
                    var overlay = this.createGradientOverlay(path, { baseColor: this.color }, deepExtend({
                        end: !options.vertical ? [
                            0,
                            1
                        ] : undefined
                    }, options.overlay));
                    visual.append(overlay);
                }
            },
            createHighlight: function (style) {
                var highlight = Path.fromRect(this.box.toRect(), style);
                return alignPathToPixel(highlight);
            },
            highlightVisual: function () {
                return this.rectVisual;
            },
            highlightVisualArgs: function () {
                return {
                    options: this.options,
                    rect: this.box.toRect(),
                    visual: this.rectVisual
                };
            },
            getBorderColor: function () {
                var color = this.color;
                var border = this.options.border;
                var brightness = border._brightness || BORDER_BRIGHTNESS;
                var borderColor = border.color;
                if (!defined(borderColor)) {
                    borderColor = new Color(color).brightness(brightness).toHex();
                }
                return borderColor;
            },
            tooltipAnchor: function () {
                var ref = this;
                var options = ref.options;
                var box = ref.box;
                var aboveAxis = ref.aboveAxis;
                var clipBox = this.owner.pane.clipBox() || box;
                var horizontalAlign = LEFT;
                var verticalAlign = TOP;
                var x, y;
                if (options.vertical) {
                    x = Math.min(box.x2, clipBox.x2) + TOOLTIP_OFFSET;
                    if (aboveAxis) {
                        y = Math.max(box.y1, clipBox.y1);
                    } else {
                        y = Math.min(box.y2, clipBox.y2);
                        verticalAlign = BOTTOM;
                    }
                } else {
                    var x1 = Math.max(box.x1, clipBox.x1);
                    var x2 = Math.min(box.x2, clipBox.x2);
                    if (options.isStacked) {
                        verticalAlign = BOTTOM;
                        if (aboveAxis) {
                            horizontalAlign = RIGHT;
                            x = x2;
                        } else {
                            x = x1;
                        }
                        y = Math.max(box.y1, clipBox.y1) - TOOLTIP_OFFSET;
                    } else {
                        if (aboveAxis) {
                            x = x2 + TOOLTIP_OFFSET;
                        } else {
                            x = x1 - TOOLTIP_OFFSET;
                            horizontalAlign = RIGHT;
                        }
                        y = Math.max(box.y1, clipBox.y1);
                    }
                }
                return {
                    point: new Point(x, y),
                    align: {
                        horizontal: horizontalAlign,
                        vertical: verticalAlign
                    }
                };
            },
            overlapsBox: function (box) {
                return this.box.overlaps(box);
            }
        });
        deepExtend(Bar.prototype, PointEventsMixin);
        deepExtend(Bar.prototype, NoteMixin);
        Bar.prototype.defaults = {
            border: { width: 1 },
            vertical: true,
            overlay: { gradient: 'glass' },
            labels: {
                visible: false,
                format: '{0}'
            },
            opacity: 1,
            notes: { label: {} }
        };
        var ClusterLayout = ChartElement.extend({
            reflow: function (box) {
                var ref = this.options;
                var vertical = ref.vertical;
                var gap = ref.gap;
                var spacing = ref.spacing;
                var children = this.children;
                var count = children.length;
                var axis = vertical ? Y : X;
                var slots = count + gap + spacing * (count - 1);
                var slotSize = (vertical ? box.height() : box.width()) / slots;
                var position = box[axis + 1] + slotSize * (gap / 2);
                for (var i = 0; i < count; i++) {
                    var childBox = (children[i].box || box).clone();
                    childBox[axis + 1] = position;
                    childBox[axis + 2] = position + slotSize;
                    children[i].reflow(childBox);
                    if (i < count - 1) {
                        position += slotSize * spacing;
                    }
                    position += slotSize;
                }
            }
        });
        setDefaultOptions(ClusterLayout, {
            vertical: false,
            gap: 0,
            spacing: 0
        });
        var StackWrap = ChartElement.extend({
            reflow: function (targetBox) {
                var this$1 = this;
                var positionAxis = this.options.vertical ? X : Y;
                var children = this.children;
                var childrenCount = children.length;
                var box = this.box = new Box();
                for (var i = 0; i < childrenCount; i++) {
                    var currentChild = children[i];
                    if (currentChild.visible !== false) {
                        var childBox = currentChild.box.clone();
                        childBox.snapTo(targetBox, positionAxis);
                        if (i === 0) {
                            box = this$1.box = childBox.clone();
                        }
                        currentChild.reflow(childBox);
                        box.wrap(childBox);
                    }
                }
            }
        });
        setDefaultOptions(StackWrap, { vertical: true });
        var BarChart = CategoricalChart.extend({
            render: function () {
                CategoricalChart.fn.render.call(this);
                this.updateStackRange();
            },
            pointType: function () {
                return Bar;
            },
            clusterType: function () {
                return ClusterLayout;
            },
            stackType: function () {
                return StackWrap;
            },
            stackLimits: function (axisName, stackName) {
                var limits = CategoricalChart.fn.stackLimits.call(this, axisName, stackName);
                return limits;
            },
            createPoint: function (data, fields) {
                var categoryIx = fields.categoryIx;
                var category = fields.category;
                var series = fields.series;
                var seriesIx = fields.seriesIx;
                var ref = this;
                var options = ref.options;
                var children = ref.children;
                var isStacked = options.isStacked;
                var value = this.pointValue(data);
                var pointOptions = this.pointOptions(series, seriesIx);
                var labelOptions = pointOptions.labels;
                if (isStacked) {
                    if (labelOptions.position === OUTSIDE_END) {
                        labelOptions.position = INSIDE_END;
                    }
                }
                pointOptions.isStacked = isStacked;
                var color = data.fields.color || series.color;
                if (value < 0 && pointOptions.negativeColor) {
                    color = pointOptions.negativeColor;
                }
                pointOptions = this.evalPointOptions(pointOptions, value, category, categoryIx, series, seriesIx);
                if (isFunction(series.color)) {
                    color = pointOptions.color;
                }
                var pointType = this.pointType();
                var point = new pointType(value, pointOptions);
                point.color = color;
                var cluster = children[categoryIx];
                if (!cluster) {
                    var clusterType = this.clusterType();
                    cluster = new clusterType({
                        vertical: options.invertAxes,
                        gap: options.gap,
                        spacing: options.spacing
                    });
                    this.append(cluster);
                }
                if (isStacked) {
                    var stackWrap = this.getStackWrap(series, cluster);
                    stackWrap.append(point);
                } else {
                    cluster.append(point);
                }
                return point;
            },
            getStackWrap: function (series, cluster) {
                var stack = series.stack;
                var stackGroup = stack ? stack.group || stack : stack;
                var wraps = cluster.children;
                var stackWrap;
                if (typeof stackGroup === datavizConstants.STRING) {
                    for (var i = 0; i < wraps.length; i++) {
                        if (wraps[i]._stackGroup === stackGroup) {
                            stackWrap = wraps[i];
                            break;
                        }
                    }
                } else {
                    stackWrap = wraps[0];
                }
                if (!stackWrap) {
                    var stackType = this.stackType();
                    stackWrap = new stackType({ vertical: !this.options.invertAxes });
                    stackWrap._stackGroup = stackGroup;
                    cluster.append(stackWrap);
                }
                return stackWrap;
            },
            categorySlot: function (categoryAxis, categoryIx, valueAxis) {
                var options = this.options;
                var categorySlot = categoryAxis.getSlot(categoryIx);
                var startValue = valueAxis.startValue();
                if (options.isStacked) {
                    var zeroSlot = valueAxis.getSlot(startValue, startValue, true);
                    var stackAxis = options.invertAxes ? X : Y;
                    categorySlot[stackAxis + 1] = categorySlot[stackAxis + 2] = zeroSlot[stackAxis + 1];
                }
                return categorySlot;
            },
            reflowCategories: function (categorySlots) {
                var children = this.children;
                var childrenLength = children.length;
                for (var i = 0; i < childrenLength; i++) {
                    children[i].reflow(categorySlots[i]);
                }
            },
            createAnimation: function () {
                this._setAnimationOptions();
                CategoricalChart.fn.createAnimation.call(this);
                if (anyHasZIndex(this.options.series)) {
                    this._setChildrenAnimation();
                }
            },
            _setChildrenAnimation: function () {
                var this$1 = this;
                var points = this.points;
                for (var idx = 0; idx < points.length; idx++) {
                    var point = points[idx];
                    var pointVisual = point.visual;
                    if (pointVisual && defined(pointVisual.options.zIndex)) {
                        point.options.animation = this$1.options.animation;
                        point.createAnimation();
                    }
                }
            },
            _setAnimationOptions: function () {
                var options = this.options;
                var animation = options.animation || {};
                var origin;
                if (options.isStacked) {
                    var valueAxis = this.seriesValueAxis(options.series[0]);
                    origin = valueAxis.getSlot(valueAxis.startValue());
                } else {
                    origin = this.categoryAxis.getSlot(0);
                }
                animation.origin = new GeometryPoint(origin.x1, origin.y1);
                animation.vertical = !options.invertAxes;
            }
        });
        setDefaultOptions(BarChart, { animation: { type: BAR } });
        var Candlestick = ChartElement.extend({
            init: function (value, options) {
                ChartElement.fn.init.call(this, options);
                this.value = value;
            },
            reflow: function (box) {
                var ref = this;
                var options = ref.options;
                var value = ref.value;
                var chart = ref.owner;
                var valueAxis = chart.seriesValueAxis(options);
                var ocSlot = valueAxis.getSlot(value.open, value.close);
                var lhSlot = valueAxis.getSlot(value.low, value.high);
                ocSlot.x1 = lhSlot.x1 = box.x1;
                ocSlot.x2 = lhSlot.x2 = box.x2;
                this.realBody = ocSlot;
                var mid = lhSlot.center().x;
                var points = [];
                points.push([
                    [
                        mid,
                        lhSlot.y1
                    ],
                    [
                        mid,
                        ocSlot.y1
                    ]
                ]);
                points.push([
                    [
                        mid,
                        ocSlot.y2
                    ],
                    [
                        mid,
                        lhSlot.y2
                    ]
                ]);
                this.lines = points;
                this.box = lhSlot.clone().wrap(ocSlot);
                if (!this._rendered) {
                    this._rendered = true;
                    this.createNote();
                }
                this.reflowNote();
            },
            reflowNote: function () {
                if (this.note) {
                    this.note.reflow(this.box);
                }
            },
            createVisual: function () {
                ChartElement.fn.createVisual.call(this);
                this._mainVisual = this.mainVisual(this.options);
                this.visual.append(this._mainVisual);
                this.createOverlay();
            },
            mainVisual: function (options) {
                var group = new Group();
                this.createBody(group, options);
                this.createLines(group, options);
                return group;
            },
            createBody: function (container, options) {
                var body = Path.fromRect(this.realBody.toRect(), {
                    fill: {
                        color: this.color,
                        opacity: options.opacity
                    },
                    stroke: null
                });
                if (options.border.width > 0) {
                    body.options.set('stroke', {
                        color: this.getBorderColor(),
                        width: options.border.width,
                        dashType: options.border.dashType,
                        opacity: valueOrDefault(options.border.opacity, options.opacity)
                    });
                }
                alignPathToPixel(body);
                container.append(body);
                if (hasGradientOverlay(options)) {
                    container.append(this.createGradientOverlay(body, { baseColor: this.color }, deepExtend({
                        end: !options.vertical ? [
                            0,
                            1
                        ] : undefined
                    }, options.overlay)));
                }
            },
            createLines: function (container, options) {
                this.drawLines(container, options, this.lines, options.line);
            },
            drawLines: function (container, options, lines, lineOptions) {
                if (!lines) {
                    return;
                }
                var lineStyle = {
                    stroke: {
                        color: lineOptions.color || this.color,
                        opacity: valueOrDefault(lineOptions.opacity, options.opacity),
                        width: lineOptions.width,
                        dashType: lineOptions.dashType,
                        lineCap: 'butt'
                    }
                };
                for (var i = 0; i < lines.length; i++) {
                    var line = Path.fromPoints(lines[i], lineStyle);
                    alignPathToPixel(line);
                    container.append(line);
                }
            },
            getBorderColor: function () {
                var border = this.options.border;
                var borderColor = border.color;
                if (!defined(borderColor)) {
                    borderColor = new Color(this.color).brightness(border._brightness).toHex();
                }
                return borderColor;
            },
            createOverlay: function () {
                var overlay = Path.fromRect(this.box.toRect(), {
                    fill: {
                        color: WHITE,
                        opacity: 0
                    },
                    stroke: null
                });
                this.visual.append(overlay);
            },
            createHighlight: function () {
                var highlight = this.options.highlight;
                var normalColor = this.color;
                this.color = highlight.color || this.color;
                var overlay = this.mainVisual(deepExtend({}, this.options, { line: { color: this.getBorderColor() } }, highlight));
                this.color = normalColor;
                return overlay;
            },
            highlightVisual: function () {
                return this._mainVisual;
            },
            highlightVisualArgs: function () {
                return {
                    options: this.options,
                    rect: this.box.toRect(),
                    visual: this._mainVisual
                };
            },
            tooltipAnchor: function () {
                var box = this.box;
                var clipBox = this.owner.pane.clipBox() || box;
                return {
                    point: new Point(box.x2 + TOOLTIP_OFFSET, Math.max(box.y1, clipBox.y1) + TOOLTIP_OFFSET),
                    align: {
                        horizontal: LEFT,
                        vertical: TOP
                    }
                };
            },
            formatValue: function (format) {
                return this.owner.formatPointValue(this, format);
            },
            overlapsBox: function (box) {
                return this.box.overlaps(box);
            }
        });
        setDefaultOptions(Candlestick, {
            vertical: true,
            border: { _brightness: 0.8 },
            line: { width: 2 },
            overlay: { gradient: 'glass' },
            tooltip: { format: '<table>' + '<tr><th colspan=\'2\'>{4:d}</th></tr>' + '<tr><td>Open:</td><td>{0:C}</td></tr>' + '<tr><td>High:</td><td>{1:C}</td></tr>' + '<tr><td>Low:</td><td>{2:C}</td></tr>' + '<tr><td>Close:</td><td>{3:C}</td></tr>' + '</table>' },
            highlight: {
                opacity: 1,
                border: {
                    width: 1,
                    opacity: 1
                },
                line: {
                    width: 1,
                    opacity: 1
                }
            },
            notes: {
                visible: true,
                label: {}
            }
        });
        deepExtend(Candlestick.prototype, PointEventsMixin);
        deepExtend(Candlestick.prototype, NoteMixin);
        function areNumbers(values) {
            return countNumbers(values) === values.length;
        }
        var CandlestickChart = CategoricalChart.extend({
            reflowCategories: function (categorySlots) {
                var children = this.children;
                var childrenLength = children.length;
                for (var i = 0; i < childrenLength; i++) {
                    children[i].reflow(categorySlots[i]);
                }
            },
            addValue: function (data, fields) {
                var categoryIx = fields.categoryIx;
                var category = fields.category;
                var series = fields.series;
                var seriesIx = fields.seriesIx;
                var ref = this;
                var children = ref.children;
                var options = ref.options;
                var value = data.valueFields;
                var valueParts = this.splitValue(value);
                var hasValue = areNumbers(valueParts);
                var dataItem = series.data[categoryIx];
                var categoryPoints = this.categoryPoints[categoryIx];
                var point;
                if (!categoryPoints) {
                    this.categoryPoints[categoryIx] = categoryPoints = [];
                }
                if (hasValue) {
                    point = this.createPoint(data, fields);
                }
                var cluster = children[categoryIx];
                if (!cluster) {
                    cluster = new ClusterLayout({
                        vertical: options.invertAxes,
                        gap: options.gap,
                        spacing: options.spacing
                    });
                    this.append(cluster);
                }
                if (point) {
                    this.updateRange(value, fields);
                    cluster.append(point);
                    point.categoryIx = categoryIx;
                    point.category = category;
                    point.series = series;
                    point.seriesIx = seriesIx;
                    point.owner = this;
                    point.dataItem = dataItem;
                    point.noteText = data.fields.noteText;
                }
                this.points.push(point);
                categoryPoints.push(point);
            },
            pointType: function () {
                return Candlestick;
            },
            createPoint: function (data, fields) {
                var categoryIx = fields.categoryIx;
                var category = fields.category;
                var series = fields.series;
                var seriesIx = fields.seriesIx;
                var pointType = this.pointType();
                var value = data.valueFields;
                var pointOptions = deepExtend({}, series);
                var color = data.fields.color || series.color;
                pointOptions = this.evalPointOptions(pointOptions, value, category, categoryIx, series, seriesIx);
                if (series.type === CANDLESTICK) {
                    if (value.open > value.close) {
                        color = data.fields.downColor || series.downColor || series.color;
                    }
                }
                if (isFunction(series.color)) {
                    color = pointOptions.color;
                }
                pointOptions.vertical = !this.options.invertAxes;
                var point = new pointType(value, pointOptions);
                point.color = color;
                return point;
            },
            splitValue: function (value) {
                return [
                    value.low,
                    value.open,
                    value.close,
                    value.high
                ];
            },
            updateRange: function (value, fields) {
                var axisName = fields.series.axis;
                var parts = this.splitValue(value);
                var axisRange = this.valueAxisRanges[axisName];
                axisRange = this.valueAxisRanges[axisName] = axisRange || {
                    min: MAX_VALUE,
                    max: MIN_VALUE
                };
                axisRange = this.valueAxisRanges[axisName] = {
                    min: Math.min.apply(Math, parts.concat([axisRange.min])),
                    max: Math.max.apply(Math, parts.concat([axisRange.max]))
                };
            },
            formatPointValue: function (point, format) {
                var value = point.value;
                return this.chartService.format.auto(format, value.open, value.high, value.low, value.close, point.category);
            },
            animationPoints: function () {
                return this.points;
            }
        });
        deepExtend(CandlestickChart.prototype, ClipAnimationMixin);
        var BoxPlot = Candlestick.extend({
            init: function (value, options) {
                Candlestick.fn.init.call(this, value, options);
                this.createNote();
            },
            reflow: function (box) {
                var ref = this;
                var options = ref.options;
                var value = ref.value;
                var chart = ref.owner;
                var valueAxis = chart.seriesValueAxis(options);
                var whiskerSlot, boxSlot;
                this.boxSlot = boxSlot = valueAxis.getSlot(value.q1, value.q3);
                this.realBody = boxSlot;
                this.reflowBoxSlot(box);
                this.whiskerSlot = whiskerSlot = valueAxis.getSlot(value.lower, value.upper);
                this.reflowWhiskerSlot(box);
                var medianSlot = valueAxis.getSlot(value.median);
                if (value.mean) {
                    var meanSlot = valueAxis.getSlot(value.mean);
                    this.meanPoints = this.calcMeanPoints(box, meanSlot);
                }
                this.whiskerPoints = this.calcWhiskerPoints(boxSlot, whiskerSlot);
                this.medianPoints = this.calcMedianPoints(box, medianSlot);
                this.box = whiskerSlot.clone().wrap(boxSlot);
                this.reflowNote();
            },
            reflowBoxSlot: function (box) {
                this.boxSlot.x1 = box.x1;
                this.boxSlot.x2 = box.x2;
            },
            reflowWhiskerSlot: function (box) {
                this.whiskerSlot.x1 = box.x1;
                this.whiskerSlot.x2 = box.x2;
            },
            calcMeanPoints: function (box, meanSlot) {
                return [[
                        [
                            box.x1,
                            meanSlot.y1
                        ],
                        [
                            box.x2,
                            meanSlot.y1
                        ]
                    ]];
            },
            calcWhiskerPoints: function (boxSlot, whiskerSlot) {
                var mid = whiskerSlot.center().x;
                return [
                    [
                        [
                            mid - 5,
                            whiskerSlot.y1
                        ],
                        [
                            mid + 5,
                            whiskerSlot.y1
                        ],
                        [
                            mid,
                            whiskerSlot.y1
                        ],
                        [
                            mid,
                            boxSlot.y1
                        ]
                    ],
                    [
                        [
                            mid - 5,
                            whiskerSlot.y2
                        ],
                        [
                            mid + 5,
                            whiskerSlot.y2
                        ],
                        [
                            mid,
                            whiskerSlot.y2
                        ],
                        [
                            mid,
                            boxSlot.y2
                        ]
                    ]
                ];
            },
            calcMedianPoints: function (box, medianSlot) {
                return [[
                        [
                            box.x1,
                            medianSlot.y1
                        ],
                        [
                            box.x2,
                            medianSlot.y1
                        ]
                    ]];
            },
            renderOutliers: function (options) {
                var this$1 = this;
                var value = this.value;
                var outliers = value.outliers || [];
                var outerFence = Math.abs(value.q3 - value.q1) * 3;
                var elements = [];
                var markers = options.markers || {};
                for (var i = 0; i < outliers.length; i++) {
                    var outlierValue = outliers[i];
                    if (outlierValue < value.q3 + outerFence && outlierValue > value.q1 - outerFence) {
                        markers = options.outliers;
                    } else {
                        markers = options.extremes;
                    }
                    var markersBorder = deepExtend({}, markers.border);
                    if (!defined(markersBorder.color)) {
                        if (defined(this$1.color)) {
                            markersBorder.color = this$1.color;
                        } else {
                            markersBorder.color = new Color(markers.background).brightness(BORDER_BRIGHTNESS).toHex();
                        }
                    }
                    var shape = new ShapeElement({
                        type: markers.type,
                        width: markers.size,
                        height: markers.size,
                        rotation: markers.rotation,
                        background: markers.background,
                        border: markersBorder,
                        opacity: markers.opacity
                    });
                    shape.value = outlierValue;
                    elements.push(shape);
                }
                this.reflowOutliers(elements);
                return elements;
            },
            reflowOutliers: function (outliers) {
                var this$1 = this;
                var valueAxis = this.owner.seriesValueAxis(this.options);
                var center = this.box.center();
                for (var i = 0; i < outliers.length; i++) {
                    var outlierValue = outliers[i].value;
                    var markerBox = valueAxis.getSlot(outlierValue);
                    if (this$1.options.vertical) {
                        markerBox.move(center.x);
                    } else {
                        markerBox.move(undefined, center.y);
                    }
                    this$1.box = this$1.box.wrap(markerBox);
                    outliers[i].reflow(markerBox);
                }
            },
            mainVisual: function (options) {
                var group = Candlestick.fn.mainVisual.call(this, options);
                var outliers = this.renderOutliers(options);
                for (var i = 0; i < outliers.length; i++) {
                    var element = outliers[i].getElement();
                    if (element) {
                        group.append(element);
                    }
                }
                return group;
            },
            createLines: function (container, options) {
                this.drawLines(container, options, this.whiskerPoints, options.whiskers);
                this.drawLines(container, options, this.medianPoints, options.median);
                this.drawLines(container, options, this.meanPoints, options.mean);
            },
            getBorderColor: function () {
                if (this.color) {
                    return this.color;
                }
                return Candlestick.fn.getBorderColor.call(this);
            }
        });
        setDefaultOptions(BoxPlot, {
            border: { _brightness: 0.8 },
            line: { width: 2 },
            median: { color: '#f6f6f6' },
            mean: {
                width: 2,
                dashType: 'dash',
                color: '#f6f6f6'
            },
            overlay: { gradient: 'glass' },
            tooltip: { format: '<table>' + '<tr><th colspan=\'2\'>{6:d}</th></tr>' + '<tr><td>Lower:</td><td>{0:C}</td></tr>' + '<tr><td>Q1:</td><td>{1:C}</td></tr>' + '<tr><td>Median:</td><td>{2:C}</td></tr>' + '<tr><td>Mean:</td><td>{5:C}</td></tr>' + '<tr><td>Q3:</td><td>{3:C}</td></tr>' + '<tr><td>Upper:</td><td>{4:C}</td></tr>' + '</table>' },
            highlight: {
                opacity: 1,
                border: {
                    width: 1,
                    opacity: 1
                },
                line: {
                    width: 1,
                    opacity: 1
                }
            },
            notes: {
                visible: true,
                label: {}
            },
            outliers: {
                visible: true,
                size: LINE_MARKER_SIZE,
                type: datavizConstants.CROSS,
                background: WHITE,
                border: {
                    width: 2,
                    opacity: 1
                },
                opacity: 0
            },
            extremes: {
                visible: true,
                size: LINE_MARKER_SIZE,
                type: CIRCLE,
                background: WHITE,
                border: {
                    width: 2,
                    opacity: 1
                },
                opacity: 0
            }
        });
        deepExtend(BoxPlot.prototype, PointEventsMixin);
        var VerticalBoxPlot = BoxPlot.extend({
            reflowBoxSlot: function (box) {
                this.boxSlot.y1 = box.y1;
                this.boxSlot.y2 = box.y2;
            },
            reflowWhiskerSlot: function (box) {
                this.whiskerSlot.y1 = box.y1;
                this.whiskerSlot.y2 = box.y2;
            },
            calcMeanPoints: function (box, meanSlot) {
                return [[
                        [
                            meanSlot.x1,
                            box.y1
                        ],
                        [
                            meanSlot.x1,
                            box.y2
                        ]
                    ]];
            },
            calcWhiskerPoints: function (boxSlot, whiskerSlot) {
                var mid = whiskerSlot.center().y;
                return [
                    [
                        [
                            whiskerSlot.x1,
                            mid - 5
                        ],
                        [
                            whiskerSlot.x1,
                            mid + 5
                        ],
                        [
                            whiskerSlot.x1,
                            mid
                        ],
                        [
                            boxSlot.x1,
                            mid
                        ]
                    ],
                    [
                        [
                            whiskerSlot.x2,
                            mid - 5
                        ],
                        [
                            whiskerSlot.x2,
                            mid + 5
                        ],
                        [
                            whiskerSlot.x2,
                            mid
                        ],
                        [
                            boxSlot.x2,
                            mid
                        ]
                    ]
                ];
            },
            calcMedianPoints: function (box, medianSlot) {
                return [[
                        [
                            medianSlot.x1,
                            box.y1
                        ],
                        [
                            medianSlot.x1,
                            box.y2
                        ]
                    ]];
            }
        });
        var BoxPlotChart = CandlestickChart.extend({
            addValue: function (data, fields) {
                var categoryIx = fields.categoryIx;
                var category = fields.category;
                var series = fields.series;
                var seriesIx = fields.seriesIx;
                var ref = this;
                var children = ref.children;
                var options = ref.options;
                var value = data.valueFields;
                var valueParts = this.splitValue(value);
                var hasValue = areNumbers(valueParts);
                var dataItem = series.data[categoryIx];
                var categoryPoints = this.categoryPoints[categoryIx];
                var point;
                if (!categoryPoints) {
                    this.categoryPoints[categoryIx] = categoryPoints = [];
                }
                if (hasValue) {
                    point = this.createPoint(data, fields);
                }
                var cluster = children[categoryIx];
                if (!cluster) {
                    cluster = new ClusterLayout({
                        vertical: options.invertAxes,
                        gap: options.gap,
                        spacing: options.spacing
                    });
                    this.append(cluster);
                }
                if (point) {
                    this.updateRange(value, fields);
                    cluster.append(point);
                    point.categoryIx = categoryIx;
                    point.category = category;
                    point.series = series;
                    point.seriesIx = seriesIx;
                    point.owner = this;
                    point.dataItem = dataItem;
                }
                this.points.push(point);
                categoryPoints.push(point);
            },
            pointType: function () {
                if (this.options.invertAxes) {
                    return VerticalBoxPlot;
                }
                return BoxPlot;
            },
            splitValue: function (value) {
                return [
                    value.lower,
                    value.q1,
                    value.median,
                    value.q3,
                    value.upper
                ];
            },
            updateRange: function (value, fields) {
                var axisName = fields.series.axis;
                var axisRange = this.valueAxisRanges[axisName];
                var parts = this.splitValue(value).concat(this.filterOutliers(value.outliers));
                if (defined(value.mean)) {
                    parts = parts.concat(value.mean);
                }
                axisRange = this.valueAxisRanges[axisName] = axisRange || {
                    min: MAX_VALUE,
                    max: MIN_VALUE
                };
                axisRange = this.valueAxisRanges[axisName] = {
                    min: Math.min.apply(Math, parts.concat([axisRange.min])),
                    max: Math.max.apply(Math, parts.concat([axisRange.max]))
                };
            },
            formatPointValue: function (point, format) {
                var value = point.value;
                return this.chartService.format.auto(format, value.lower, value.q1, value.median, value.q3, value.upper, value.mean, point.category);
            },
            filterOutliers: function (items) {
                var length = (items || []).length;
                var result = [];
                for (var i = 0; i < length; i++) {
                    var item = items[i];
                    if (defined(item) && item !== null) {
                        result.push(item);
                    }
                }
                return result;
            }
        });
        var ScatterErrorBar = ErrorBarBase.extend({
            getAxis: function () {
                var axes = this.chart.seriesAxes(this.series);
                var axis = this.isVertical ? axes.y : axes.x;
                return axis;
            }
        });
        function hasValue(value) {
            return defined(value) && value !== null;
        }
        var ScatterChart = ChartElement.extend({
            init: function (plotArea, options) {
                ChartElement.fn.init.call(this, options);
                this.plotArea = plotArea;
                this.chartService = plotArea.chartService;
                this._initFields();
                this.render();
            },
            _initFields: function () {
                this.xAxisRanges = {};
                this.yAxisRanges = {};
                this.points = [];
                this.seriesPoints = [];
                this.seriesOptions = [];
                this._evalSeries = [];
            },
            render: function () {
                this.traverseDataPoints(this.addValue.bind(this));
            },
            addErrorBar: function (point, field, fields) {
                var value = point.value[field];
                var valueErrorField = field + 'Value';
                var lowField = field + 'ErrorLow';
                var highField = field + 'ErrorHigh';
                var seriesIx = fields.seriesIx;
                var series = fields.series;
                var errorBars = point.options.errorBars;
                var lowValue = fields[lowField];
                var highValue = fields[highField];
                if (isNumber(value)) {
                    var errorRange;
                    if (isNumber(lowValue) && isNumber(highValue)) {
                        errorRange = {
                            low: lowValue,
                            high: highValue
                        };
                    }
                    if (errorBars && defined(errorBars[valueErrorField])) {
                        this.seriesErrorRanges = this.seriesErrorRanges || {
                            x: [],
                            y: []
                        };
                        this.seriesErrorRanges[field][seriesIx] = this.seriesErrorRanges[field][seriesIx] || new ErrorRangeCalculator(errorBars[valueErrorField], series, field);
                        errorRange = this.seriesErrorRanges[field][seriesIx].getErrorRange(value, errorBars[valueErrorField]);
                    }
                    if (errorRange) {
                        this.addPointErrorBar(errorRange, point, field);
                    }
                }
            },
            addPointErrorBar: function (errorRange, point, field) {
                var low = errorRange.low;
                var high = errorRange.high;
                var series = point.series;
                var options = point.options.errorBars;
                var isVertical = field === Y;
                var item = {};
                point[field + 'Low'] = low;
                point[field + 'High'] = high;
                point.errorBars = point.errorBars || [];
                var errorBar = new ScatterErrorBar(low, high, isVertical, this, series, options);
                point.errorBars.push(errorBar);
                point.append(errorBar);
                item[field] = low;
                this.updateRange(item, series);
                item[field] = high;
                this.updateRange(item, series);
            },
            addValue: function (value, fields) {
                var x = value.x;
                var y = value.y;
                var seriesIx = fields.seriesIx;
                var series = this.options.series[seriesIx];
                var missingValues = this.seriesMissingValues(series);
                var seriesPoints = this.seriesPoints[seriesIx];
                var pointValue = value;
                if (!(hasValue(x) && hasValue(y))) {
                    pointValue = this.createMissingValue(pointValue, missingValues);
                }
                var point;
                if (pointValue) {
                    point = this.createPoint(pointValue, fields);
                    if (point) {
                        $.extend(point, fields);
                        this.addErrorBar(point, X, fields);
                        this.addErrorBar(point, Y, fields);
                    }
                    this.updateRange(pointValue, fields.series);
                }
                this.points.push(point);
                seriesPoints.push(point);
            },
            seriesMissingValues: function (series) {
                return series.missingValues;
            },
            createMissingValue: function () {
            },
            updateRange: function (value, series) {
                var intlService = this.chartService.intl;
                var xAxisName = series.xAxis;
                var yAxisName = series.yAxis;
                var x = value.x;
                var y = value.y;
                var xAxisRange = this.xAxisRanges[xAxisName];
                var yAxisRange = this.yAxisRanges[yAxisName];
                if (hasValue(x)) {
                    xAxisRange = this.xAxisRanges[xAxisName] = xAxisRange || {
                        min: MAX_VALUE,
                        max: MIN_VALUE
                    };
                    if (isString(x)) {
                        x = parseDate(intlService, x);
                    }
                    xAxisRange.min = Math.min(xAxisRange.min, x);
                    xAxisRange.max = Math.max(xAxisRange.max, x);
                }
                if (hasValue(y)) {
                    yAxisRange = this.yAxisRanges[yAxisName] = yAxisRange || {
                        min: MAX_VALUE,
                        max: MIN_VALUE
                    };
                    if (isString(y)) {
                        y = parseDate(intlService, y);
                    }
                    yAxisRange.min = Math.min(yAxisRange.min, y);
                    yAxisRange.max = Math.max(yAxisRange.max, y);
                }
            },
            evalPointOptions: function (options, value, fields) {
                var series = fields.series;
                var seriesIx = fields.seriesIx;
                var state = {
                    defaults: series._defaults,
                    excluded: [
                        'data',
                        'tooltip',
                        'template',
                        'visual',
                        'toggle',
                        '_outOfRangeMinPoint',
                        '_outOfRangeMaxPoint'
                    ]
                };
                var doEval = this._evalSeries[seriesIx];
                if (!defined(doEval)) {
                    this._evalSeries[seriesIx] = doEval = evalOptions(options, {}, state, true);
                }
                var pointOptions = options;
                if (doEval) {
                    pointOptions = deepExtend({}, options);
                    evalOptions(pointOptions, {
                        value: value,
                        series: series,
                        dataItem: fields.dataItem
                    }, state);
                }
                return pointOptions;
            },
            pointType: function () {
                return LinePoint;
            },
            pointOptions: function (series, seriesIx) {
                var options = this.seriesOptions[seriesIx];
                if (!options) {
                    var defaults = this.pointType().prototype.defaults;
                    this.seriesOptions[seriesIx] = options = deepExtend({}, defaults, {
                        markers: { opacity: series.opacity },
                        tooltip: { format: this.options.tooltip.format },
                        labels: { format: this.options.labels.format }
                    }, series);
                }
                return options;
            },
            createPoint: function (value, fields) {
                var series = fields.series;
                var pointOptions = this.pointOptions(series, fields.seriesIx);
                var color = fields.color || series.color;
                pointOptions = this.evalPointOptions(pointOptions, value, fields);
                if (isFunction(series.color)) {
                    color = pointOptions.color;
                }
                var point = new LinePoint(value, pointOptions);
                point.color = color;
                this.append(point);
                return point;
            },
            seriesAxes: function (series) {
                var xAxisName = series.xAxis;
                var yAxisName = series.yAxis;
                var plotArea = this.plotArea;
                var xAxis = xAxisName ? plotArea.namedXAxes[xAxisName] : plotArea.axisX;
                var yAxis = yAxisName ? plotArea.namedYAxes[yAxisName] : plotArea.axisY;
                if (!xAxis) {
                    throw new Error('Unable to locate X axis with name ' + xAxisName);
                }
                if (!yAxis) {
                    throw new Error('Unable to locate Y axis with name ' + yAxisName);
                }
                return {
                    x: xAxis,
                    y: yAxis
                };
            },
            reflow: function (targetBox) {
                var this$1 = this;
                var chartPoints = this.points;
                var limit = !this.options.clip;
                var pointIx = 0;
                this.traverseDataPoints(function (value, fields) {
                    var point = chartPoints[pointIx++];
                    var seriesAxes = this$1.seriesAxes(fields.series);
                    var slotX = seriesAxes.x.getSlot(value.x, value.x, limit);
                    var slotY = seriesAxes.y.getSlot(value.y, value.y, limit);
                    if (point) {
                        if (slotX && slotY) {
                            var pointSlot = this$1.pointSlot(slotX, slotY);
                            point.reflow(pointSlot);
                        } else {
                            point.visible = false;
                        }
                    }
                });
                this.box = targetBox;
            },
            pointSlot: function (slotX, slotY) {
                return new Box(slotX.x1, slotY.y1, slotX.x2, slotY.y2);
            },
            traverseDataPoints: function (callback) {
                var this$1 = this;
                var ref = this;
                var series = ref.options.series;
                var seriesPoints = ref.seriesPoints;
                for (var seriesIx = 0; seriesIx < series.length; seriesIx++) {
                    var currentSeries = series[seriesIx];
                    var currentSeriesPoints = seriesPoints[seriesIx];
                    if (!currentSeriesPoints) {
                        seriesPoints[seriesIx] = [];
                    }
                    for (var pointIx = 0; pointIx < currentSeries.data.length; pointIx++) {
                        var ref$1 = this$1._bindPoint(currentSeries, seriesIx, pointIx);
                        var value = ref$1.valueFields;
                        var fields = ref$1.fields;
                        callback(value, deepExtend({
                            pointIx: pointIx,
                            series: currentSeries,
                            seriesIx: seriesIx,
                            dataItem: currentSeries.data[pointIx],
                            owner: this$1
                        }, fields));
                    }
                }
            },
            formatPointValue: function (point, format) {
                var value = point.value;
                return this.chartService.format.auto(format, value.x, value.y);
            },
            animationPoints: function () {
                var points = this.points;
                var result = [];
                for (var idx = 0; idx < points.length; idx++) {
                    result.push((points[idx] || {}).marker);
                }
                return result;
            }
        });
        setDefaultOptions(ScatterChart, {
            series: [],
            tooltip: { format: '{0}, {1}' },
            labels: { format: '{0}, {1}' },
            clip: true
        });
        deepExtend(ScatterChart.prototype, ClipAnimationMixin, { _bindPoint: CategoricalChart.prototype._bindPoint });
        var Bubble = LinePoint.extend({
            init: function (value, options) {
                LinePoint.fn.init.call(this, value, options);
                this.category = value.category;
            },
            createHighlight: function () {
                var highlight = this.options.highlight;
                var border = highlight.border;
                var markers = this.options.markers;
                var center = this.box.center();
                var radius = (markers.size + markers.border.width + border.width) / 2;
                var highlightGroup = new Group();
                var shadow = new drawing.Circle(new geometry.Circle([
                    center.x,
                    center.y + radius / 5 + border.width / 2
                ], radius + border.width / 2), {
                    stroke: { color: 'none' },
                    fill: this.createGradient({
                        gradient: 'bubbleShadow',
                        color: markers.background,
                        stops: [
                            {
                                offset: 0,
                                color: markers.background,
                                opacity: 0.3
                            },
                            {
                                offset: 1,
                                color: markers.background,
                                opacity: 0
                            }
                        ]
                    })
                });
                var overlay = new drawing.Circle(new geometry.Circle([
                    center.x,
                    center.y
                ], radius), {
                    stroke: {
                        color: border.color || new Color(markers.background).brightness(BORDER_BRIGHTNESS).toHex(),
                        width: border.width,
                        opacity: border.opacity
                    },
                    fill: {
                        color: markers.background,
                        opacity: highlight.opacity
                    }
                });
                highlightGroup.append(shadow, overlay);
                return highlightGroup;
            }
        });
        Bubble.prototype.defaults = deepExtend({}, Bubble.prototype.defaults, {
            labels: { position: CENTER },
            highlight: {
                opacity: 1,
                border: {
                    color: '#fff',
                    width: 2,
                    opacity: 1
                }
            }
        });
        var BubbleChart = ScatterChart.extend({
            _initFields: function () {
                this._maxSize = MIN_VALUE;
                ScatterChart.fn._initFields.call(this);
            },
            addValue: function (value, fields) {
                if (value.size !== null && (value.size > 0 || value.size < 0 && fields.series.negativeValues.visible)) {
                    this._maxSize = Math.max(this._maxSize, Math.abs(value.size));
                    ScatterChart.fn.addValue.call(this, value, fields);
                } else {
                    this.points.push(null);
                    this.seriesPoints[fields.seriesIx].push(null);
                }
            },
            reflow: function (box) {
                this.updateBubblesSize(box);
                ScatterChart.fn.reflow.call(this, box);
            },
            pointType: function () {
                return Bubble;
            },
            createPoint: function (value, fields) {
                var series = fields.series;
                var pointsCount = series.data.length;
                var delay = fields.pointIx * (INITIAL_ANIMATION_DURATION / pointsCount);
                var animationOptions = {
                    delay: delay,
                    duration: INITIAL_ANIMATION_DURATION - delay,
                    type: BUBBLE
                };
                var color = fields.color || series.color;
                if (value.size < 0 && series.negativeValues.visible) {
                    color = valueOrDefault(series.negativeValues.color, color);
                }
                var pointOptions = deepExtend({
                    labels: {
                        animation: {
                            delay: delay,
                            duration: INITIAL_ANIMATION_DURATION - delay
                        }
                    }
                }, this.pointOptions(series, fields.seriesIx), {
                    markers: {
                        type: CIRCLE,
                        border: series.border,
                        opacity: series.opacity,
                        animation: animationOptions
                    }
                });
                pointOptions = this.evalPointOptions(pointOptions, value, fields);
                if (isFunction(series.color)) {
                    color = pointOptions.color;
                }
                pointOptions.markers.background = color;
                var point = new Bubble(value, pointOptions);
                point.color = color;
                this.append(point);
                return point;
            },
            updateBubblesSize: function (box) {
                var this$1 = this;
                var ref = this;
                var series = ref.options.series;
                var boxSize = Math.min(box.width(), box.height());
                for (var seriesIx = 0; seriesIx < series.length; seriesIx++) {
                    var currentSeries = series[seriesIx];
                    var seriesPoints = this$1.seriesPoints[seriesIx];
                    var minSize = currentSeries.minSize || Math.max(boxSize * 0.02, 10);
                    var maxSize = currentSeries.maxSize || boxSize * 0.2;
                    var minR = minSize / 2;
                    var maxR = maxSize / 2;
                    var minArea = Math.PI * minR * minR;
                    var maxArea = Math.PI * maxR * maxR;
                    var areaRange = maxArea - minArea;
                    var areaRatio = areaRange / this$1._maxSize;
                    for (var pointIx = 0; pointIx < seriesPoints.length; pointIx++) {
                        var point = seriesPoints[pointIx];
                        if (point) {
                            var area = Math.abs(point.value.size) * areaRatio;
                            var radius = Math.sqrt((minArea + area) / Math.PI);
                            var baseZIndex = valueOrDefault(point.options.zIndex, 0);
                            var zIndex = baseZIndex + (1 - radius / maxR);
                            deepExtend(point.options, {
                                zIndex: zIndex,
                                markers: {
                                    size: radius * 2,
                                    zIndex: zIndex
                                },
                                labels: { zIndex: zIndex + 1 }
                            });
                        }
                    }
                }
            },
            formatPointValue: function (point, format) {
                var value = point.value;
                return this.chartService.format.auto(format, value.x, value.y, value.size, point.category);
            },
            createAnimation: function () {
            },
            createVisual: function () {
            }
        });
        setDefaultOptions(BubbleChart, {
            tooltip: { format: '{3}' },
            labels: { format: '{3}' }
        });
        var Target = ShapeElement.extend({});
        deepExtend(Target.prototype, PointEventsMixin);
        var Bullet = ChartElement.extend({
            init: function (value, options) {
                ChartElement.fn.init.call(this, options);
                this.aboveAxis = this.options.aboveAxis;
                this.color = options.color || WHITE;
                this.value = value;
            },
            render: function () {
                var options = this.options;
                if (!this._rendered) {
                    this._rendered = true;
                    if (defined(this.value.target)) {
                        this.target = new Target({
                            type: options.target.shape,
                            background: options.target.color || this.color,
                            opacity: options.opacity,
                            zIndex: options.zIndex,
                            border: options.target.border,
                            vAlign: TOP,
                            align: RIGHT
                        });
                        this.target.value = this.value;
                        this.target.dataItem = this.dataItem;
                        this.target.series = this.series;
                        this.append(this.target);
                    }
                    this.createNote();
                }
            },
            reflow: function (box) {
                this.render();
                var ref = this;
                var options = ref.options;
                var target = ref.target;
                var chart = ref.owner;
                var invertAxes = options.invertAxes;
                var valueAxis = chart.seriesValueAxis(this.options);
                var categorySlot = chart.categorySlot(chart.categoryAxis, options.categoryIx, valueAxis);
                var targetValueSlot = valueAxis.getSlot(this.value.target);
                var targetSlotX = invertAxes ? targetValueSlot : categorySlot;
                var targetSlotY = invertAxes ? categorySlot : targetValueSlot;
                if (target) {
                    var targetSlot = new Box(targetSlotX.x1, targetSlotY.y1, targetSlotX.x2, targetSlotY.y2);
                    target.options.height = invertAxes ? targetSlot.height() : options.target.line.width;
                    target.options.width = invertAxes ? options.target.line.width : targetSlot.width();
                    target.reflow(targetSlot);
                }
                if (this.note) {
                    this.note.reflow(box);
                }
                this.box = box;
            },
            createVisual: function () {
                ChartElement.fn.createVisual.call(this);
                var options = this.options;
                var body = Path.fromRect(this.box.toRect(), {
                    fill: {
                        color: this.color,
                        opacity: options.opacity
                    },
                    stroke: null
                });
                if (options.border.width > 0) {
                    body.options.set('stroke', {
                        color: options.border.color || this.color,
                        width: options.border.width,
                        dashType: options.border.dashType,
                        opacity: valueOrDefault(options.border.opacity, options.opacity)
                    });
                }
                this.bodyVisual = body;
                alignPathToPixel(body);
                this.visual.append(body);
            },
            createAnimation: function () {
                if (this.bodyVisual) {
                    this.animation = Animation.create(this.bodyVisual, this.options.animation);
                }
            },
            createHighlight: function (style) {
                return Path.fromRect(this.box.toRect(), style);
            },
            highlightVisual: function () {
                return this.bodyVisual;
            },
            highlightVisualArgs: function () {
                return {
                    rect: this.box.toRect(),
                    visual: this.bodyVisual,
                    options: this.options
                };
            },
            formatValue: function (format) {
                return this.owner.formatPointValue(this, format);
            }
        });
        Bullet.prototype.tooltipAnchor = Bar.prototype.tooltipAnchor;
        setDefaultOptions(Bullet, {
            border: { width: 1 },
            vertical: false,
            opacity: 1,
            target: {
                shape: '',
                border: {
                    width: 0,
                    color: 'green'
                },
                line: { width: 2 }
            },
            tooltip: { format: 'Current: {0}<br />Target: {1}' }
        });
        deepExtend(Bullet.prototype, PointEventsMixin);
        deepExtend(Bullet.prototype, NoteMixin);
        var BulletChart = CategoricalChart.extend({
            init: function (plotArea, options) {
                wrapData(options);
                CategoricalChart.fn.init.call(this, plotArea, options);
            },
            reflowCategories: function (categorySlots) {
                var children = this.children;
                var childrenLength = children.length;
                for (var i = 0; i < childrenLength; i++) {
                    children[i].reflow(categorySlots[i]);
                }
            },
            plotRange: function (point) {
                var series = point.series;
                var valueAxis = this.seriesValueAxis(series);
                var axisCrossingValue = this.categoryAxisCrossingValue(valueAxis);
                return [
                    axisCrossingValue,
                    point.value.current || axisCrossingValue
                ];
            },
            createPoint: function (data, fields) {
                var categoryIx = fields.categoryIx;
                var category = fields.category;
                var series = fields.series;
                var seriesIx = fields.seriesIx;
                var ref = this;
                var options = ref.options;
                var children = ref.children;
                var value = data.valueFields;
                var bulletOptions = deepExtend({
                    vertical: !options.invertAxes,
                    overlay: series.overlay,
                    categoryIx: categoryIx,
                    invertAxes: options.invertAxes
                }, series);
                var color = data.fields.color || series.color;
                bulletOptions = this.evalPointOptions(bulletOptions, value, category, categoryIx, series, seriesIx);
                if (isFunction(series.color)) {
                    color = bulletOptions.color;
                }
                var bullet = new Bullet(value, bulletOptions);
                bullet.color = color;
                var cluster = children[categoryIx];
                if (!cluster) {
                    cluster = new ClusterLayout({
                        vertical: options.invertAxes,
                        gap: options.gap,
                        spacing: options.spacing
                    });
                    this.append(cluster);
                }
                cluster.append(bullet);
                return bullet;
            },
            updateRange: function (value, fields) {
                var current = value.current;
                var target = value.target;
                var axisName = fields.series.axis;
                var axisRange = this.valueAxisRanges[axisName];
                if (defined(current) && !isNaN(current) && defined(target && !isNaN(target))) {
                    axisRange = this.valueAxisRanges[axisName] = axisRange || {
                        min: MAX_VALUE,
                        max: MIN_VALUE
                    };
                    axisRange.min = Math.min(axisRange.min, current, target);
                    axisRange.max = Math.max(axisRange.max, current, target);
                }
            },
            formatPointValue: function (point, format) {
                return this.chartService.format.auto(format, point.value.current, point.value.target);
            },
            pointValue: function (data) {
                return data.valueFields.current;
            },
            aboveAxis: function (point) {
                var value = point.value.current;
                return value > 0;
            },
            createAnimation: function () {
                var this$1 = this;
                var points = this.points;
                this._setAnimationOptions();
                for (var idx = 0; idx < points.length; idx++) {
                    var point = points[idx];
                    point.options.animation = this$1.options.animation;
                    point.createAnimation();
                }
            }
        });
        BulletChart.prototype._setAnimationOptions = BarChart.prototype._setAnimationOptions;
        setDefaultOptions(BulletChart, { animation: { type: BAR } });
        function wrapData(options) {
            var series = options.series;
            for (var i = 0; i < series.length; i++) {
                var seriesItem = series[i];
                var data = seriesItem.data;
                if (data && !isArray(data[0]) && !isObject(data[0])) {
                    seriesItem.data = [data];
                }
            }
        }
        var BaseTooltip = Class.extend({
            init: function (chartService, options) {
                this.chartService = chartService;
                this.options = deepExtend({}, this.options, options);
            },
            getStyle: function (options, point) {
                var background = options.background;
                var border = options.border.color;
                if (point) {
                    var pointColor = point.color || point.options.color;
                    background = valueOrDefault(background, pointColor);
                    border = valueOrDefault(border, pointColor);
                }
                var padding = getSpacing(options.padding || {}, 'auto');
                return {
                    backgroundColor: background,
                    borderColor: border,
                    font: options.font,
                    color: options.color,
                    opacity: options.opacity,
                    borderWidth: styleValue(options.border.width),
                    paddingTop: styleValue(padding.top),
                    paddingBottom: styleValue(padding.bottom),
                    paddingLeft: styleValue(padding.left),
                    paddingRight: styleValue(padding.right)
                };
            },
            show: function (options, tooltipOptions, point) {
                options.format = tooltipOptions.format;
                var style = this.getStyle(tooltipOptions, point);
                options.style = style;
                if (!defined(tooltipOptions.color) && new Color(style.backgroundColor).percBrightness() > 180) {
                    options.className = 'k-chart-tooltip-inverse';
                }
                this.chartService.notify(SHOW_TOOLTIP, options);
            },
            hide: function () {
                if (this.chartService) {
                    this.chartService.notify(HIDE_TOOLTIP);
                }
            },
            destroy: function () {
                delete this.chartService;
            }
        });
        setDefaultOptions(BaseTooltip, {
            border: { width: 1 },
            opacity: 1
        });
        var CrosshairTooltip = BaseTooltip.extend({
            init: function (chartService, crosshair, options) {
                BaseTooltip.fn.init.call(this, chartService, options);
                this.crosshair = crosshair;
                this.formatService = chartService.format;
                this.initAxisName();
            },
            initAxisName: function () {
                var axis = this.crosshair.axis;
                var plotArea = axis.plotArea;
                var name;
                if (plotArea.categoryAxis) {
                    name = axis.getCategory ? 'categoryAxis' : 'valueAxis';
                } else {
                    name = axis.options.vertical ? 'yAxis' : 'xAxis';
                }
                this.axisName = name;
            },
            showAt: function (point) {
                var ref = this;
                var axis = ref.crosshair.axis;
                var options = ref.options;
                var value = axis[options.stickyMode ? 'getCategory' : 'getValue'](point);
                var formattedValue = value;
                if (options.format) {
                    formattedValue = this.formatService.auto(options.format, value);
                } else if (axis.options.type === DATE) {
                    formattedValue = this.formatService.auto(axis.options.labels.dateFormats[axis.options.baseUnit], value);
                }
                this.show({
                    point: point,
                    anchor: this.getAnchor(),
                    crosshair: this.crosshair,
                    value: formattedValue,
                    axisName: this.axisName,
                    axisIndex: this.crosshair.axis.axisIndex
                }, this.options);
            },
            hide: function () {
                this.chartService.notify(HIDE_TOOLTIP, {
                    crosshair: this.crosshair,
                    axisName: this.axisName,
                    axisIndex: this.crosshair.axis.axisIndex
                });
            },
            getAnchor: function () {
                var ref = this;
                var crosshair = ref.crosshair;
                var ref_options = ref.options;
                var position = ref_options.position;
                var padding = ref_options.padding;
                var vertical = !crosshair.axis.options.vertical;
                var lineBox = crosshair.line.bbox();
                var horizontalAlign, verticalAlign, point;
                if (vertical) {
                    horizontalAlign = CENTER;
                    if (position === BOTTOM) {
                        verticalAlign = TOP;
                        point = lineBox.bottomLeft().translate(0, padding);
                    } else {
                        verticalAlign = BOTTOM;
                        point = lineBox.topLeft().translate(0, -padding);
                    }
                } else {
                    verticalAlign = CENTER;
                    if (position === LEFT) {
                        horizontalAlign = RIGHT;
                        point = lineBox.topLeft().translate(-padding, 0);
                    } else {
                        horizontalAlign = LEFT;
                        point = lineBox.topRight().translate(padding, 0);
                    }
                }
                return {
                    point: point,
                    align: {
                        horizontal: horizontalAlign,
                        vertical: verticalAlign
                    }
                };
            }
        });
        setDefaultOptions(CrosshairTooltip, { padding: 10 });
        var Crosshair = ChartElement.extend({
            init: function (chartService, axis, options) {
                ChartElement.fn.init.call(this, options);
                this.axis = axis;
                this.stickyMode = axis instanceof CategoryAxis;
                var tooltipOptions = this.options.tooltip;
                if (tooltipOptions.visible) {
                    this.tooltip = new CrosshairTooltip(chartService, this, deepExtend({}, tooltipOptions, { stickyMode: this.stickyMode }));
                }
            },
            showAt: function (point) {
                this.point = point;
                this.moveLine();
                this.line.visible(true);
                if (this.tooltip) {
                    this.tooltip.showAt(point);
                }
            },
            hide: function () {
                this.line.visible(false);
                if (this.tooltip) {
                    this.tooltip.hide();
                }
            },
            moveLine: function () {
                var ref = this;
                var axis = ref.axis;
                var point = ref.point;
                var vertical = axis.options.vertical;
                var box = this.getBox();
                var dim = vertical ? Y : X;
                var lineStart = new GeometryPoint(box.x1, box.y1);
                var lineEnd;
                if (vertical) {
                    lineEnd = new GeometryPoint(box.x2, box.y1);
                } else {
                    lineEnd = new GeometryPoint(box.x1, box.y2);
                }
                if (point) {
                    if (this.stickyMode) {
                        var slot = axis.getSlot(axis.pointCategoryIndex(point));
                        lineStart[dim] = lineEnd[dim] = slot.center()[dim];
                    } else {
                        lineStart[dim] = lineEnd[dim] = point[dim];
                    }
                }
                this.box = box;
                this.line.moveTo(lineStart).lineTo(lineEnd);
            },
            getBox: function () {
                var axis = this.axis;
                var axes = axis.pane.axes;
                var length = axes.length;
                var vertical = axis.options.vertical;
                var box = axis.lineBox().clone();
                var dim = vertical ? X : Y;
                var axisLineBox;
                for (var i = 0; i < length; i++) {
                    var currentAxis = axes[i];
                    if (currentAxis.options.vertical !== vertical) {
                        if (!axisLineBox) {
                            axisLineBox = currentAxis.lineBox().clone();
                        } else {
                            axisLineBox.wrap(currentAxis.lineBox());
                        }
                    }
                }
                box[dim + 1] = axisLineBox[dim + 1];
                box[dim + 2] = axisLineBox[dim + 2];
                return box;
            },
            createVisual: function () {
                ChartElement.fn.createVisual.call(this);
                var options = this.options;
                this.line = new Path({
                    stroke: {
                        color: options.color,
                        width: options.width,
                        opacity: options.opacity,
                        dashType: options.dashType
                    },
                    visible: false
                });
                this.moveLine();
                this.visual.append(this.line);
            },
            destroy: function () {
                if (this.tooltip) {
                    this.tooltip.destroy();
                }
                ChartElement.fn.destroy.call(this);
            }
        });
        setDefaultOptions(Crosshair, {
            color: BLACK,
            width: 2,
            zIndex: -1,
            tooltip: { visible: false }
        });
        var ChartContainer = ChartElement.extend({
            init: function (options, pane) {
                ChartElement.fn.init.call(this, options);
                this.pane = pane;
            },
            shouldClip: function () {
                var children = this.children;
                var length = children.length;
                for (var i = 0; i < length; i++) {
                    if (children[i].options.clip === true) {
                        return true;
                    }
                }
                return false;
            },
            _clipBox: function () {
                return this.pane.chartsBox();
            },
            createVisual: function () {
                this.visual = new Group({ zIndex: 0 });
                if (this.shouldClip()) {
                    var clipBox = this.clipBox = this._clipBox();
                    var clipRect = clipBox.toRect();
                    var clipPath = Path.fromRect(clipRect);
                    this.visual.clip(clipPath);
                    this.unclipLabels();
                }
            },
            stackRoot: function () {
                return this;
            },
            unclipLabels: function () {
                var ref = this;
                var charts = ref.children;
                var clipBox = ref.clipBox;
                for (var i = 0; i < charts.length; i++) {
                    var points = charts[i].points || {};
                    var length = points.length;
                    for (var j = 0; j < length; j++) {
                        var point = points[j];
                        if (point && point.overlapsBox && point.overlapsBox(clipBox)) {
                            var label = point.label;
                            var note = point.note;
                            if (label && label.options.visible) {
                                if (label.alignToClipBox) {
                                    label.alignToClipBox(clipBox);
                                }
                                label.options.noclip = true;
                            }
                            if (note && note.options.visible) {
                                note.options.noclip = true;
                            }
                        }
                    }
                }
            },
            destroy: function () {
                ChartElement.fn.destroy.call(this);
                delete this.parent;
            }
        });
        ChartContainer.prototype.isStackRoot = true;
        var Pane = BoxElement.extend({
            init: function (options) {
                BoxElement.fn.init.call(this, options);
                this.id = paneID();
                this.createTitle();
                this.content = new ChartElement();
                this.chartContainer = new ChartContainer({}, this);
                this.append(this.content);
                this.axes = [];
                this.charts = [];
            },
            createTitle: function () {
                var titleOptions = this.options.title;
                if (isObject(titleOptions)) {
                    titleOptions = deepExtend({}, titleOptions, {
                        align: titleOptions.position,
                        position: TOP
                    });
                }
                this.title = dataviz.Title.buildTitle(titleOptions, this, Pane.prototype.options.title);
            },
            appendAxis: function (axis) {
                this.content.append(axis);
                this.axes.push(axis);
                axis.pane = this;
            },
            appendChart: function (chart) {
                if (this.chartContainer.parent !== this.content) {
                    this.content.append(this.chartContainer);
                }
                this.charts.push(chart);
                this.chartContainer.append(chart);
                chart.pane = this;
            },
            empty: function () {
                var this$1 = this;
                var plotArea = this.parent;
                if (plotArea) {
                    for (var i = 0; i < this.axes.length; i++) {
                        plotArea.removeAxis(this$1.axes[i]);
                    }
                    for (var i$1 = 0; i$1 < this.charts.length; i$1++) {
                        plotArea.removeChart(this$1.charts[i$1]);
                    }
                }
                this.axes = [];
                this.charts = [];
                this.content.destroy();
                this.content.children = [];
                this.chartContainer.children = [];
            },
            reflow: function (targetBox) {
                var content;
                if (last(this.children) === this.content) {
                    content = this.children.pop();
                }
                BoxElement.fn.reflow.call(this, targetBox);
                if (content) {
                    this.children.push(content);
                }
                if (this.title) {
                    this.contentBox.y1 += this.title.box.height();
                }
            },
            visualStyle: function () {
                var style = BoxElement.fn.visualStyle.call(this);
                style.zIndex = -10;
                return style;
            },
            renderComplete: function () {
                if (this.options.visible) {
                    this.createGridLines();
                }
            },
            stackRoot: function () {
                return this;
            },
            clipRoot: function () {
                return this;
            },
            createGridLines: function () {
                var axes = this.axes;
                var allAxes = axes.concat(this.parent.axes);
                var vGridLines = [];
                var hGridLines = [];
                for (var i = 0; i < axes.length; i++) {
                    var axis = axes[i];
                    var vertical = axis.options.vertical;
                    var gridLines = vertical ? vGridLines : hGridLines;
                    for (var j = 0; j < allAxes.length; j++) {
                        if (gridLines.length === 0) {
                            var altAxis = allAxes[j];
                            if (vertical !== altAxis.options.vertical) {
                                append(gridLines, axis.createGridLines(altAxis));
                            }
                        }
                    }
                }
            },
            refresh: function () {
                this.visual.clear();
                this.content.parent = null;
                this.content.createGradient = this.createGradient.bind(this);
                this.content.renderVisual();
                this.content.parent = this;
                if (this.title) {
                    this.visual.append(this.title.visual);
                }
                this.visual.append(this.content.visual);
                this.renderComplete();
            },
            chartsBox: function () {
                var axes = this.axes;
                var length = axes.length;
                var chartsBox = new Box();
                for (var idx = 0; idx < length; idx++) {
                    var axis = axes[idx];
                    var axisValueField = axis.options.vertical ? Y : X;
                    var lineBox = axis.lineBox();
                    chartsBox[axisValueField + 1] = lineBox[axisValueField + 1];
                    chartsBox[axisValueField + 2] = lineBox[axisValueField + 2];
                }
                if (chartsBox.x2 === 0) {
                    var allAxes = this.parent.axes;
                    var length$1 = allAxes.length;
                    for (var idx$1 = 0; idx$1 < length$1; idx$1++) {
                        var axis$1 = allAxes[idx$1];
                        if (!axis$1.options.vertical) {
                            var lineBox$1 = axis$1.lineBox();
                            chartsBox.x1 = lineBox$1.x1;
                            chartsBox.x2 = lineBox$1.x2;
                        }
                    }
                }
                return chartsBox;
            },
            clipBox: function () {
                return this.chartContainer.clipBox;
            }
        });
        var ID = 1;
        function paneID() {
            return 'pane' + ID++;
        }
        Pane.prototype.isStackRoot = true;
        setDefaultOptions(Pane, {
            zIndex: -1,
            shrinkToFit: true,
            title: { align: LEFT },
            visible: true
        });
        var PlotAreaBase = ChartElement.extend({
            init: function (series, options, chartService) {
                ChartElement.fn.init.call(this, options);
                this.initFields(series, options);
                this.series = series;
                this.initSeries();
                this.charts = [];
                this.options.legend.items = [];
                this.axes = [];
                this.crosshairs = [];
                this.chartService = chartService;
                this.createPanes();
                this.render();
                this.createCrosshairs();
            },
            initFields: function () {
            },
            initSeries: function () {
                var series = this.series;
                for (var i = 0; i < series.length; i++) {
                    series[i].index = i;
                }
            },
            createPanes: function () {
                var this$1 = this;
                var defaults = { title: { color: (this.options.title || {}).color } };
                var panes = [];
                var paneOptions = this.options.panes || [];
                var panesLength = Math.max(paneOptions.length, 1);
                function setTitle(options, defaults) {
                    if (isString(options.title)) {
                        options.title = { text: options.title };
                    }
                    options.title = deepExtend({}, defaults.title, options.title);
                }
                for (var i = 0; i < panesLength; i++) {
                    var options = paneOptions[i] || {};
                    setTitle(options, defaults);
                    var currentPane = new Pane(options);
                    currentPane.paneIndex = i;
                    panes.push(currentPane);
                    this$1.append(currentPane);
                }
                this.panes = panes;
            },
            createCrosshairs: function (panes) {
                var this$1 = this;
                if (panes === void 0) {
                    panes = this.panes;
                }
                for (var i = 0; i < panes.length; i++) {
                    var pane = panes[i];
                    for (var j = 0; j < pane.axes.length; j++) {
                        var axis = pane.axes[j];
                        if (axis.options.crosshair && axis.options.crosshair.visible) {
                            var currentCrosshair = new Crosshair(this$1.chartService, axis, axis.options.crosshair);
                            this$1.crosshairs.push(currentCrosshair);
                            pane.content.append(currentCrosshair);
                        }
                    }
                }
            },
            removeCrosshairs: function (pane) {
                var crosshairs = this.crosshairs;
                var axes = pane.axes;
                for (var i = crosshairs.length - 1; i >= 0; i--) {
                    for (var j = 0; j < axes.length; j++) {
                        if (crosshairs[i].axis === axes[j]) {
                            crosshairs.splice(i, 1);
                            break;
                        }
                    }
                }
            },
            hideCrosshairs: function () {
                var crosshairs = this.crosshairs;
                for (var idx = 0; idx < crosshairs.length; idx++) {
                    crosshairs[idx].hide();
                }
            },
            findPane: function (name) {
                var panes = this.panes;
                var matchingPane;
                for (var i = 0; i < panes.length; i++) {
                    if (panes[i].options.name === name) {
                        matchingPane = panes[i];
                        break;
                    }
                }
                return matchingPane || panes[0];
            },
            findPointPane: function (point) {
                var panes = this.panes;
                var matchingPane;
                for (var i = 0; i < panes.length; i++) {
                    if (panes[i].box.containsPoint(point)) {
                        matchingPane = panes[i];
                        break;
                    }
                }
                return matchingPane;
            },
            appendAxis: function (axis) {
                var pane = this.findPane(axis.options.pane);
                pane.appendAxis(axis);
                this.axes.push(axis);
                axis.plotArea = this;
            },
            removeAxis: function (axisToRemove) {
                var this$1 = this;
                var filteredAxes = [];
                for (var i = 0; i < this.axes.length; i++) {
                    var axis = this$1.axes[i];
                    if (axisToRemove !== axis) {
                        filteredAxes.push(axis);
                    } else {
                        axis.destroy();
                    }
                }
                this.axes = filteredAxes;
            },
            appendChart: function (chart, pane) {
                this.charts.push(chart);
                if (pane) {
                    pane.appendChart(chart);
                } else {
                    this.append(chart);
                }
            },
            removeChart: function (chartToRemove) {
                var this$1 = this;
                var filteredCharts = [];
                for (var i = 0; i < this.charts.length; i++) {
                    var chart = this$1.charts[i];
                    if (chart !== chartToRemove) {
                        filteredCharts.push(chart);
                    } else {
                        chart.destroy();
                    }
                }
                this.charts = filteredCharts;
            },
            addToLegend: function (series) {
                var count = series.length;
                var legend = this.options.legend;
                var labels = legend.labels || {};
                var inactiveItems = legend.inactiveItems || {};
                var inactiveItemsLabels = inactiveItems.labels || {};
                var data = [];
                for (var i = 0; i < count; i++) {
                    var currentSeries = series[i];
                    var seriesVisible = currentSeries.visible !== false;
                    if (currentSeries.visibleInLegend === false) {
                        continue;
                    }
                    var text = currentSeries.name || '';
                    var labelTemplate = seriesVisible ? labels.template : inactiveItemsLabels.template || labels.template;
                    if (labelTemplate) {
                        text = TemplateService.compile(labelTemplate)({
                            text: text,
                            series: currentSeries
                        });
                    }
                    var defaults = currentSeries._defaults;
                    var color = currentSeries.color;
                    if (isFunction(color) && defaults) {
                        color = defaults.color;
                    }
                    var itemLabelOptions = void 0, markerColor = void 0;
                    if (seriesVisible) {
                        itemLabelOptions = {};
                        markerColor = color;
                    } else {
                        itemLabelOptions = {
                            color: inactiveItemsLabels.color,
                            font: inactiveItemsLabels.font
                        };
                        markerColor = inactiveItems.markers.color;
                    }
                    if (text) {
                        data.push({
                            text: text,
                            labels: itemLabelOptions,
                            markerColor: markerColor,
                            series: currentSeries,
                            active: seriesVisible
                        });
                    }
                }
                append(legend.items, data);
            },
            groupAxes: function (panes) {
                var xAxes = [];
                var yAxes = [];
                for (var paneIx = 0; paneIx < panes.length; paneIx++) {
                    var paneAxes = panes[paneIx].axes;
                    for (var axisIx = 0; axisIx < paneAxes.length; axisIx++) {
                        var axis = paneAxes[axisIx];
                        if (axis.options.vertical) {
                            yAxes.push(axis);
                        } else {
                            xAxes.push(axis);
                        }
                    }
                }
                return {
                    x: xAxes,
                    y: yAxes,
                    any: xAxes.concat(yAxes)
                };
            },
            groupSeriesByPane: function () {
                var this$1 = this;
                var series = this.series;
                var seriesByPane = {};
                for (var i = 0; i < series.length; i++) {
                    var currentSeries = series[i];
                    var pane = this$1.seriesPaneName(currentSeries);
                    if (seriesByPane[pane]) {
                        seriesByPane[pane].push(currentSeries);
                    } else {
                        seriesByPane[pane] = [currentSeries];
                    }
                }
                return seriesByPane;
            },
            filterVisibleSeries: function (series) {
                var result = [];
                for (var i = 0; i < series.length; i++) {
                    var currentSeries = series[i];
                    if (currentSeries.visible !== false) {
                        result.push(currentSeries);
                    }
                }
                return result;
            },
            reflow: function (targetBox) {
                var options = this.options.plotArea;
                var panes = this.panes;
                var margin = getSpacing(options.margin);
                this.box = targetBox.clone().unpad(margin);
                this.reflowPanes();
                this.reflowAxes(panes);
                this.reflowCharts(panes);
            },
            redraw: function (panes) {
                var this$1 = this;
                var panesArray = [].concat(panes);
                this.initSeries();
                for (var i = 0; i < panesArray.length; i++) {
                    this$1.removeCrosshairs(panesArray[i]);
                    panesArray[i].empty();
                }
                this.render(panesArray);
                this.reflowAxes(this.panes);
                this.reflowCharts(panesArray);
                this.createCrosshairs(panesArray);
                for (var i$1 = 0; i$1 < panesArray.length; i$1++) {
                    panesArray[i$1].refresh();
                }
            },
            axisCrossingValues: function (axis, crossingAxes) {
                var options = axis.options;
                var crossingValues = [].concat(options.axisCrossingValues || options.axisCrossingValue);
                var valuesToAdd = crossingAxes.length - crossingValues.length;
                var defaultValue = crossingValues[0] || 0;
                for (var i = 0; i < valuesToAdd; i++) {
                    crossingValues.push(defaultValue);
                }
                return crossingValues;
            },
            alignAxisTo: function (axis, targetAxis, crossingValue, targetCrossingValue) {
                var slot = axis.getSlot(crossingValue, crossingValue, true);
                var slotEdge = axis.options.reverse ? 2 : 1;
                var targetSlot = targetAxis.getSlot(targetCrossingValue, targetCrossingValue, true);
                var targetEdge = targetAxis.options.reverse ? 2 : 1;
                var axisBox = axis.box.translate(targetSlot[X + targetEdge] - slot[X + slotEdge], targetSlot[Y + targetEdge] - slot[Y + slotEdge]);
                if (axis.pane !== targetAxis.pane) {
                    axisBox.translate(0, axis.pane.box.y1 - targetAxis.pane.box.y1);
                }
                axis.reflow(axisBox);
            },
            alignAxes: function (xAxes, yAxes) {
                var this$1 = this;
                var xAnchor = xAxes[0];
                var yAnchor = yAxes[0];
                var xAnchorCrossings = this.axisCrossingValues(xAnchor, yAxes);
                var yAnchorCrossings = this.axisCrossingValues(yAnchor, xAxes);
                var leftAnchors = {};
                var rightAnchors = {};
                var topAnchors = {};
                var bottomAnchors = {};
                for (var i = 0; i < yAxes.length; i++) {
                    var axis = yAxes[i];
                    var pane = axis.pane;
                    var paneId = pane.id;
                    var anchor = paneAnchor(xAxes, pane) || xAnchor;
                    var anchorCrossings = xAnchorCrossings;
                    if (anchor !== xAnchor) {
                        anchorCrossings = this$1.axisCrossingValues(anchor, yAxes);
                    }
                    this$1.alignAxisTo(axis, anchor, yAnchorCrossings[i], anchorCrossings[i]);
                    if (axis.options._overlap) {
                        continue;
                    }
                    if (round(axis.lineBox().x1) === round(anchor.lineBox().x1)) {
                        if (leftAnchors[paneId]) {
                            axis.reflow(axis.box.alignTo(leftAnchors[paneId].box, LEFT).translate(-axis.options.margin, 0));
                        }
                        leftAnchors[paneId] = axis;
                    }
                    if (round(axis.lineBox().x2) === round(anchor.lineBox().x2)) {
                        if (!axis._mirrored) {
                            axis.options.labels.mirror = !axis.options.labels.mirror;
                            axis._mirrored = true;
                        }
                        this$1.alignAxisTo(axis, anchor, yAnchorCrossings[i], anchorCrossings[i]);
                        if (rightAnchors[paneId]) {
                            axis.reflow(axis.box.alignTo(rightAnchors[paneId].box, RIGHT).translate(axis.options.margin, 0));
                        }
                        rightAnchors[paneId] = axis;
                    }
                    if (i !== 0 && yAnchor.pane === axis.pane) {
                        axis.alignTo(yAnchor);
                        axis.reflow(axis.box);
                    }
                }
                for (var i$1 = 0; i$1 < xAxes.length; i$1++) {
                    var axis$1 = xAxes[i$1];
                    var pane$1 = axis$1.pane;
                    var paneId$1 = pane$1.id;
                    var anchor$1 = paneAnchor(yAxes, pane$1) || yAnchor;
                    var anchorCrossings$1 = yAnchorCrossings;
                    if (anchor$1 !== yAnchor) {
                        anchorCrossings$1 = this$1.axisCrossingValues(anchor$1, xAxes);
                    }
                    this$1.alignAxisTo(axis$1, anchor$1, xAnchorCrossings[i$1], anchorCrossings$1[i$1]);
                    if (axis$1.options._overlap) {
                        continue;
                    }
                    if (round(axis$1.lineBox().y1) === round(anchor$1.lineBox().y1)) {
                        if (!axis$1._mirrored) {
                            axis$1.options.labels.mirror = !axis$1.options.labels.mirror;
                            axis$1._mirrored = true;
                        }
                        this$1.alignAxisTo(axis$1, anchor$1, xAnchorCrossings[i$1], anchorCrossings$1[i$1]);
                        if (topAnchors[paneId$1]) {
                            axis$1.reflow(axis$1.box.alignTo(topAnchors[paneId$1].box, TOP).translate(0, -axis$1.options.margin));
                        }
                        topAnchors[paneId$1] = axis$1;
                    }
                    if (round(axis$1.lineBox().y2, datavizConstants.COORD_PRECISION) === round(anchor$1.lineBox().y2, datavizConstants.COORD_PRECISION)) {
                        if (bottomAnchors[paneId$1]) {
                            axis$1.reflow(axis$1.box.alignTo(bottomAnchors[paneId$1].box, BOTTOM).translate(0, axis$1.options.margin));
                        }
                        bottomAnchors[paneId$1] = axis$1;
                    }
                    if (i$1 !== 0) {
                        axis$1.alignTo(xAnchor);
                        axis$1.reflow(axis$1.box);
                    }
                }
            },
            shrinkAxisWidth: function (panes) {
                var axes = this.groupAxes(panes).any;
                var axisBox = axisGroupBox(axes);
                var overflowX = 0;
                for (var i = 0; i < panes.length; i++) {
                    var currentPane = panes[i];
                    if (currentPane.axes.length > 0) {
                        overflowX = Math.max(overflowX, axisBox.width() - currentPane.contentBox.width());
                    }
                }
                if (overflowX !== 0) {
                    for (var i$1 = 0; i$1 < axes.length; i$1++) {
                        var currentAxis = axes[i$1];
                        if (!currentAxis.options.vertical) {
                            currentAxis.reflow(currentAxis.box.shrink(overflowX, 0));
                        }
                    }
                }
            },
            shrinkAxisHeight: function (panes) {
                var shrinked;
                for (var i = 0; i < panes.length; i++) {
                    var currentPane = panes[i];
                    var axes = currentPane.axes;
                    var overflowY = Math.max(0, axisGroupBox(axes).height() - currentPane.contentBox.height());
                    if (overflowY !== 0) {
                        for (var j = 0; j < axes.length; j++) {
                            var currentAxis = axes[j];
                            if (currentAxis.options.vertical) {
                                currentAxis.reflow(currentAxis.box.shrink(0, overflowY));
                            }
                        }
                        shrinked = true;
                    }
                }
                return shrinked;
            },
            fitAxes: function (panes) {
                var axes = this.groupAxes(panes).any;
                var offsetX = 0;
                for (var i = 0; i < panes.length; i++) {
                    var currentPane = panes[i];
                    var paneAxes = currentPane.axes;
                    var paneBox = currentPane.contentBox;
                    if (paneAxes.length > 0) {
                        var axisBox = axisGroupBox(paneAxes);
                        var offsetY = Math.max(paneBox.y1 - axisBox.y1, paneBox.y2 - axisBox.y2);
                        offsetX = Math.max(offsetX, paneBox.x1 - axisBox.x1);
                        for (var j = 0; j < paneAxes.length; j++) {
                            var currentAxis = paneAxes[j];
                            currentAxis.reflow(currentAxis.box.translate(0, offsetY));
                        }
                    }
                }
                for (var i$1 = 0; i$1 < axes.length; i$1++) {
                    var currentAxis$1 = axes[i$1];
                    currentAxis$1.reflow(currentAxis$1.box.translate(offsetX, 0));
                }
            },
            reflowAxes: function (panes) {
                var this$1 = this;
                var axes = this.groupAxes(panes);
                for (var i = 0; i < panes.length; i++) {
                    this$1.reflowPaneAxes(panes[i]);
                }
                if (axes.x.length > 0 && axes.y.length > 0) {
                    this.alignAxes(axes.x, axes.y);
                    this.shrinkAxisWidth(panes);
                    this.autoRotateAxisLabels(axes);
                    this.alignAxes(axes.x, axes.y);
                    if (this.shrinkAxisWidth(panes)) {
                        this.alignAxes(axes.x, axes.y);
                    }
                    this.shrinkAxisHeight(panes);
                    this.alignAxes(axes.x, axes.y);
                    if (this.shrinkAxisHeight(panes)) {
                        this.alignAxes(axes.x, axes.y);
                    }
                    this.fitAxes(panes);
                }
            },
            autoRotateAxisLabels: function (groupedAxes) {
                var this$1 = this;
                var ref = this;
                var axes = ref.axes;
                var panes = ref.panes;
                var rotated;
                for (var idx = 0; idx < axes.length; idx++) {
                    var axis = axes[idx];
                    if (axis.autoRotateLabels()) {
                        rotated = true;
                    }
                }
                if (rotated) {
                    for (var idx$1 = 0; idx$1 < panes.length; idx$1++) {
                        this$1.reflowPaneAxes(panes[idx$1]);
                    }
                    if (groupedAxes.x.length > 0 && groupedAxes.y.length > 0) {
                        this.alignAxes(groupedAxes.x, groupedAxes.y);
                        this.shrinkAxisWidth(panes);
                    }
                }
            },
            reflowPaneAxes: function (pane) {
                var axes = pane.axes;
                var length = axes.length;
                if (length > 0) {
                    for (var i = 0; i < length; i++) {
                        axes[i].reflow(pane.contentBox);
                    }
                }
            },
            reflowCharts: function (panes) {
                var charts = this.charts;
                var count = charts.length;
                var box = this.box;
                for (var i = 0; i < count; i++) {
                    var chartPane = charts[i].pane;
                    if (!chartPane || inArray(chartPane, panes)) {
                        charts[i].reflow(box);
                    }
                }
            },
            reflowPanes: function () {
                var ref = this;
                var box = ref.box;
                var panes = ref.panes;
                var panesLength = panes.length;
                var remainingHeight = box.height();
                var remainingPanes = panesLength;
                var autoHeightPanes = 0;
                var top = box.y1;
                for (var i = 0; i < panesLength; i++) {
                    var currentPane = panes[i];
                    var height = currentPane.options.height;
                    currentPane.options.width = box.width();
                    if (!currentPane.options.height) {
                        autoHeightPanes++;
                    } else {
                        if (height.indexOf && height.indexOf('%')) {
                            var percents = parseInt(height, 10) / 100;
                            currentPane.options.height = percents * box.height();
                        }
                        currentPane.reflow(box.clone());
                        remainingHeight -= currentPane.options.height;
                    }
                }
                for (var i$1 = 0; i$1 < panesLength; i$1++) {
                    var currentPane$1 = panes[i$1];
                    if (!currentPane$1.options.height) {
                        currentPane$1.options.height = remainingHeight / autoHeightPanes;
                    }
                }
                for (var i$2 = 0; i$2 < panesLength; i$2++) {
                    var currentPane$2 = panes[i$2];
                    var paneBox = box.clone().move(box.x1, top);
                    currentPane$2.reflow(paneBox);
                    remainingPanes--;
                    top += currentPane$2.options.height;
                }
            },
            backgroundBox: function () {
                var axes = this.axes;
                var axesCount = axes.length;
                var box;
                for (var i = 0; i < axesCount; i++) {
                    var axisA = axes[i];
                    for (var j = 0; j < axesCount; j++) {
                        var axisB = axes[j];
                        if (axisA.options.vertical !== axisB.options.vertical) {
                            var lineBox = axisA.lineBox().clone().wrap(axisB.lineBox());
                            if (!box) {
                                box = lineBox;
                            } else {
                                box = box.wrap(lineBox);
                            }
                        }
                    }
                }
                return box || this.box;
            },
            chartsBoxes: function () {
                var panes = this.panes;
                var boxes = [];
                for (var idx = 0; idx < panes.length; idx++) {
                    boxes.push(panes[idx].chartsBox());
                }
                return boxes;
            },
            addBackgroundPaths: function (multipath) {
                var boxes = this.chartsBoxes();
                for (var idx = 0; idx < boxes.length; idx++) {
                    multipath.paths.push(Path.fromRect(boxes[idx].toRect()));
                }
            },
            backgroundContainsPoint: function (point) {
                var boxes = this.chartsBoxes();
                for (var idx = 0; idx < boxes.length; idx++) {
                    if (boxes[idx].containsPoint(point)) {
                        return true;
                    }
                }
            },
            createVisual: function () {
                ChartElement.fn.createVisual.call(this);
                var options = this.options.plotArea;
                var opacity = options.opacity;
                var background = options.background;
                var border = options.border;
                if (border === void 0) {
                    border = {};
                }
                if (isTransparent(background)) {
                    background = WHITE;
                    opacity = 0;
                }
                var bg = this._bgVisual = new drawing.MultiPath({
                    fill: {
                        color: background,
                        opacity: opacity
                    },
                    stroke: {
                        color: border.width ? border.color : '',
                        width: border.width,
                        dashType: border.dashType
                    },
                    zIndex: -1
                });
                this.addBackgroundPaths(bg);
                this.appendVisual(bg);
            },
            pointsByCategoryIndex: function (categoryIndex) {
                var charts = this.charts;
                var result = [];
                if (categoryIndex !== null) {
                    for (var i = 0; i < charts.length; i++) {
                        var chart = charts[i];
                        if (chart.pane.options.name === '_navigator') {
                            continue;
                        }
                        var points = charts[i].categoryPoints[categoryIndex];
                        if (points && points.length) {
                            for (var j = 0; j < points.length; j++) {
                                var point = points[j];
                                if (point && defined(point.value) && point.value !== null) {
                                    result.push(point);
                                }
                            }
                        }
                    }
                }
                return result;
            },
            pointsBySeriesIndex: function (seriesIndex) {
                return this.filterPoints(function (point) {
                    return point.series.index === seriesIndex;
                });
            },
            pointsBySeriesName: function (name) {
                return this.filterPoints(function (point) {
                    return point.series.name === name;
                });
            },
            filterPoints: function (callback) {
                var charts = this.charts;
                var result = [];
                for (var i = 0; i < charts.length; i++) {
                    var chart = charts[i];
                    var points = chart.points;
                    for (var j = 0; j < points.length; j++) {
                        var point = points[j];
                        if (point && callback(point)) {
                            result.push(point);
                        }
                    }
                }
                return result;
            },
            findPoint: function (callback) {
                var charts = this.charts;
                for (var i = 0; i < charts.length; i++) {
                    var chart = charts[i];
                    var points = chart.points;
                    for (var j = 0; j < points.length; j++) {
                        var point = points[j];
                        if (point && callback(point)) {
                            return point;
                        }
                    }
                }
            },
            paneByPoint: function (point) {
                var panes = this.panes;
                for (var i = 0; i < panes.length; i++) {
                    var pane = panes[i];
                    if (pane.box.containsPoint(point)) {
                        return pane;
                    }
                }
            }
        });
        function axisGroupBox(axes) {
            var length = axes.length;
            var box;
            if (length > 0) {
                for (var i = 0; i < length; i++) {
                    var axisBox = axes[i].contentBox();
                    if (!box) {
                        box = axisBox.clone();
                    } else {
                        box.wrap(axisBox);
                    }
                }
            }
            return box || new Box();
        }
        function paneAnchor(axes, pane) {
            for (var i = 0; i < axes.length; i++) {
                var anchor = axes[i];
                if (anchor && anchor.pane === pane) {
                    return anchor;
                }
            }
        }
        function isTransparent(color) {
            return color === '' || color === null || color === 'none' || color === 'transparent' || !defined(color);
        }
        setDefaultOptions(PlotAreaBase, {
            series: [],
            plotArea: { margin: {} },
            background: '',
            border: {
                color: BLACK,
                width: 0
            },
            legend: {
                inactiveItems: {
                    labels: { color: '#919191' },
                    markers: { color: '#919191' }
                }
            }
        });
        var PlotAreaEventsMixin = {
            hover: function (chart, e) {
                this._dispatchEvent(chart, e, PLOT_AREA_HOVER);
            },
            click: function (chart, e) {
                this._dispatchEvent(chart, e, PLOT_AREA_CLICK);
            }
        };
        var SeriesAggregator = Class.extend({
            init: function (series, binder, defaultAggregates) {
                var canonicalFields = binder.canonicalFields(series);
                var valueFields = binder.valueFields(series);
                var sourceFields = binder.sourceFields(series, canonicalFields);
                var seriesFields = this._seriesFields = [];
                var defaults = defaultAggregates.query(series.type);
                var rootAggregate = series.aggregate || defaults;
                this._series = series;
                this._binder = binder;
                for (var i = 0; i < canonicalFields.length; i++) {
                    var field = canonicalFields[i];
                    var fieldAggregate = void 0;
                    if (isObject(rootAggregate)) {
                        fieldAggregate = rootAggregate[field];
                    } else if (i === 0 || inArray(field, valueFields)) {
                        fieldAggregate = rootAggregate;
                    } else {
                        break;
                    }
                    if (fieldAggregate) {
                        seriesFields.push({
                            canonicalName: field,
                            name: sourceFields[i],
                            transform: isFunction(fieldAggregate) ? fieldAggregate : Aggregates[fieldAggregate]
                        });
                    }
                }
            },
            aggregatePoints: function (srcPoints, group) {
                var this$1 = this;
                var ref = this;
                var series = ref._series;
                var seriesFields = ref._seriesFields;
                var data = this._bindPoints(srcPoints || []);
                var firstDataItem = data.dataItems[0];
                var result = {};
                if (firstDataItem && !isNumber(firstDataItem) && !isArray(firstDataItem)) {
                    var fn = function () {
                    };
                    fn.prototype = firstDataItem;
                    result = new fn();
                }
                for (var i = 0; i < seriesFields.length; i++) {
                    var field = seriesFields[i];
                    var srcValues = this$1._bindField(data.values, field.canonicalName);
                    var value = field.transform(srcValues, series, data.dataItems, group);
                    if (value !== null && isObject(value) && !defined(value.length) && !(value instanceof Date)) {
                        result = value;
                        break;
                    } else {
                        if (defined(value)) {
                            setValue(field.name, result, value);
                        }
                    }
                }
                return result;
            },
            _bindPoints: function (points) {
                var ref = this;
                var binder = ref._binder;
                var series = ref._series;
                var values = [];
                var dataItems = [];
                for (var i = 0; i < points.length; i++) {
                    var pointIx = points[i];
                    values.push(binder.bindPoint(series, pointIx));
                    dataItems.push(series.data[pointIx]);
                }
                return {
                    values: values,
                    dataItems: dataItems
                };
            },
            _bindField: function (data, field) {
                var values = [];
                var count = data.length;
                for (var i = 0; i < count; i++) {
                    var item = data[i];
                    var valueFields = item.valueFields;
                    var value = void 0;
                    if (defined(valueFields[field])) {
                        value = valueFields[field];
                    } else {
                        value = item.fields[field];
                    }
                    values.push(value);
                }
                return values;
            }
        });
        function setValue(fieldName, target, value) {
            var parentObj = target;
            var field = fieldName;
            if (fieldName.indexOf('.') > -1) {
                var parts = fieldName.split('.');
                while (parts.length > 1) {
                    field = parts.shift();
                    if (!defined(parentObj[field])) {
                        parentObj[field] = {};
                    }
                    parentObj = parentObj[field];
                }
                field = parts.shift();
            }
            parentObj[field] = value;
        }
        var DefaultAggregates = Class.extend({
            init: function () {
                this._defaults = {};
            },
            register: function (seriesTypes, aggregates) {
                var this$1 = this;
                for (var i = 0; i < seriesTypes.length; i++) {
                    this$1._defaults[seriesTypes[i]] = aggregates;
                }
            },
            query: function (seriesType) {
                return this._defaults[seriesType];
            }
        });
        DefaultAggregates.current = new DefaultAggregates();
        var RangeBar = Bar.extend({
            createLabel: function () {
                var labels = this.options.labels;
                var fromOptions = deepExtend({}, labels, labels.from);
                var toOptions = deepExtend({}, labels, labels.to);
                if (fromOptions.visible) {
                    this.labelFrom = this._createLabel(fromOptions);
                    this.append(this.labelFrom);
                }
                if (toOptions.visible) {
                    this.labelTo = this._createLabel(toOptions);
                    this.append(this.labelTo);
                }
            },
            _createLabel: function (options) {
                var labelText;
                if (options.template) {
                    var labelTemplate = TemplateService.compile(options.template);
                    labelText = labelTemplate({
                        dataItem: this.dataItem,
                        category: this.category,
                        value: this.value,
                        percentage: this.percentage,
                        runningTotal: this.runningTotal,
                        total: this.total,
                        series: this.series
                    });
                } else {
                    labelText = this.formatValue(options.format);
                }
                return new BarLabel(labelText, deepExtend({ vertical: this.options.vertical }, options));
            },
            reflow: function (targetBox) {
                this.render();
                var ref = this;
                var labelFrom = ref.labelFrom;
                var labelTo = ref.labelTo;
                var value = ref.value;
                this.box = targetBox;
                if (labelFrom) {
                    labelFrom.options.aboveAxis = value.from > value.to;
                    labelFrom.reflow(targetBox);
                }
                if (labelTo) {
                    labelTo.options.aboveAxis = value.to > value.from;
                    labelTo.reflow(targetBox);
                }
                if (this.note) {
                    this.note.reflow(targetBox);
                }
            }
        });
        RangeBar.prototype.defaults = deepExtend({}, RangeBar.prototype.defaults, {
            labels: { format: '{0} - {1}' },
            tooltip: { format: '{1}' }
        });
        var RangeBarChart = BarChart.extend({
            pointType: function () {
                return RangeBar;
            },
            pointValue: function (data) {
                return data.valueFields;
            },
            formatPointValue: function (point, format) {
                if (point.value.from === null && point.value.to === null) {
                    return '';
                }
                return this.chartService.format.auto(format, point.value.from, point.value.to);
            },
            plotRange: function (point) {
                if (!point) {
                    return 0;
                }
                return [
                    point.value.from,
                    point.value.to
                ];
            },
            updateRange: function (value, fields) {
                var axisName = fields.series.axis;
                var from = value.from;
                var to = value.to;
                var axisRange = this.valueAxisRanges[axisName];
                if (value !== null && isNumber(from) && isNumber(to)) {
                    axisRange = this.valueAxisRanges[axisName] = axisRange || {
                        min: MAX_VALUE,
                        max: MIN_VALUE
                    };
                    axisRange.min = Math.min(axisRange.min, from);
                    axisRange.max = Math.max(axisRange.max, from);
                    axisRange.min = Math.min(axisRange.min, to);
                    axisRange.max = Math.max(axisRange.max, to);
                }
            },
            aboveAxis: function (point) {
                var value = point.value;
                return value.from < value.to;
            }
        });
        RangeBarChart.prototype.plotLimits = CategoricalChart.prototype.plotLimits;
        var OHLCPoint = Candlestick.extend({
            reflow: function (box) {
                var ref = this;
                var options = ref.options;
                var value = ref.value;
                var chart = ref.owner;
                var valueAxis = chart.seriesValueAxis(options);
                var oPoints = [];
                var cPoints = [];
                var lhPoints = [];
                var lhSlot = valueAxis.getSlot(value.low, value.high);
                var oSlot = valueAxis.getSlot(value.open, value.open);
                var cSlot = valueAxis.getSlot(value.close, value.close);
                oSlot.x1 = cSlot.x1 = lhSlot.x1 = box.x1;
                oSlot.x2 = cSlot.x2 = lhSlot.x2 = box.x2;
                var mid = lhSlot.center().x;
                oPoints.push([
                    oSlot.x1,
                    oSlot.y1
                ]);
                oPoints.push([
                    mid,
                    oSlot.y1
                ]);
                cPoints.push([
                    mid,
                    cSlot.y1
                ]);
                cPoints.push([
                    cSlot.x2,
                    cSlot.y1
                ]);
                lhPoints.push([
                    mid,
                    lhSlot.y1
                ]);
                lhPoints.push([
                    mid,
                    lhSlot.y2
                ]);
                this.lines = [
                    oPoints,
                    cPoints,
                    lhPoints
                ];
                this.box = lhSlot.clone().wrap(oSlot.clone().wrap(cSlot));
                this.reflowNote();
            },
            createBody: function () {
            }
        });
        var OHLCChart = CandlestickChart.extend({
            pointType: function () {
                return OHLCPoint;
            }
        });
        var WaterfallSegment = ChartElement.extend({
            init: function (from, to, series) {
                ChartElement.fn.init.call(this);
                this.from = from;
                this.to = to;
                this.series = series;
            },
            linePoints: function () {
                var from = this.from;
                var ref = this;
                var fromBox = ref.from.box;
                var toBox = ref.to.box;
                var points = [];
                if (from.isVertical) {
                    var y = from.aboveAxis ? fromBox.y1 : fromBox.y2;
                    points.push([
                        fromBox.x1,
                        y
                    ], [
                        toBox.x2,
                        y
                    ]);
                } else {
                    var x = from.aboveAxis ? fromBox.x2 : fromBox.x1;
                    points.push([
                        x,
                        fromBox.y1
                    ], [
                        x,
                        toBox.y2
                    ]);
                }
                return points;
            },
            createVisual: function () {
                ChartElement.fn.createVisual.call(this);
                var line = this.series.line || {};
                var path = Path.fromPoints(this.linePoints(), {
                    stroke: {
                        color: line.color,
                        width: line.width,
                        opacity: line.opacity,
                        dashType: line.dashType
                    }
                });
                alignPathToPixel(path);
                this.visual.append(path);
            }
        });
        setDefaultOptions(WaterfallSegment, {
            animation: {
                type: FADEIN,
                delay: INITIAL_ANIMATION_DURATION
            }
        });
        var WaterfallChart = BarChart.extend({
            render: function () {
                BarChart.fn.render.call(this);
                this.createSegments();
            },
            traverseDataPoints: function (callback) {
                var series = this.options.series;
                var categories = this.categoryAxis.options.categories || [];
                var totalCategories = categoriesCount(series);
                var isVertical = !this.options.invertAxes;
                for (var seriesIx = 0; seriesIx < series.length; seriesIx++) {
                    var currentSeries = series[seriesIx];
                    var total = 0;
                    var runningTotal = 0;
                    for (var categoryIx = 0; categoryIx < totalCategories; categoryIx++) {
                        var data = SeriesBinder.current.bindPoint(currentSeries, categoryIx);
                        var value = data.valueFields.value;
                        var summary = data.fields.summary;
                        var from = total;
                        var to = void 0;
                        if (summary) {
                            if (summary.toLowerCase() === 'total') {
                                data.valueFields.value = total;
                                from = 0;
                                to = total;
                            } else {
                                data.valueFields.value = runningTotal;
                                to = from - runningTotal;
                                runningTotal = 0;
                            }
                        } else if (isNumber(value)) {
                            runningTotal += value;
                            total += value;
                            to = total;
                        }
                        callback(data, {
                            category: categories[categoryIx],
                            categoryIx: categoryIx,
                            series: currentSeries,
                            seriesIx: seriesIx,
                            total: total,
                            runningTotal: runningTotal,
                            from: from,
                            to: to,
                            isVertical: isVertical
                        });
                    }
                }
            },
            updateRange: function (value, fields) {
                BarChart.fn.updateRange.call(this, { value: fields.to }, fields);
            },
            aboveAxis: function (point) {
                return point.value >= 0;
            },
            plotRange: function (point) {
                return [
                    point.from,
                    point.to
                ];
            },
            createSegments: function () {
                var this$1 = this;
                var series = this.options.series;
                var seriesPoints = this.seriesPoints;
                var segments = this.segments = [];
                for (var seriesIx = 0; seriesIx < series.length; seriesIx++) {
                    var currentSeries = series[seriesIx];
                    var points = seriesPoints[seriesIx];
                    if (points) {
                        var prevPoint = void 0;
                        for (var pointIx = 0; pointIx < points.length; pointIx++) {
                            var point = points[pointIx];
                            if (point && prevPoint) {
                                var segment = new WaterfallSegment(prevPoint, point, currentSeries);
                                segments.push(segment);
                                this$1.append(segment);
                            }
                            prevPoint = point;
                        }
                    }
                }
            }
        });
        function filterSeriesByType(series, types) {
            var result = [];
            var seriesTypes = [].concat(types);
            for (var idx = 0; idx < series.length; idx++) {
                var currentSeries = series[idx];
                if (inArray(currentSeries.type, seriesTypes)) {
                    result.push(currentSeries);
                }
            }
            return result;
        }
        function equalsIgnoreCase(a, b) {
            if (a && b) {
                return a.toLowerCase() === b.toLowerCase();
            }
            return a === b;
        }
        function isDateAxis(axisOptions, sampleCategory) {
            var type = axisOptions.type;
            var dateCategory = sampleCategory instanceof Date;
            return !type && dateCategory || equalsIgnoreCase(type, DATE);
        }
        function appendIfNotNull(array, element) {
            if (element !== null) {
                array.push(element);
            }
        }
        function singleItemOrArray(array) {
            return array.length === 1 ? array[0] : array;
        }
        function getDateField(field, row, intlService) {
            if (row === null) {
                return row;
            }
            var key = '_date_' + field;
            var value = row[key];
            if (!value) {
                value = parseDate(intlService, getter(field, true)(row));
                row[key] = value;
            }
            return value;
        }
        var CategoricalPlotArea = PlotAreaBase.extend({
            initFields: function (series) {
                var this$1 = this;
                this.namedCategoryAxes = {};
                this.namedValueAxes = {};
                this.valueAxisRangeTracker = new AxisGroupRangeTracker();
                if (series.length > 0) {
                    this.invertAxes = inArray(series[0].type, [
                        BAR,
                        BULLET,
                        VERTICAL_LINE,
                        VERTICAL_AREA,
                        RANGE_BAR,
                        HORIZONTAL_WATERFALL,
                        VERTICAL_BOX_PLOT
                    ]);
                    for (var i = 0; i < series.length; i++) {
                        var stack = series[i].stack;
                        if (stack && stack.type === '100%') {
                            this$1.stack100 = true;
                            break;
                        }
                    }
                }
            },
            render: function (panes) {
                if (panes === void 0) {
                    panes = this.panes;
                }
                this.createCategoryAxes(panes);
                this.aggregateCategories(panes);
                this.createCategoryAxesLabels(panes);
                this.createCharts(panes);
                this.createValueAxes(panes);
            },
            removeAxis: function (axis) {
                var axisName = axis.options.name;
                PlotAreaBase.fn.removeAxis.call(this, axis);
                if (axis instanceof CategoryAxis) {
                    delete this.namedCategoryAxes[axisName];
                } else {
                    this.valueAxisRangeTracker.reset(axisName);
                    delete this.namedValueAxes[axisName];
                }
                if (axis === this.categoryAxis) {
                    delete this.categoryAxis;
                }
                if (axis === this.valueAxis) {
                    delete this.valueAxis;
                }
            },
            createCharts: function (panes) {
                var this$1 = this;
                var seriesByPane = this.groupSeriesByPane();
                for (var i = 0; i < panes.length; i++) {
                    var pane = panes[i];
                    var paneSeries = seriesByPane[pane.options.name || 'default'] || [];
                    this$1.addToLegend(paneSeries);
                    var visibleSeries = this$1.filterVisibleSeries(paneSeries);
                    if (!visibleSeries) {
                        continue;
                    }
                    var groups = this$1.groupSeriesByCategoryAxis(visibleSeries);
                    for (var groupIx = 0; groupIx < groups.length; groupIx++) {
                        this$1.createChartGroup(groups[groupIx], pane);
                    }
                }
            },
            createChartGroup: function (series, pane) {
                this.createAreaChart(filterSeriesByType(series, [
                    AREA,
                    VERTICAL_AREA
                ]), pane);
                this.createBarChart(filterSeriesByType(series, [
                    COLUMN,
                    BAR
                ]), pane);
                this.createRangeBarChart(filterSeriesByType(series, [
                    RANGE_COLUMN,
                    RANGE_BAR
                ]), pane);
                this.createBulletChart(filterSeriesByType(series, [
                    BULLET,
                    VERTICAL_BULLET
                ]), pane);
                this.createCandlestickChart(filterSeriesByType(series, CANDLESTICK), pane);
                this.createBoxPlotChart(filterSeriesByType(series, [
                    BOX_PLOT,
                    VERTICAL_BOX_PLOT
                ]), pane);
                this.createOHLCChart(filterSeriesByType(series, OHLC), pane);
                this.createWaterfallChart(filterSeriesByType(series, [
                    WATERFALL,
                    HORIZONTAL_WATERFALL
                ]), pane);
                this.createLineChart(filterSeriesByType(series, [
                    LINE,
                    VERTICAL_LINE
                ]), pane);
            },
            aggregateCategories: function (panes) {
                var this$1 = this;
                var series = this.srcSeries || this.series;
                var processedSeries = [];
                for (var i = 0; i < series.length; i++) {
                    var currentSeries = series[i];
                    var categoryAxis = this$1.seriesCategoryAxis(currentSeries);
                    var axisPane = this$1.findPane(categoryAxis.options.pane);
                    var dateAxis = equalsIgnoreCase(categoryAxis.options.type, DATE);
                    if ((dateAxis || currentSeries.categoryField) && inArray(axisPane, panes)) {
                        currentSeries = this$1.aggregateSeries(currentSeries, categoryAxis);
                    } else if (isNumber(categoryAxis.options.min) || isNumber(categoryAxis.options.max)) {
                        currentSeries = this$1.filterSeries(currentSeries, categoryAxis);
                    }
                    processedSeries.push(currentSeries);
                }
                this.srcSeries = series;
                this.series = processedSeries;
            },
            filterSeries: function (series, categoryAxis) {
                var range = categoryAxis.totalRangeIndices();
                var justified = categoryAxis.options.justified;
                var outOfRangePoints = inArray(series.type, [
                    LINE,
                    VERTICAL_LINE,
                    AREA,
                    VERTICAL_AREA
                ]);
                range.min = isNumber(categoryAxis.options.min) ? Math.floor(range.min) : 0;
                if (isNumber(categoryAxis.options.max)) {
                    range.max = justified ? Math.floor(range.max) + 1 : Math.ceil(range.max);
                } else {
                    range.max = series.data.length;
                }
                var currentSeries = deepExtend({}, series);
                if (outOfRangePoints) {
                    var minCategory = range.min - 1;
                    var srcCategories = categoryAxis.options.srcCategories || [];
                    if (minCategory >= 0 && minCategory < currentSeries.data.length) {
                        currentSeries._outOfRangeMinPoint = {
                            item: currentSeries.data[minCategory],
                            category: srcCategories[minCategory],
                            categoryIx: -1
                        };
                    }
                    if (range.max < currentSeries.data.length) {
                        currentSeries._outOfRangeMaxPoint = {
                            item: currentSeries.data[range.max],
                            category: srcCategories[range.max],
                            categoryIx: range.max - range.min
                        };
                    }
                }
                categoryAxis._seriesMax = Math.max(categoryAxis._seriesMax || 0, currentSeries.data.length);
                currentSeries.data = (currentSeries.data || []).slice(range.min, range.max);
                return currentSeries;
            },
            aggregateSeries: function (series, categoryAxis) {
                var this$1 = this;
                var outOfRangePoints = inArray(series.type, [
                    LINE,
                    VERTICAL_LINE,
                    AREA,
                    VERTICAL_AREA
                ]);
                var ref = categoryAxis.options;
                var categories = ref.categories;
                var srcCategories = ref.srcCategories;
                if (srcCategories === void 0) {
                    srcCategories = categories;
                }
                var dataItems = ref.dataItems;
                if (dataItems === void 0) {
                    dataItems = [];
                }
                var dateAxis = equalsIgnoreCase(categoryAxis.options.type, DATE);
                var aggregatorSeries = deepExtend({}, series);
                var result = deepExtend({}, series);
                var srcData = series.data;
                var srcPoints = [];
                var outOfRangeMinIdx = MIN_VALUE;
                var outOfRangeMaxIdx = MAX_VALUE;
                var getFn = getField;
                var outOfRangeMinCategory, outOfRangeMaxCategory;
                if (dateAxis) {
                    getFn = getDateField;
                }
                for (var i = 0; i < srcData.length; i++) {
                    var category = void 0;
                    if (series.categoryField) {
                        category = getFn(series.categoryField, srcData[i], this$1.chartService.intl);
                    } else {
                        category = srcCategories[i];
                    }
                    if (defined(category)) {
                        var categoryIx = categoryAxis.categoryIndex(category);
                        if (0 <= categoryIx && categoryIx < categories.length) {
                            srcPoints[categoryIx] = srcPoints[categoryIx] || [];
                            srcPoints[categoryIx].push(i);
                        } else if (outOfRangePoints) {
                            if (categoryIx < 0) {
                                if (categoryIx === outOfRangeMinIdx) {
                                    outOfRangeMinCategory.points.push(i);
                                } else if (categoryIx > outOfRangeMinIdx) {
                                    outOfRangeMinIdx = categoryIx;
                                    outOfRangeMinCategory = {
                                        category: category,
                                        points: [i]
                                    };
                                }
                            } else if (categoryIx >= categories.length) {
                                if (categoryIx === outOfRangeMaxIdx) {
                                    outOfRangeMaxCategory.points.push(i);
                                } else if (categoryIx < outOfRangeMaxIdx) {
                                    outOfRangeMaxIdx = categoryIx;
                                    outOfRangeMaxCategory = {
                                        category: category,
                                        points: [i]
                                    };
                                }
                            }
                        }
                    }
                }
                var aggregator = new SeriesAggregator(aggregatorSeries, SeriesBinder.current, DefaultAggregates.current);
                var data = result.data = [];
                for (var i$1 = 0; i$1 < categories.length; i$1++) {
                    data[i$1] = aggregator.aggregatePoints(srcPoints[i$1], categories[i$1]);
                    if (srcPoints[i$1]) {
                        dataItems[i$1] = data[i$1];
                    }
                }
                if (outOfRangeMinCategory && data.length) {
                    result._outOfRangeMinPoint = {
                        item: aggregator.aggregatePoints(outOfRangeMinCategory.points, outOfRangeMinCategory.category),
                        categoryIx: outOfRangeMinIdx,
                        category: outOfRangeMinCategory.category
                    };
                }
                if (outOfRangeMaxCategory && data.length) {
                    result._outOfRangeMaxPoint = {
                        item: aggregator.aggregatePoints(outOfRangeMaxCategory.points, outOfRangeMaxCategory.category),
                        categoryIx: outOfRangeMaxIdx,
                        category: outOfRangeMaxCategory.category
                    };
                }
                categoryAxis.options.dataItems = dataItems;
                return result;
            },
            appendChart: function (chart, pane) {
                var series = chart.options.series;
                var categoryAxis = this.seriesCategoryAxis(series[0]);
                var categories = categoryAxis.options.categories;
                var categoriesToAdd = Math.max(0, categoriesCount(series) - categories.length);
                while (categoriesToAdd--) {
                    categories.push('');
                }
                this.valueAxisRangeTracker.update(chart.valueAxisRanges);
                PlotAreaBase.fn.appendChart.call(this, chart, pane);
            },
            seriesPaneName: function (series) {
                var options = this.options;
                var axisName = series.axis;
                var axisOptions = [].concat(options.valueAxis);
                var axis = grep(axisOptions, function (a) {
                    return a.name === axisName;
                })[0];
                var panes = options.panes || [{}];
                var defaultPaneName = (panes[0] || {}).name || 'default';
                var paneName = (axis || {}).pane || defaultPaneName;
                return paneName;
            },
            seriesCategoryAxis: function (series) {
                var axisName = series.categoryAxis;
                var axis = axisName ? this.namedCategoryAxes[axisName] : this.categoryAxis;
                if (!axis) {
                    throw new Error('Unable to locate category axis with name ' + axisName);
                }
                return axis;
            },
            stackableChartOptions: function (firstSeries, pane) {
                var stack = firstSeries.stack;
                var isStacked100 = stack && stack.type === '100%';
                var clip = pane.options.clip;
                return {
                    isStacked: stack,
                    isStacked100: isStacked100,
                    clip: clip
                };
            },
            groupSeriesByCategoryAxis: function (series) {
                var categoryAxes = [];
                var unique = {};
                for (var idx = 0; idx < series.length; idx++) {
                    var name = series[idx].categoryAxis || '$$default$$';
                    if (!unique.hasOwnProperty(name)) {
                        unique[name] = true;
                        categoryAxes.push(name);
                    }
                }
                var groups = [];
                for (var axisIx = 0; axisIx < categoryAxes.length; axisIx++) {
                    var axis = categoryAxes[axisIx];
                    var axisSeries = groupSeries(series, axis, axisIx);
                    if (axisSeries.length === 0) {
                        continue;
                    }
                    groups.push(axisSeries);
                }
                return groups;
            },
            createBarChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var barChart = new BarChart(this, $.extend({
                    series: series,
                    invertAxes: this.invertAxes,
                    gap: firstSeries.gap,
                    spacing: firstSeries.spacing
                }, this.stackableChartOptions(firstSeries, pane)));
                this.appendChart(barChart, pane);
            },
            createRangeBarChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var rangeColumnChart = new RangeBarChart(this, {
                    series: series,
                    invertAxes: this.invertAxes,
                    gap: firstSeries.gap,
                    spacing: firstSeries.spacing
                });
                this.appendChart(rangeColumnChart, pane);
            },
            createBulletChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var bulletChart = new BulletChart(this, {
                    series: series,
                    invertAxes: this.invertAxes,
                    gap: firstSeries.gap,
                    spacing: firstSeries.spacing,
                    clip: pane.options.clip
                });
                this.appendChart(bulletChart, pane);
            },
            createLineChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var lineChart = new LineChart(this, $.extend({
                    invertAxes: this.invertAxes,
                    series: series
                }, this.stackableChartOptions(firstSeries, pane)));
                this.appendChart(lineChart, pane);
            },
            createAreaChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var areaChart = new AreaChart(this, $.extend({
                    invertAxes: this.invertAxes,
                    series: series
                }, this.stackableChartOptions(firstSeries, pane)));
                this.appendChart(areaChart, pane);
            },
            createOHLCChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var chart = new OHLCChart(this, {
                    invertAxes: this.invertAxes,
                    gap: firstSeries.gap,
                    series: series,
                    spacing: firstSeries.spacing,
                    clip: pane.options.clip
                });
                this.appendChart(chart, pane);
            },
            createCandlestickChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var chart = new CandlestickChart(this, {
                    invertAxes: this.invertAxes,
                    gap: firstSeries.gap,
                    series: series,
                    spacing: firstSeries.spacing,
                    clip: pane.options.clip
                });
                this.appendChart(chart, pane);
            },
            createBoxPlotChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var chart = new BoxPlotChart(this, {
                    invertAxes: this.invertAxes,
                    gap: firstSeries.gap,
                    series: series,
                    spacing: firstSeries.spacing,
                    clip: pane.options.clip
                });
                this.appendChart(chart, pane);
            },
            createWaterfallChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var waterfallChart = new WaterfallChart(this, {
                    series: series,
                    invertAxes: this.invertAxes,
                    gap: firstSeries.gap,
                    spacing: firstSeries.spacing
                });
                this.appendChart(waterfallChart, pane);
            },
            axisRequiresRounding: function (categoryAxisName, categoryAxisIndex) {
                var this$1 = this;
                var centeredSeries = filterSeriesByType(this.series, EQUALLY_SPACED_SERIES);
                for (var seriesIx = 0; seriesIx < this.series.length; seriesIx++) {
                    var currentSeries = this$1.series[seriesIx];
                    if (currentSeries.type === LINE || currentSeries.type === AREA) {
                        var line = currentSeries.line;
                        if (line && line.style === STEP) {
                            centeredSeries.push(currentSeries);
                        }
                    }
                }
                for (var seriesIx$1 = 0; seriesIx$1 < centeredSeries.length; seriesIx$1++) {
                    var seriesAxis = centeredSeries[seriesIx$1].categoryAxis || '';
                    if (seriesAxis === categoryAxisName || !seriesAxis && categoryAxisIndex === 0) {
                        return true;
                    }
                }
            },
            aggregatedAxis: function (categoryAxisName, categoryAxisIndex) {
                var series = this.series;
                for (var seriesIx = 0; seriesIx < series.length; seriesIx++) {
                    var seriesAxis = series[seriesIx].categoryAxis || '';
                    if ((seriesAxis === categoryAxisName || !seriesAxis && categoryAxisIndex === 0) && series[seriesIx].categoryField) {
                        return true;
                    }
                }
            },
            createCategoryAxesLabels: function () {
                var axes = this.axes;
                for (var i = 0; i < axes.length; i++) {
                    if (axes[i] instanceof CategoryAxis) {
                        axes[i].createLabels();
                    }
                }
            },
            createCategoryAxes: function (panes) {
                var this$1 = this;
                var invertAxes = this.invertAxes;
                var definitions = [].concat(this.options.categoryAxis);
                var axes = [];
                for (var i = 0; i < definitions.length; i++) {
                    var axisOptions = definitions[i];
                    var axisPane = this$1.findPane(axisOptions.pane);
                    if (inArray(axisPane, panes)) {
                        var name = axisOptions.name;
                        var categories = axisOptions.categories;
                        if (categories === void 0) {
                            categories = [];
                        }
                        axisOptions = deepExtend({
                            vertical: invertAxes,
                            axisCrossingValue: invertAxes ? MAX_VALUE : 0
                        }, axisOptions);
                        if (!defined(axisOptions.justified)) {
                            axisOptions.justified = this$1.isJustified();
                        }
                        if (this$1.axisRequiresRounding(name, i)) {
                            axisOptions.justified = false;
                        }
                        var categoryAxis = void 0;
                        if (isDateAxis(axisOptions, categories[0])) {
                            categoryAxis = new DateCategoryAxis(axisOptions, this$1.chartService);
                        } else {
                            categoryAxis = new CategoryAxis(axisOptions, this$1.chartService);
                        }
                        if (name) {
                            if (this$1.namedCategoryAxes[name]) {
                                throw new Error('Category axis with name ' + name + ' is already defined');
                            }
                            this$1.namedCategoryAxes[name] = categoryAxis;
                        }
                        categoryAxis.axisIndex = i;
                        axes.push(categoryAxis);
                        this$1.appendAxis(categoryAxis);
                    }
                }
                var primaryAxis = this.categoryAxis || axes[0];
                this.categoryAxis = primaryAxis;
                if (invertAxes) {
                    this.axisY = primaryAxis;
                } else {
                    this.axisX = primaryAxis;
                }
            },
            isJustified: function () {
                var series = this.series;
                for (var i = 0; i < series.length; i++) {
                    var currentSeries = series[i];
                    if (!inArray(currentSeries.type, [
                            AREA,
                            VERTICAL_AREA
                        ])) {
                        return false;
                    }
                }
                return true;
            },
            createValueAxes: function (panes) {
                var this$1 = this;
                var tracker = this.valueAxisRangeTracker;
                var defaultRange = tracker.query();
                var definitions = [].concat(this.options.valueAxis);
                var invertAxes = this.invertAxes;
                var baseOptions = { vertical: !invertAxes };
                var axes = [];
                if (this.stack100) {
                    baseOptions.roundToMajorUnit = false;
                    baseOptions.labels = { format: 'P0' };
                }
                for (var i = 0; i < definitions.length; i++) {
                    var axisOptions = definitions[i];
                    var axisPane = this$1.findPane(axisOptions.pane);
                    if (inArray(axisPane, panes)) {
                        var name = axisOptions.name;
                        var defaultAxisRange = equalsIgnoreCase(axisOptions.type, LOGARITHMIC) ? {
                            min: 0.1,
                            max: 1
                        } : {
                            min: 0,
                            max: 1
                        };
                        var range = tracker.query(name) || defaultRange || defaultAxisRange;
                        if (i === 0 && range && defaultRange) {
                            range.min = Math.min(range.min, defaultRange.min);
                            range.max = Math.max(range.max, defaultRange.max);
                        }
                        var axisType = void 0;
                        if (equalsIgnoreCase(axisOptions.type, LOGARITHMIC)) {
                            axisType = dataviz.LogarithmicAxis;
                        } else {
                            axisType = dataviz.NumericAxis;
                        }
                        var valueAxis = new axisType(range.min, range.max, deepExtend({}, baseOptions, axisOptions), this$1.chartService);
                        if (name) {
                            if (this$1.namedValueAxes[name]) {
                                throw new Error('Value axis with name ' + name + ' is already defined');
                            }
                            this$1.namedValueAxes[name] = valueAxis;
                        }
                        valueAxis.axisIndex = i;
                        axes.push(valueAxis);
                        this$1.appendAxis(valueAxis);
                    }
                }
                var primaryAxis = this.valueAxis || axes[0];
                this.valueAxis = primaryAxis;
                if (invertAxes) {
                    this.axisX = primaryAxis;
                } else {
                    this.axisY = primaryAxis;
                }
            },
            _dispatchEvent: function (chart, e, eventType) {
                var coords = chart._eventCoordinates(e);
                var point = new Point(coords.x, coords.y);
                var pane = this.pointPane(point);
                var categories = [];
                var values = [];
                if (!pane) {
                    return;
                }
                var allAxes = pane.axes;
                for (var i = 0; i < allAxes.length; i++) {
                    var axis = allAxes[i];
                    if (axis.getValue) {
                        appendIfNotNull(values, axis.getValue(point));
                    } else {
                        appendIfNotNull(categories, axis.getCategory(point));
                    }
                }
                if (categories.length === 0) {
                    appendIfNotNull(categories, this.categoryAxis.getCategory(point));
                }
                if (categories.length > 0 && values.length > 0) {
                    chart.trigger(eventType, {
                        element: eventElement(e),
                        originalEvent: e,
                        category: singleItemOrArray(categories),
                        value: singleItemOrArray(values)
                    });
                }
            },
            pointPane: function (point) {
                var panes = this.panes;
                for (var i = 0; i < panes.length; i++) {
                    var currentPane = panes[i];
                    if (currentPane.contentBox.containsPoint(point)) {
                        return currentPane;
                    }
                }
            },
            updateAxisOptions: function (axis, options) {
                var axesOptions = axis instanceof CategoryAxis ? [].concat(this.options.categoryAxis) : [].concat(this.options.valueAxis);
                deepExtend(axesOptions[axis.axisIndex], options);
            }
        });
        function groupSeries(series, axis, axisIx) {
            return grep(series, function (s) {
                return axisIx === 0 && !s.categoryAxis || s.categoryAxis === axis;
            });
        }
        setDefaultOptions(CategoricalPlotArea, {
            categoryAxis: { categories: [] },
            valueAxis: {}
        });
        deepExtend(CategoricalPlotArea.prototype, PlotAreaEventsMixin);
        var Highlight = Class.extend({
            init: function () {
                this._points = [];
            },
            destroy: function () {
                this._points = [];
            },
            show: function (points) {
                var this$1 = this;
                var arrayPoints = [].concat(points);
                this.hide();
                for (var i = 0; i < arrayPoints.length; i++) {
                    var point = arrayPoints[i];
                    if (point && point.toggleHighlight && point.hasHighlight()) {
                        this$1.togglePointHighlight(point, true);
                        this$1._points.push(point);
                    }
                }
            },
            togglePointHighlight: function (point, show) {
                var toggleHandler = (point.options.highlight || {}).toggle;
                if (toggleHandler) {
                    var eventArgs = {
                        category: point.category,
                        series: point.series,
                        dataItem: point.dataItem,
                        value: point.value,
                        stackValue: point.stackValue,
                        preventDefault: preventDefault,
                        visual: point.highlightVisual(),
                        show: show
                    };
                    toggleHandler(eventArgs);
                    if (!eventArgs._defaultPrevented) {
                        point.toggleHighlight(show);
                    }
                } else {
                    point.toggleHighlight(show);
                }
            },
            hide: function () {
                var this$1 = this;
                var points = this._points;
                while (points.length) {
                    this$1.togglePointHighlight(points.pop(), false);
                }
            },
            isHighlighted: function (element) {
                var points = this._points;
                for (var i = 0; i < points.length; i++) {
                    var point = points[i];
                    if (element === point) {
                        return true;
                    }
                }
                return false;
            }
        });
        function preventDefault() {
            this._defaultPrevented = true;
        }
        function acceptKey(e, mouseKey) {
            var key = (mouseKey || '').toLowerCase();
            var event = e.event;
            var accept = key === 'none' && !(event.ctrlKey || event.shiftKey || event.altKey) || event[key + 'Key'];
            return accept;
        }
        function toChartAxisRanges(axisRanges) {
            var ranges = {};
            for (var idx = 0; idx < axisRanges.length; idx++) {
                var axisRange = axisRanges[idx];
                if (axisRange.axis.options.name) {
                    ranges[axisRange.axis.options.name] = {
                        min: axisRange.range.min,
                        max: axisRange.range.max
                    };
                }
            }
            return ranges;
        }
        var Pannable = Class.extend({
            init: function (plotArea, options) {
                this.plotArea = plotArea;
                this.options = deepExtend({}, this.options, options);
            },
            start: function (e) {
                this._active = acceptKey(e, this.options.key);
                return this._active;
            },
            move: function (e) {
                if (this._active) {
                    var axisRanges = this.axisRanges = this._panAxes(e, X).concat(this._panAxes(e, Y));
                    if (axisRanges.length) {
                        this.axisRanges = axisRanges;
                        return toChartAxisRanges(axisRanges);
                    }
                }
            },
            end: function () {
                var active = this._active;
                this._active = false;
                return active;
            },
            pan: function () {
                var ref = this;
                var plotArea = ref.plotArea;
                var axisRanges = ref.axisRanges;
                if (axisRanges.length) {
                    for (var idx = 0; idx < axisRanges.length; idx++) {
                        var range = axisRanges[idx];
                        plotArea.updateAxisOptions(range.axis, range.range);
                    }
                    plotArea.redraw(plotArea.panes);
                }
            },
            destroy: function () {
                delete this.plotArea;
            },
            _panAxes: function (e, position) {
                var plotArea = this.plotArea;
                var delta = -e[position].delta;
                var lock = (this.options.lock || '').toLowerCase();
                var updatedAxes = [];
                if (delta !== 0 && (lock || '').toLowerCase() !== position) {
                    var axes = plotArea.axes;
                    for (var idx = 0; idx < axes.length; idx++) {
                        var axis = axes[idx];
                        if (position === X && !axis.options.vertical || position === Y && axis.options.vertical) {
                            var range = axis.pan(delta);
                            if (range) {
                                range.limitRange = true;
                                updatedAxes.push({
                                    axis: axis,
                                    range: range
                                });
                            }
                        }
                    }
                }
                return updatedAxes;
            }
        });
        Pannable.prototype.options = {
            key: 'none',
            lock: 'none'
        };
        var ZoomSelection = Class.extend({
            init: function (chart, options) {
                this.chart = chart;
                this.options = deepExtend({}, this.options, options);
                this.createElement();
            },
            createElement: function () {
                var marquee = this._marquee = document.createElement('div');
                marquee.className = 'k-marquee';
                var marqueeColor = document.createElement('div');
                marqueeColor.className = 'k-marquee-color';
                marquee.appendChild(marqueeColor);
            },
            removeElement: function () {
                if (this._marquee.parentNode) {
                    this._marquee.parentNode.removeChild(this._marquee);
                }
            },
            setStyles: function (styles) {
                elementStyles(this._marquee, styles);
            },
            start: function (e) {
                if (acceptKey(e, this.options.key)) {
                    var chart = this.chart;
                    var point = chart._eventCoordinates(e);
                    var zoomPane = this._zoomPane = chart._plotArea.paneByPoint(point);
                    if (zoomPane && zoomPane.clipBox()) {
                        var clipBox = zoomPane.clipBox().clone();
                        var offset = this._elementOffset();
                        clipBox.translate(offset.left, offset.top);
                        this._zoomPaneClipBox = clipBox;
                        document.body.appendChild(this._marquee);
                        this.setStyles({
                            left: e.pageX + 1,
                            top: e.pageY + 1,
                            width: 0,
                            height: 0
                        });
                        return true;
                    }
                }
                return false;
            },
            _elementOffset: function () {
                var chartElement = this.chart.element;
                var ref = elementStyles(chartElement, [
                    'paddingLeft',
                    'paddingTop'
                ]);
                var paddingLeft = ref.paddingLeft;
                var paddingTop = ref.paddingTop;
                var offset = dataviz.elementOffset(chartElement);
                return {
                    left: paddingLeft + offset.left,
                    top: paddingTop + offset.top
                };
            },
            move: function (e) {
                var zoomPane = this._zoomPane;
                if (zoomPane) {
                    this.setStyles(this._selectionPosition(e));
                }
            },
            end: function (e) {
                var zoomPane = this._zoomPane;
                if (zoomPane) {
                    var elementOffset$$1 = this._elementOffset();
                    var selectionPosition = this._selectionPosition(e);
                    selectionPosition.left -= elementOffset$$1.left;
                    selectionPosition.top -= elementOffset$$1.top;
                    var start = {
                        x: selectionPosition.left,
                        y: selectionPosition.top
                    };
                    var end = {
                        x: selectionPosition.left + selectionPosition.width,
                        y: selectionPosition.top + selectionPosition.height
                    };
                    this._updateAxisRanges(start, end);
                    this.removeElement();
                    delete this._zoomPane;
                    return toChartAxisRanges(this.axisRanges);
                }
            },
            zoom: function () {
                var axisRanges = this.axisRanges;
                if (axisRanges && axisRanges.length) {
                    var plotArea = this.chart._plotArea;
                    for (var idx = 0; idx < axisRanges.length; idx++) {
                        var axisRange = axisRanges[idx];
                        plotArea.updateAxisOptions(axisRange.axis, axisRange.range);
                    }
                    plotArea.redraw(plotArea.panes);
                }
            },
            destroy: function () {
                this.removeElement();
                delete this._marquee;
                delete this.chart;
            },
            _updateAxisRanges: function (start, end) {
                var lock = (this.options.lock || '').toLowerCase();
                var axisRanges = [];
                var axes = this._zoomPane.axes;
                for (var idx = 0; idx < axes.length; idx++) {
                    var axis = axes[idx];
                    var vertical = axis.options.vertical;
                    if (!(lock === X && !vertical) && !(lock === Y && vertical)) {
                        var range = axis.pointsRange(start, end);
                        if (range) {
                            axisRanges.push({
                                axis: axis,
                                range: range
                            });
                        }
                    }
                }
                this.axisRanges = axisRanges;
            },
            _selectionPosition: function (e) {
                var clipBox = this._zoomPaneClipBox;
                var startLocation = {
                    x: e.x.startLocation,
                    y: e.y.startLocation
                };
                var pageX = e.x.location;
                var pageY = e.y.location;
                var lock = (this.options.lock || '').toLowerCase();
                var left = Math.min(startLocation.x, pageX);
                var top = Math.min(startLocation.y, pageY);
                var width = Math.abs(startLocation.x - pageX);
                var height = Math.abs(startLocation.y - pageY);
                if (lock === X) {
                    left = clipBox.x1;
                    width = clipBox.width();
                }
                if (lock === Y) {
                    top = clipBox.y1;
                    height = clipBox.height();
                }
                if (pageX > clipBox.x2) {
                    width = clipBox.x2 - startLocation.x;
                }
                if (pageX < clipBox.x1) {
                    width = startLocation.x - clipBox.x1;
                }
                if (pageY > clipBox.y2) {
                    height = clipBox.y2 - startLocation.y;
                }
                if (pageY < clipBox.y1) {
                    height = startLocation.y - clipBox.y1;
                }
                return {
                    left: Math.max(left, clipBox.x1),
                    top: Math.max(top, clipBox.y1),
                    width: width,
                    height: height
                };
            }
        });
        ZoomSelection.prototype.options = {
            key: 'shift',
            lock: 'none'
        };
        var MousewheelZoom = Class.extend({
            init: function (chart, options) {
                this.chart = chart;
                this.options = deepExtend({}, this.options, options);
            },
            updateRanges: function (delta) {
                var lock = (this.options.lock || '').toLowerCase();
                var axisRanges = [];
                var axes = this.chart._plotArea.axes;
                for (var idx = 0; idx < axes.length; idx++) {
                    var axis = axes[idx];
                    var vertical = axis.options.vertical;
                    if (!(lock === X && !vertical) && !(lock === Y && vertical)) {
                        var range = axis.zoomRange(-delta);
                        if (range) {
                            axisRanges.push({
                                axis: axis,
                                range: range
                            });
                        }
                    }
                }
                this.axisRanges = axisRanges;
                return toChartAxisRanges(axisRanges);
            },
            zoom: function () {
                var axisRanges = this.axisRanges;
                if (axisRanges && axisRanges.length) {
                    var plotArea = this.chart._plotArea;
                    for (var idx = 0; idx < axisRanges.length; idx++) {
                        var axisRange = axisRanges[idx];
                        plotArea.updateAxisOptions(axisRange.axis, axisRange.range);
                    }
                    plotArea.redraw(plotArea.panes);
                }
            },
            destroy: function () {
                delete this.chart;
            }
        });
        var LegendLayout = ChartElement.extend({
            init: function (options, chartService) {
                ChartElement.fn.init.call(this, options);
                this.chartService = chartService;
            },
            render: function () {
                var ref = this;
                var children = ref.children;
                var options = ref.options;
                var vertical = options.vertical;
                this.visual = new drawing.Layout(null, {
                    spacing: vertical ? 0 : options.spacing,
                    lineSpacing: vertical ? options.spacing : 0,
                    orientation: vertical ? 'vertical' : 'horizontal'
                });
                for (var idx = 0; idx < children.length; idx++) {
                    var legendItem = children[idx];
                    legendItem.reflow(new Box());
                    legendItem.renderVisual();
                }
            },
            reflow: function (box) {
                this.visual.rect(box.toRect());
                this.visual.reflow();
                var bbox = this.visual.clippedBBox();
                if (bbox) {
                    this.box = dataviz.rectToBox(bbox);
                } else {
                    this.box = new Box();
                }
            },
            renderVisual: function () {
                this.addVisual();
            },
            createVisual: function () {
            }
        });
        var LegendItem = BoxElement.extend({
            init: function (options) {
                BoxElement.fn.init.call(this, options);
                this.createContainer();
                this.createMarker();
                this.createLabel();
            },
            createContainer: function () {
                this.container = new dataviz.FloatElement({
                    vertical: false,
                    wrap: false,
                    align: CENTER
                });
                this.append(this.container);
            },
            createMarker: function () {
                this.container.append(new ShapeElement(this.markerOptions()));
            },
            markerOptions: function () {
                var options = this.options;
                var markerColor = options.markerColor;
                return deepExtend({}, options.markers, {
                    background: markerColor,
                    border: { color: markerColor }
                });
            },
            createLabel: function () {
                var options = this.options;
                var labelOptions = deepExtend({}, options.labels);
                this.container.append(new TextBox(options.text, labelOptions));
            },
            renderComplete: function () {
                BoxElement.fn.renderComplete.call(this);
                var cursor = this.options.cursor || {};
                var eventSink = this._itemOverlay = Path.fromRect(this.container.box.toRect(), {
                    fill: {
                        color: WHITE,
                        opacity: 0
                    },
                    stroke: null,
                    cursor: cursor.style || cursor
                });
                this.appendVisual(eventSink);
            },
            click: function (widget, e) {
                var args = this.eventArgs(e);
                if (!widget.trigger(LEGEND_ITEM_CLICK, args)) {
                    e.preventDefault();
                }
            },
            hover: function (widget, e) {
                var args = this.eventArgs(e);
                if (!widget.trigger(LEGEND_ITEM_HOVER, args)) {
                    e.preventDefault();
                    widget._legendItemHover(args.seriesIndex, args.pointIndex);
                }
                return true;
            },
            leave: function (widget) {
                widget._unsetActivePoint();
            },
            eventArgs: function (e) {
                var options = this.options;
                return {
                    element: eventElement(e),
                    text: options.text,
                    series: options.series,
                    seriesIndex: options.series.index,
                    pointIndex: options.pointIndex
                };
            },
            renderVisual: function () {
                var this$1 = this;
                var options = this.options;
                var customVisual = options.visual;
                if (customVisual) {
                    this.visual = customVisual({
                        active: options.active,
                        series: options.series,
                        sender: this.getSender(),
                        pointIndex: options.pointIndex,
                        options: {
                            markers: this.markerOptions(),
                            labels: options.labels
                        },
                        createVisual: function () {
                            this$1.createVisual();
                            this$1.renderChildren();
                            this$1.renderComplete();
                            var defaultVisual = this$1.visual;
                            delete this$1.visual;
                            return defaultVisual;
                        }
                    });
                    this.addVisual();
                } else {
                    BoxElement.fn.renderVisual.call(this);
                }
            }
        });
        var HORIZONTAL = 'horizontal';
        var POINTER = 'pointer';
        var CUSTOM = 'custom';
        var Legend = ChartElement.extend({
            init: function (options, chartService) {
                ChartElement.fn.init.call(this, options);
                this.chartService = chartService;
                if (!inArray(this.options.position, [
                        TOP,
                        RIGHT,
                        BOTTOM,
                        LEFT,
                        CUSTOM
                    ])) {
                    this.options.position = RIGHT;
                }
                this.createContainer();
                this.createItems();
            },
            createContainer: function () {
                var options = this.options;
                var position = options.position;
                var userAlign = options.align;
                var align = position;
                var vAlign = CENTER;
                if (position === CUSTOM) {
                    align = LEFT;
                } else if (inArray(position, [
                        TOP,
                        BOTTOM
                    ])) {
                    if (userAlign === 'start') {
                        align = LEFT;
                    } else if (userAlign === 'end') {
                        align = RIGHT;
                    } else {
                        align = CENTER;
                    }
                    vAlign = position;
                } else if (userAlign) {
                    if (userAlign === 'start') {
                        vAlign = TOP;
                    } else if (userAlign === 'end') {
                        vAlign = BOTTOM;
                    }
                }
                this.container = new BoxElement({
                    margin: options.margin,
                    padding: options.padding,
                    background: options.background,
                    border: options.border,
                    vAlign: vAlign,
                    align: align,
                    zIndex: options.zIndex,
                    shrinkToFit: true
                });
                this.append(this.container);
            },
            createItems: function () {
                var chartService = this.getService();
                var options = this.options;
                var vertical = this.isVertical();
                var innerElement = new LegendLayout({
                    vertical: vertical,
                    spacing: options.spacing
                }, chartService);
                var items = options.items;
                if (options.reverse) {
                    items = items.slice(0).reverse();
                }
                var count = items.length;
                for (var i = 0; i < count; i++) {
                    var item = items[i];
                    innerElement.append(new LegendItem(deepExtend({}, {
                        markers: options.markers,
                        labels: options.labels
                    }, options.item, item)));
                }
                innerElement.render();
                this.container.append(innerElement);
            },
            isVertical: function () {
                var ref = this.options;
                var orientation = ref.orientation;
                var position = ref.position;
                var vertical = position === CUSTOM && orientation !== HORIZONTAL || (defined(orientation) ? orientation !== HORIZONTAL : inArray(position, [
                    LEFT,
                    RIGHT
                ]));
                return vertical;
            },
            hasItems: function () {
                return this.container.children[0].children.length > 0;
            },
            reflow: function (targetBox) {
                var options = this.options;
                var legendBox = targetBox.clone();
                if (!this.hasItems()) {
                    this.box = legendBox;
                    return;
                }
                if (options.position === CUSTOM) {
                    this.containerCustomReflow(legendBox);
                    this.box = legendBox;
                } else {
                    this.containerReflow(legendBox);
                }
            },
            containerReflow: function (targetBox) {
                var ref = this;
                var options = ref.options;
                var container = ref.container;
                var position = options.position;
                var width = options.width;
                var height = options.height;
                var pos = position === TOP || position === BOTTOM ? X : Y;
                var vertical = this.isVertical();
                var alignTarget = targetBox.clone();
                var containerBox = targetBox.clone();
                if (position === LEFT || position === RIGHT) {
                    containerBox.y1 = alignTarget.y1 = 0;
                }
                if (vertical && height) {
                    containerBox.y2 = containerBox.y1 + height;
                    containerBox.align(alignTarget, Y, container.options.vAlign);
                } else if (!vertical && width) {
                    containerBox.x2 = containerBox.x1 + width;
                    containerBox.align(alignTarget, X, container.options.align);
                }
                container.reflow(containerBox);
                containerBox = container.box;
                var box = containerBox.clone();
                if (options.offsetX || options.offsetY) {
                    containerBox.translate(options.offsetX, options.offsetY);
                    this.container.reflow(containerBox);
                }
                box[pos + 1] = targetBox[pos + 1];
                box[pos + 2] = targetBox[pos + 2];
                this.box = box;
            },
            containerCustomReflow: function (targetBox) {
                var ref = this;
                var options = ref.options;
                var container = ref.container;
                var offsetX = options.offsetX;
                var offsetY = options.offsetY;
                var width = options.width;
                var height = options.height;
                var vertical = this.isVertical();
                var containerBox = targetBox.clone();
                if (vertical && height) {
                    containerBox.y2 = containerBox.y1 + height;
                } else if (!vertical && width) {
                    containerBox.x2 = containerBox.x1 + width;
                }
                container.reflow(containerBox);
                containerBox = container.box;
                container.reflow(new Box(offsetX, offsetY, offsetX + containerBox.width(), offsetY + containerBox.height()));
            },
            renderVisual: function () {
                if (this.hasItems()) {
                    ChartElement.fn.renderVisual.call(this);
                }
            }
        });
        setDefaultOptions(Legend, {
            position: RIGHT,
            items: [],
            labels: { margin: { left: 6 } },
            offsetX: 0,
            offsetY: 0,
            margin: getSpacing(5),
            padding: getSpacing(5),
            border: {
                color: BLACK,
                width: 0
            },
            item: { cursor: POINTER },
            spacing: 6,
            background: '',
            zIndex: 1,
            markers: {
                border: { width: 0 },
                width: 15,
                height: 3,
                type: 'rect',
                align: LEFT,
                vAlign: CENTER
            }
        });
        var PlotAreaFactory = Class.extend({
            init: function () {
                this._registry = [];
            },
            register: function (type, seriesTypes) {
                this._registry.push({
                    type: type,
                    seriesTypes: seriesTypes
                });
            },
            create: function (srcSeries, options, chartService) {
                var registry = this._registry;
                var match = registry[0];
                var series;
                for (var idx = 0; idx < registry.length; idx++) {
                    var entry = registry[idx];
                    series = filterSeriesByType(srcSeries, entry.seriesTypes);
                    if (series.length > 0) {
                        match = entry;
                        break;
                    }
                }
                return new match.type(series, options, chartService);
            }
        });
        PlotAreaFactory.current = new PlotAreaFactory();
        var ZOOM_ACCELERATION = 3;
        var SELECTOR_HEIGHT_ADJUST = 0.1;
        function createDiv(className) {
            var element = document.createElement('div');
            if (className) {
                element.className = className;
            }
            return element;
        }
        function closestHandle(element) {
            var current = element;
            while (current && !hasClasses(current, 'k-handle')) {
                current = current.parentNode;
            }
            return current;
        }
        var Selection = Class.extend({
            init: function (chart, categoryAxis, options, observer) {
                var chartElement = chart.element;
                var valueAxis = this.getValueAxis(categoryAxis);
                this.options = deepExtend({}, this.options, options);
                this.chart = chart;
                this.observer = observer;
                this.chartElement = chartElement;
                this.categoryAxis = categoryAxis;
                this._dateAxis = this.categoryAxis instanceof DateCategoryAxis;
                this.valueAxis = valueAxis;
                this.initOptions();
                if (this.options.visible) {
                    this.createElements();
                    this.set(this._index(this.options.from), this._index(this.options.to));
                    this.bindEvents();
                }
            },
            createElements: function () {
                var options = this.options;
                var wrapper = this.wrapper = createDiv('k-selector');
                elementStyles(wrapper, {
                    top: options.offset.top,
                    left: options.offset.left,
                    width: options.width,
                    height: options.height
                });
                var selection = this.selection = createDiv('k-selection');
                this.leftMask = createDiv('k-mask');
                this.rightMask = createDiv('k-mask');
                wrapper.appendChild(this.leftMask);
                wrapper.appendChild(this.rightMask);
                wrapper.appendChild(selection);
                selection.appendChild(createDiv('k-selection-bg'));
                var leftHandle = this.leftHandle = createDiv('k-handle k-left-handle');
                var rightHandle = this.rightHandle = createDiv('k-handle k-right-handle');
                leftHandle.appendChild(createDiv());
                rightHandle.appendChild(createDiv());
                selection.appendChild(leftHandle);
                selection.appendChild(rightHandle);
                this.chartElement.appendChild(wrapper);
                var selectionStyles = elementStyles(selection, [
                    'borderLeftWidth',
                    'borderRightWidth',
                    'height'
                ]);
                var leftHandleHeight = elementStyles(leftHandle, 'height').height;
                var rightHandleHeight = elementStyles(rightHandle, 'height').height;
                options.selection = {
                    border: {
                        left: selectionStyles.borderLeftWidth,
                        right: selectionStyles.borderRightWidth
                    }
                };
                elementStyles(leftHandle, { top: (selectionStyles.height - leftHandleHeight) / 2 });
                elementStyles(rightHandle, { top: (selectionStyles.height - rightHandleHeight) / 2 });
                wrapper.style.cssText = wrapper.style.cssText;
            },
            bindEvents: function () {
                this._mousewheelHandler = this.options.mousewheel !== false ? this._mousewheel.bind(this) : stopPropagation;
                var obj;
                bindEvents(this.wrapper, (obj = {}, obj[MOUSEWHEEL] = this._mousewheelHandler, obj));
                this._domEvents = services.DomEventsBuilder.create(this.wrapper, {
                    start: this._start.bind(this),
                    move: this._move.bind(this),
                    end: this._end.bind(this),
                    tap: this._tap.bind(this),
                    press: this._press.bind(this),
                    gesturestart: this._gesturestart.bind(this),
                    gesturechange: this._gesturechange.bind(this),
                    gestureend: this._gestureend.bind(this)
                });
            },
            initOptions: function () {
                var ref = this;
                var options = ref.options;
                var categoryAxis = ref.categoryAxis;
                var valueAxis = ref.valueAxis;
                var categoryAxisLineBox = categoryAxis.lineBox();
                var valueAxisLineBox = valueAxis.lineBox();
                var intlService = this.chart.chartService.intl;
                if (this._dateAxis) {
                    deepExtend(options, {
                        min: parseDate(intlService, options.min),
                        max: parseDate(intlService, options.max),
                        from: parseDate(intlService, options.from),
                        to: parseDate(intlService, options.to)
                    });
                }
                var ref$1 = elementStyles(this.chartElement, [
                    'paddingLeft',
                    'paddingTop'
                ]);
                var paddingLeft = ref$1.paddingLeft;
                var paddingTop = ref$1.paddingTop;
                this.options = deepExtend({}, {
                    width: categoryAxisLineBox.width(),
                    height: valueAxisLineBox.height() + SELECTOR_HEIGHT_ADJUST,
                    padding: {
                        left: paddingLeft,
                        top: paddingTop
                    },
                    offset: {
                        left: valueAxisLineBox.x2 + paddingLeft,
                        top: valueAxisLineBox.y1 + paddingTop
                    },
                    from: options.min,
                    to: options.max
                }, options);
            },
            destroy: function () {
                if (this._domEvents) {
                    this._domEvents.destroy();
                    delete this._domEvents;
                }
                clearTimeout(this._mwTimeout);
                this._state = null;
                if (this.wrapper) {
                    var obj;
                    unbindEvents(this.wrapper, (obj = {}, obj[MOUSEWHEEL] = this._mousewheelHandler, obj));
                    this.chartElement.removeChild(this.wrapper);
                }
            },
            _rangeEventArgs: function (range) {
                return {
                    axis: this.categoryAxis.options,
                    from: this._value(range.from),
                    to: this._value(range.to)
                };
            },
            _start: function (e) {
                var options = this.options;
                var target = eventElement(e);
                if (this._state || !target) {
                    return;
                }
                this.chart._unsetActivePoint();
                this._state = {
                    moveTarget: closestHandle(target) || target,
                    startLocation: e.x ? e.x.location : 0,
                    range: {
                        from: this._index(options.from),
                        to: this._index(options.to)
                    }
                };
                var args = this._rangeEventArgs({
                    from: this._index(options.from),
                    to: this._index(options.to)
                });
                if (this.trigger(SELECT_START, args)) {
                    this._state = null;
                }
            },
            _press: function (e) {
                var handle;
                if (this._state) {
                    handle = this._state.moveTarget;
                } else {
                    handle = closestHandle(eventElement(e));
                }
                if (handle) {
                    dataviz.addClass(handle, 'k-handle-active');
                }
            },
            _move: function (e) {
                if (!this._state) {
                    return;
                }
                var ref = this;
                var state = ref._state;
                var options = ref.options;
                var categories = ref.categoryAxis.options.categories;
                var range = state.range;
                var target = state.moveTarget;
                var from = this._index(options.from);
                var to = this._index(options.to);
                var min = this._index(options.min);
                var max = this._index(options.max);
                var delta = state.startLocation - e.x.location;
                var oldRange = {
                    from: range.from,
                    to: range.to
                };
                var span = range.to - range.from;
                var scale = elementStyles(this.wrapper, 'width').width / (categories.length - 1);
                var offset = Math.round(delta / scale);
                if (!target) {
                    return;
                }
                if (hasClasses(target, 'k-selection k-selection-bg')) {
                    range.from = Math.min(Math.max(min, from - offset), max - span);
                    range.to = Math.min(range.from + span, max);
                } else if (hasClasses(target, 'k-left-handle')) {
                    range.from = Math.min(Math.max(min, from - offset), max - 1);
                    range.to = Math.max(range.from + 1, range.to);
                } else if (hasClasses(target, 'k-right-handle')) {
                    range.to = Math.min(Math.max(min + 1, to - offset), max);
                    range.from = Math.min(range.to - 1, range.from);
                }
                if (range.from !== oldRange.from || range.to !== oldRange.to) {
                    this.move(range.from, range.to);
                    this.trigger(SELECT, this._rangeEventArgs(range));
                }
            },
            _end: function () {
                if (this._state) {
                    var moveTarget = this._state.moveTarget;
                    if (moveTarget) {
                        dataviz.removeClass(moveTarget, 'k-handle-active');
                    }
                    var range = this._state.range;
                    this.set(range.from, range.to);
                    this.trigger(SELECT_END, this._rangeEventArgs(range));
                    delete this._state;
                }
            },
            _tap: function (e) {
                var ref = this;
                var options = ref.options;
                var categoryAxis = ref.categoryAxis;
                var coords = this.chart._eventCoordinates(e);
                var categoryIx = categoryAxis.pointCategoryIndex(new Point(coords.x, categoryAxis.box.y1));
                var from = this._index(options.from);
                var to = this._index(options.to);
                var min = this._index(options.min);
                var max = this._index(options.max);
                var span = to - from;
                var mid = from + span / 2;
                var range = {};
                var rightClick = e.event.which === 3;
                var offset = Math.round(mid - categoryIx);
                if (this._state || rightClick) {
                    return;
                }
                this.chart._unsetActivePoint();
                if (!categoryAxis.options.justified) {
                    offset--;
                }
                range.from = Math.min(Math.max(min, from - offset), max - span);
                range.to = Math.min(range.from + span, max);
                this._start(e);
                if (this._state) {
                    this._state.range = range;
                    this.trigger(SELECT, this._rangeEventArgs(range));
                    this._end();
                }
            },
            _mousewheel: function (e) {
                var this$1 = this;
                var delta = dataviz.mousewheelDelta(e);
                this._start({ target: this.selection });
                if (this._state) {
                    var range = this._state.range;
                    e.preventDefault();
                    e.stopPropagation();
                    if (Math.abs(delta) > 1) {
                        delta *= ZOOM_ACCELERATION;
                    }
                    if (this.options.mousewheel.reverse) {
                        delta *= -1;
                    }
                    if (this.expand(delta)) {
                        this.trigger(SELECT, {
                            axis: this.categoryAxis.options,
                            delta: delta,
                            originalEvent: e,
                            from: this._value(range.from),
                            to: this._value(range.to)
                        });
                    }
                    if (this._mwTimeout) {
                        clearTimeout(this._mwTimeout);
                    }
                    this._mwTimeout = setTimeout(function () {
                        this$1._end();
                    }, MOUSEWHEEL_DELAY);
                }
            },
            _gesturestart: function (e) {
                var options = this.options;
                this._state = {
                    range: {
                        from: this._index(options.from),
                        to: this._index(options.to)
                    }
                };
                var args = this._rangeEventArgs(this._state.range);
                if (this.trigger(SELECT_START, args)) {
                    this._state = null;
                } else {
                    e.preventDefault();
                }
            },
            _gestureend: function () {
                if (this._state) {
                    this.trigger(SELECT_END, this._rangeEventArgs(this._state.range));
                    delete this._state;
                }
            },
            _gesturechange: function (e) {
                var ref = this;
                var chart = ref.chart;
                var state = ref._state;
                var options = ref.options;
                var categoryAxis = ref.categoryAxis;
                var range = state.range;
                var p0 = chart._toModelCoordinates(e.touches[0].x.location).x;
                var p1 = chart._toModelCoordinates(e.touches[1].x.location).x;
                var left = Math.min(p0, p1);
                var right = Math.max(p0, p1);
                e.preventDefault();
                range.from = categoryAxis.pointCategoryIndex(new Point(left)) || options.min;
                range.to = categoryAxis.pointCategoryIndex(new Point(right)) || options.max;
                this.move(range.from, range.to);
                this.trigger(SELECT, this._rangeEventArgs(range));
            },
            _index: function (value) {
                var index = value;
                if (value instanceof Date) {
                    index = this.categoryAxis.categoryIndex(value);
                }
                return index;
            },
            _value: function (index) {
                var categories = this.categoryAxis.options.categories;
                var value = index;
                if (this._dateAxis) {
                    if (index > categories.length - 1) {
                        value = this.options.max;
                    } else {
                        value = categories[Math.ceil(index)];
                    }
                }
                return value;
            },
            _slot: function (value) {
                var categoryAxis = this.categoryAxis;
                var index = this._index(value);
                return categoryAxis.getSlot(index, index, true);
            },
            move: function (from, to) {
                var options = this.options;
                var offset = options.offset;
                var padding = options.padding;
                var border = options.selection.border;
                var box = this._slot(from);
                var leftMaskWidth = round(box.x1 - offset.left + padding.left);
                elementStyles(this.leftMask, { width: leftMaskWidth });
                elementStyles(this.selection, { left: leftMaskWidth });
                box = this._slot(to);
                var rightMaskWidth = round(options.width - (box.x1 - offset.left + padding.left));
                elementStyles(this.rightMask, { width: rightMaskWidth });
                var distance = options.width - rightMaskWidth;
                if (distance !== options.width) {
                    distance += border.right;
                }
                elementStyles(this.rightMask, { left: distance });
                elementStyles(this.selection, { width: Math.max(options.width - (leftMaskWidth + rightMaskWidth) - border.right, 0) });
            },
            set: function (from, to) {
                var options = this.options;
                var min = this._index(options.min);
                var max = this._index(options.max);
                var fromValue = limitValue(this._index(from), min, max);
                var toValue = limitValue(this._index(to), fromValue + 1, max);
                if (options.visible) {
                    this.move(fromValue, toValue);
                }
                options.from = this._value(fromValue);
                options.to = this._value(toValue);
            },
            expand: function (delta) {
                var options = this.options;
                var min = this._index(options.min);
                var max = this._index(options.max);
                var zDir = options.mousewheel.zoom;
                var from = this._index(options.from);
                var to = this._index(options.to);
                var range = {
                    from: from,
                    to: to
                };
                var oldRange = deepExtend({}, range);
                if (this._state) {
                    range = this._state.range;
                }
                if (zDir !== RIGHT) {
                    range.from = limitValue(limitValue(from - delta, 0, to - 1), min, max);
                }
                if (zDir !== LEFT) {
                    range.to = limitValue(limitValue(to + delta, range.from + 1, max), min, max);
                }
                if (range.from !== oldRange.from || range.to !== oldRange.to) {
                    this.set(range.from, range.to);
                    return true;
                }
            },
            getValueAxis: function (categoryAxis) {
                var axes = categoryAxis.pane.axes;
                var axesCount = axes.length;
                for (var i = 0; i < axesCount; i++) {
                    var axis = axes[i];
                    if (axis.options.vertical !== categoryAxis.options.vertical) {
                        return axis;
                    }
                }
            },
            trigger: function (name, args) {
                return (this.observer || this.chart).trigger(name, args);
            }
        });
        function stopPropagation(e) {
            e.stopPropagation();
        }
        setDefaultOptions(Selection, {
            visible: true,
            mousewheel: { zoom: 'both' },
            min: MIN_VALUE,
            max: MAX_VALUE
        });
        var Tooltip = BaseTooltip.extend({
            show: function (point) {
                if (!point || !point.tooltipAnchor || this._current && this._current === point) {
                    return;
                }
                var options = deepExtend({}, this.options, point.options.tooltip);
                var anchor = point.tooltipAnchor();
                if (anchor) {
                    this._current = point;
                    BaseTooltip.fn.show.call(this, {
                        point: point,
                        anchor: anchor
                    }, options, point);
                } else {
                    this.hide();
                }
            },
            hide: function () {
                delete this._current;
                BaseTooltip.fn.hide.call(this);
            }
        });
        var SharedTooltip = BaseTooltip.extend({
            init: function (plotArea, options) {
                BaseTooltip.fn.init.call(this, plotArea.chartService, options);
                this.plotArea = plotArea;
                this.formatService = plotArea.chartService.format;
            },
            showAt: function (points, coords) {
                var tooltipPoints = grep(points, function (point) {
                    var tooltip = point.series.tooltip;
                    var excluded = tooltip && tooltip.visible === false;
                    return !excluded;
                });
                if (tooltipPoints.length > 0) {
                    var point = tooltipPoints[0];
                    var slot = this.plotArea.categoryAxis.getSlot(point.categoryIx);
                    var anchor = coords ? this._slotAnchor(coords, slot) : this._defaultAnchor(point, slot);
                    this.show({
                        anchor: anchor,
                        shared: true,
                        points: points,
                        category: point.category,
                        categoryText: this.formatService.auto(this.options.categoryFormat, point.category),
                        series: this.plotArea.series
                    }, this.options);
                }
            },
            _slotAnchor: function (point, slot) {
                var axis = this.plotArea.categoryAxis;
                var align = {
                    horizontal: 'left',
                    vertical: 'center'
                };
                if (!axis.options.vertical) {
                    point.x = slot.center().x;
                }
                return {
                    point: point,
                    align: align
                };
            },
            _defaultAnchor: function (point, slot) {
                var box = point.owner.pane.chartsBox();
                var vertical = this.plotArea.categoryAxis.options.vertical;
                var center = box.center();
                var slotCenter = slot.center();
                var align = {
                    horizontal: 'center',
                    vertical: 'center'
                };
                var centerPoint;
                if (vertical) {
                    centerPoint = new Point(center.x, slotCenter.y);
                } else {
                    centerPoint = new Point(slotCenter.x, center.y);
                }
                return {
                    point: centerPoint,
                    align: align
                };
            }
        });
        setDefaultOptions(SharedTooltip, { categoryFormat: '{0:d}' });
        var BarChartAnimation = Animation.extend({
            setup: function () {
                var ref = this;
                var element = ref.element;
                var options = ref.options;
                var bbox = element.bbox();
                if (bbox) {
                    this.origin = options.origin;
                    var axis = options.vertical ? Y : X;
                    var fromScale = this.fromScale = new GeometryPoint(1, 1);
                    fromScale[axis] = START_SCALE;
                    element.transform(transform().scale(fromScale.x, fromScale.y));
                } else {
                    this.abort();
                }
            },
            step: function (pos) {
                var scaleX = dataviz.interpolateValue(this.fromScale.x, 1, pos);
                var scaleY = dataviz.interpolateValue(this.fromScale.y, 1, pos);
                this.element.transform(transform().scale(scaleX, scaleY, this.origin));
            },
            abort: function () {
                Animation.fn.abort.call(this);
                this.element.transform(null);
            }
        });
        setDefaultOptions(BarChartAnimation, { duration: INITIAL_ANIMATION_DURATION });
        AnimationFactory.current.register(BAR, BarChartAnimation);
        var BubbleAnimation = Animation.extend({
            setup: function () {
                var center = this.center = this.element.bbox().center();
                this.element.transform(transform().scale(START_SCALE, START_SCALE, center));
            },
            step: function (pos) {
                this.element.transform(transform().scale(pos, pos, this.center));
            }
        });
        setDefaultOptions(BubbleAnimation, { easing: 'easeOutElastic' });
        AnimationFactory.current.register(BUBBLE, BubbleAnimation);
        var FadeInAnimation = Animation.extend({
            setup: function () {
                this.fadeTo = this.element.opacity();
                this.element.opacity(0);
            },
            step: function (pos) {
                this.element.opacity(pos * this.fadeTo);
            }
        });
        setDefaultOptions(FadeInAnimation, {
            duration: 200,
            easing: 'linear'
        });
        AnimationFactory.current.register(FADEIN, FadeInAnimation);
        var PieAnimation = Animation.extend({
            setup: function () {
                this.element.transform(transform().scale(START_SCALE, START_SCALE, this.options.center));
            },
            step: function (pos) {
                this.element.transform(transform().scale(pos, pos, this.options.center));
            }
        });
        setDefaultOptions(PieAnimation, {
            easing: 'easeOutElastic',
            duration: INITIAL_ANIMATION_DURATION
        });
        AnimationFactory.current.register(PIE, PieAnimation);
        var ScatterLineChart = ScatterChart.extend({
            render: function () {
                ScatterChart.fn.render.call(this);
                this.renderSegments();
            },
            createSegment: function (linePoints, currentSeries, seriesIx) {
                var style = currentSeries.style;
                var pointType;
                if (style === SMOOTH) {
                    pointType = SplineSegment;
                } else {
                    pointType = LineSegment;
                }
                return new pointType(linePoints, currentSeries, seriesIx);
            },
            animationPoints: function () {
                var points = ScatterChart.fn.animationPoints.call(this);
                return points.concat(this._segments);
            },
            createMissingValue: function (value, missingValues) {
                if (missingValues === ZERO) {
                    var missingValue = {
                        x: value.x,
                        y: value.y
                    };
                    if (!hasValue(missingValue.x)) {
                        missingValue.x = 0;
                    }
                    if (!hasValue(missingValue.y)) {
                        missingValue.y = 0;
                    }
                    return missingValue;
                }
            }
        });
        deepExtend(ScatterLineChart.prototype, LineChartMixin);
        var XYPlotArea = PlotAreaBase.extend({
            initFields: function () {
                this.namedXAxes = {};
                this.namedYAxes = {};
                this.xAxisRangeTracker = new AxisGroupRangeTracker();
                this.yAxisRangeTracker = new AxisGroupRangeTracker();
            },
            render: function (panes) {
                var this$1 = this;
                if (panes === void 0) {
                    panes = this.panes;
                }
                var seriesByPane = this.groupSeriesByPane();
                for (var i = 0; i < panes.length; i++) {
                    var pane = panes[i];
                    var paneSeries = seriesByPane[pane.options.name || 'default'] || [];
                    this$1.addToLegend(paneSeries);
                    var filteredSeries = this$1.filterVisibleSeries(paneSeries);
                    if (!filteredSeries) {
                        continue;
                    }
                    this$1.createScatterChart(filterSeriesByType(filteredSeries, SCATTER), pane);
                    this$1.createScatterLineChart(filterSeriesByType(filteredSeries, SCATTER_LINE), pane);
                    this$1.createBubbleChart(filterSeriesByType(filteredSeries, BUBBLE), pane);
                }
                this.createAxes(panes);
            },
            appendChart: function (chart, pane) {
                this.xAxisRangeTracker.update(chart.xAxisRanges);
                this.yAxisRangeTracker.update(chart.yAxisRanges);
                PlotAreaBase.fn.appendChart.call(this, chart, pane);
            },
            removeAxis: function (axis) {
                var axisName = axis.options.name;
                PlotAreaBase.fn.removeAxis.call(this, axis);
                if (axis.options.vertical) {
                    this.yAxisRangeTracker.reset(axisName);
                    delete this.namedYAxes[axisName];
                } else {
                    this.xAxisRangeTracker.reset(axisName);
                    delete this.namedXAxes[axisName];
                }
                if (axis === this.axisX) {
                    delete this.axisX;
                }
                if (axis === this.axisY) {
                    delete this.axisY;
                }
            },
            seriesPaneName: function (series) {
                var options = this.options;
                var xAxisName = series.xAxis;
                var xAxisOptions = [].concat(options.xAxis);
                var xAxis = grep(xAxisOptions, function (a) {
                    return a.name === xAxisName;
                })[0];
                var yAxisName = series.yAxis;
                var yAxisOptions = [].concat(options.yAxis);
                var yAxis = grep(yAxisOptions, function (a) {
                    return a.name === yAxisName;
                })[0];
                var panes = options.panes || [{}];
                var defaultPaneName = panes[0].name || 'default';
                var paneName = (xAxis || {}).pane || (yAxis || {}).pane || defaultPaneName;
                return paneName;
            },
            createScatterChart: function (series, pane) {
                if (series.length > 0) {
                    this.appendChart(new ScatterChart(this, {
                        series: series,
                        clip: pane.options.clip
                    }), pane);
                }
            },
            createScatterLineChart: function (series, pane) {
                if (series.length > 0) {
                    this.appendChart(new ScatterLineChart(this, {
                        series: series,
                        clip: pane.options.clip
                    }), pane);
                }
            },
            createBubbleChart: function (series, pane) {
                if (series.length > 0) {
                    this.appendChart(new BubbleChart(this, {
                        series: series,
                        clip: pane.options.clip
                    }), pane);
                }
            },
            createXYAxis: function (options, vertical, axisIndex) {
                var axisName = options.name;
                var namedAxes = vertical ? this.namedYAxes : this.namedXAxes;
                var tracker = vertical ? this.yAxisRangeTracker : this.xAxisRangeTracker;
                var axisOptions = deepExtend({}, options, { vertical: vertical });
                var isLog = equalsIgnoreCase(axisOptions.type, LOGARITHMIC);
                var defaultRange = tracker.query();
                var defaultAxisRange = isLog ? {
                    min: 0.1,
                    max: 1
                } : {
                    min: 0,
                    max: 1
                };
                var range = tracker.query(axisName) || defaultRange || defaultAxisRange;
                var typeSamples = [
                    axisOptions.min,
                    axisOptions.max
                ];
                var series = this.series;
                for (var seriesIx = 0; seriesIx < series.length; seriesIx++) {
                    var currentSeries = series[seriesIx];
                    var seriesAxisName = currentSeries[vertical ? 'yAxis' : 'xAxis'];
                    if (seriesAxisName === axisOptions.name || axisIndex === 0 && !seriesAxisName) {
                        var firstPointValue = SeriesBinder.current.bindPoint(currentSeries, 0).valueFields;
                        typeSamples.push(firstPointValue[vertical ? 'y' : 'x']);
                        break;
                    }
                }
                if (axisIndex === 0 && defaultRange) {
                    range.min = Math.min(range.min, defaultRange.min);
                    range.max = Math.max(range.max, defaultRange.max);
                }
                var inferredDate;
                for (var i = 0; i < typeSamples.length; i++) {
                    if (typeSamples[i] instanceof Date) {
                        inferredDate = true;
                        break;
                    }
                }
                var axisType;
                if (equalsIgnoreCase(axisOptions.type, DATE) || !axisOptions.type && inferredDate) {
                    axisType = dataviz.DateValueAxis;
                } else if (isLog) {
                    axisType = dataviz.LogarithmicAxis;
                } else {
                    axisType = dataviz.NumericAxis;
                }
                var axis = new axisType(range.min, range.max, axisOptions, this.chartService);
                axis.axisIndex = axisIndex;
                if (axisName) {
                    if (namedAxes[axisName]) {
                        throw new Error((vertical ? 'Y' : 'X') + ' axis with name ' + axisName + ' is already defined');
                    }
                    namedAxes[axisName] = axis;
                }
                this.appendAxis(axis);
                return axis;
            },
            createAxes: function (panes) {
                var this$1 = this;
                var options = this.options;
                var xAxesOptions = [].concat(options.xAxis);
                var xAxes = [];
                var yAxesOptions = [].concat(options.yAxis);
                var yAxes = [];
                for (var idx = 0; idx < xAxesOptions.length; idx++) {
                    var axisPane = this$1.findPane(xAxesOptions[idx].pane);
                    if (inArray(axisPane, panes)) {
                        xAxes.push(this$1.createXYAxis(xAxesOptions[idx], false, idx));
                    }
                }
                for (var idx$1 = 0; idx$1 < yAxesOptions.length; idx$1++) {
                    var axisPane$1 = this$1.findPane(yAxesOptions[idx$1].pane);
                    if (inArray(axisPane$1, panes)) {
                        yAxes.push(this$1.createXYAxis(yAxesOptions[idx$1], true, idx$1));
                    }
                }
                this.axisX = this.axisX || xAxes[0];
                this.axisY = this.axisY || yAxes[0];
            },
            _dispatchEvent: function (chart, e, eventType) {
                var coords = chart._eventCoordinates(e);
                var point = new Point(coords.x, coords.y);
                var allAxes = this.axes;
                var length = allAxes.length;
                var xValues = [];
                var yValues = [];
                for (var i = 0; i < length; i++) {
                    var axis = allAxes[i];
                    var values = axis.options.vertical ? yValues : xValues;
                    var currentValue = axis.getValue(point);
                    if (currentValue !== null) {
                        values.push(currentValue);
                    }
                }
                if (xValues.length > 0 && yValues.length > 0) {
                    chart.trigger(eventType, {
                        element: eventElement(e),
                        originalEvent: e,
                        x: singleItemOrArray(xValues),
                        y: singleItemOrArray(yValues)
                    });
                }
            },
            updateAxisOptions: function (axis, options) {
                var vertical = axis.options.vertical;
                var axes = this.groupAxes(this.panes);
                var index = (vertical ? axes.y : axes.x).indexOf(axis);
                var axisOptions = [].concat(vertical ? this.options.yAxis : this.options.xAxis)[index];
                deepExtend(axisOptions, options);
            }
        });
        setDefaultOptions(XYPlotArea, {
            xAxis: {},
            yAxis: {}
        });
        deepExtend(XYPlotArea.prototype, PlotAreaEventsMixin);
        var PieSegment = ChartElement.extend({
            init: function (value, sector, options) {
                ChartElement.fn.init.call(this, options);
                this.value = value;
                this.sector = sector;
            },
            render: function () {
                var labels = this.options.labels;
                var chartService = this.owner.chartService;
                var labelText = this.value;
                if (this._rendered || this.visible === false) {
                    return;
                }
                this._rendered = true;
                if (labels.template) {
                    var labelTemplate = TemplateService.compile(labels.template);
                    labelText = labelTemplate({
                        dataItem: this.dataItem,
                        category: this.category,
                        value: this.value,
                        series: this.series,
                        percentage: this.percentage
                    });
                } else if (labels.format) {
                    labelText = chartService.format.auto(labels.format, labelText);
                }
                if (labels.visible && labelText) {
                    if (labels.position === CENTER || labels.position === INSIDE_END) {
                        if (!labels.color) {
                            var brightnessValue = new Color(this.options.color).percBrightness();
                            if (brightnessValue > 180) {
                                labels.color = BLACK;
                            } else {
                                labels.color = WHITE;
                            }
                        }
                        if (!labels.background) {
                            labels.background = this.options.color;
                        }
                    } else {
                        var themeLabels = chartService.theme.seriesDefaults.labels;
                        labels.color = labels.color || themeLabels.color;
                        labels.background = labels.background || themeLabels.background;
                    }
                    this.label = new TextBox(labelText, deepExtend({}, labels, {
                        align: CENTER,
                        vAlign: '',
                        animation: {
                            type: FADEIN,
                            delay: this.animationDelay
                        }
                    }));
                    this.append(this.label);
                }
            },
            reflow: function (targetBox) {
                this.render();
                this.box = targetBox;
                this.reflowLabel();
            },
            reflowLabel: function () {
                var ref = this;
                var labelsOptions = ref.options.labels;
                var label = ref.label;
                var sector = this.sector.clone();
                var labelsDistance = labelsOptions.distance;
                var angle = sector.middle();
                if (label) {
                    var labelHeight = label.box.height();
                    var labelWidth = label.box.width();
                    var lp;
                    if (labelsOptions.position === CENTER) {
                        sector.radius = Math.abs((sector.radius - labelHeight) / 2) + labelHeight;
                        lp = sector.point(angle);
                        label.reflow(new Box(lp.x, lp.y - labelHeight / 2, lp.x, lp.y));
                    } else if (labelsOptions.position === INSIDE_END) {
                        sector.radius = sector.radius - labelHeight / 2;
                        lp = sector.point(angle);
                        label.reflow(new Box(lp.x, lp.y - labelHeight / 2, lp.x, lp.y));
                    } else {
                        var x1;
                        lp = sector.clone().expand(labelsDistance).point(angle);
                        if (lp.x >= sector.center.x) {
                            x1 = lp.x + labelWidth;
                            label.orientation = RIGHT;
                        } else {
                            x1 = lp.x - labelWidth;
                            label.orientation = LEFT;
                        }
                        label.reflow(new Box(x1, lp.y - labelHeight, lp.x, lp.y));
                    }
                }
            },
            createVisual: function () {
                var this$1 = this;
                var ref = this;
                var sector = ref.sector;
                var options = ref.options;
                ChartElement.fn.createVisual.call(this);
                if (this.value) {
                    if (options.visual) {
                        var startAngle = (sector.startAngle + 180) % 360;
                        var visual = options.visual({
                            category: this.category,
                            dataItem: this.dataItem,
                            value: this.value,
                            series: this.series,
                            percentage: this.percentage,
                            center: new GeometryPoint(sector.center.x, sector.center.y),
                            radius: sector.radius,
                            innerRadius: sector.innerRadius,
                            startAngle: startAngle,
                            endAngle: startAngle + sector.angle,
                            options: options,
                            sender: this.getSender(),
                            createVisual: function () {
                                var group = new Group();
                                this$1.createSegmentVisual(group);
                                return group;
                            }
                        });
                        if (visual) {
                            this.visual.append(visual);
                        }
                    } else {
                        this.createSegmentVisual(this.visual);
                    }
                }
            },
            createSegmentVisual: function (group) {
                var ref = this;
                var sector = ref.sector;
                var options = ref.options;
                var borderOptions = options.border || {};
                var border = borderOptions.width > 0 ? {
                    stroke: {
                        color: borderOptions.color,
                        width: borderOptions.width,
                        opacity: borderOptions.opacity,
                        dashType: borderOptions.dashType
                    }
                } : {};
                var color = options.color;
                var fill = {
                    color: color,
                    opacity: options.opacity
                };
                var visual = this.createSegment(sector, deepExtend({
                    fill: fill,
                    stroke: { opacity: options.opacity },
                    zIndex: options.zIndex
                }, border));
                group.append(visual);
                if (hasGradientOverlay(options)) {
                    group.append(this.createGradientOverlay(visual, {
                        baseColor: color,
                        fallbackFill: fill
                    }, deepExtend({
                        center: [
                            sector.center.x,
                            sector.center.y
                        ],
                        innerRadius: sector.innerRadius,
                        radius: sector.radius,
                        userSpace: true
                    }, options.overlay)));
                }
            },
            createSegment: function (sector, options) {
                if (options.singleSegment) {
                    return new drawing.Circle(new geometry.Circle(new GeometryPoint(sector.center.x, sector.center.y), sector.radius), options);
                }
                return dataviz.ShapeBuilder.current.createRing(sector, options);
            },
            createAnimation: function () {
                var ref = this;
                var options = ref.options;
                var center = ref.sector.center;
                deepExtend(options, {
                    animation: {
                        center: [
                            center.x,
                            center.y
                        ],
                        delay: this.animationDelay
                    }
                });
                ChartElement.fn.createAnimation.call(this);
            },
            createHighlight: function (options) {
                var highlight = this.options.highlight || {};
                var border = highlight.border || {};
                return this.createSegment(this.sector, deepExtend({}, options, {
                    fill: {
                        color: highlight.color,
                        opacity: highlight.opacity
                    },
                    stroke: {
                        opacity: border.opacity,
                        width: border.width,
                        color: border.color
                    }
                }));
            },
            highlightVisual: function () {
                return this.visual.children[0];
            },
            highlightVisualArgs: function () {
                var sector = this.sector;
                return {
                    options: this.options,
                    radius: sector.radius,
                    innerRadius: sector.innerRadius,
                    center: new GeometryPoint(sector.center.x, sector.center.y),
                    startAngle: sector.startAngle,
                    endAngle: sector.angle + sector.startAngle,
                    visual: this.visual
                };
            },
            tooltipAnchor: function () {
                var sector = this.sector.clone().expand(TOOLTIP_OFFSET);
                var midAndle = sector.middle();
                var midPoint = sector.point(midAndle);
                return {
                    point: midPoint,
                    align: tooltipAlignment(midAndle + 180)
                };
            },
            formatValue: function (format) {
                return this.owner.formatPointValue(this, format);
            }
        });
        var RAD_30 = round(dataviz.rad(30), DEFAULT_PRECISION);
        var RAD_60 = round(dataviz.rad(60), DEFAULT_PRECISION);
        function tooltipAlignment(angle) {
            var radians = dataviz.rad(angle);
            var sine = round(Math.sin(radians), DEFAULT_PRECISION);
            var cosine = round(Math.cos(radians), DEFAULT_PRECISION);
            var horizontal;
            if (Math.abs(sine) > RAD_60) {
                horizontal = CENTER;
            } else if (cosine < 0) {
                horizontal = RIGHT;
            } else {
                horizontal = LEFT;
            }
            var vertical;
            if (Math.abs(sine) < RAD_30) {
                vertical = CENTER;
            } else if (sine < 0) {
                vertical = BOTTOM;
            } else {
                vertical = TOP;
            }
            return {
                horizontal: horizontal,
                vertical: vertical
            };
        }
        setDefaultOptions(PieSegment, {
            color: WHITE,
            overlay: { gradient: 'roundedBevel' },
            border: { width: 0.5 },
            labels: {
                visible: false,
                distance: 35,
                font: datavizConstants.DEFAULT_FONT,
                margin: getSpacing(0.5),
                align: CIRCLE,
                zIndex: 1,
                position: OUTSIDE_END
            },
            animation: { type: PIE },
            highlight: {
                visible: true,
                border: { width: 1 }
            },
            visible: true
        });
        deepExtend(PieSegment.prototype, PointEventsMixin);
        var PieChartMixin = {
            createLegendItem: function (value, point, options) {
                var legendOptions = this.options.legend || {};
                var labelsOptions = legendOptions.labels || {};
                var inactiveItems = legendOptions.inactiveItems || {};
                var inactiveItemsLabels = inactiveItems.labels || {};
                if (options && options.visibleInLegend !== false) {
                    var pointVisible = options.visible !== false;
                    var labelTemplate = pointVisible ? labelsOptions.template : inactiveItemsLabels.template || labelsOptions.template;
                    var text = options.category || '';
                    if (labelTemplate) {
                        text = TemplateService.compile(labelTemplate)({
                            text: text,
                            series: options.series,
                            dataItem: options.dataItem,
                            percentage: options.percentage,
                            value: value
                        });
                    }
                    var itemLabelOptions, markerColor;
                    if (pointVisible) {
                        itemLabelOptions = {};
                        markerColor = point.color;
                    } else {
                        itemLabelOptions = {
                            color: inactiveItemsLabels.color,
                            font: inactiveItemsLabels.font
                        };
                        markerColor = (inactiveItems.markers || {}).color;
                    }
                    if (text) {
                        this.legendItems.push({
                            pointIndex: options.index,
                            text: text,
                            series: options.series,
                            markerColor: markerColor,
                            labels: itemLabelOptions
                        });
                    }
                }
            }
        };
        function segmentVisible(series, fields, index) {
            var visible = fields.visible;
            if (defined(visible)) {
                return visible;
            }
            var pointVisibility = series.pointVisibility;
            if (pointVisibility) {
                return pointVisibility[index];
            }
        }
        function seriesTotal(series) {
            var data = series.data;
            var sum = 0;
            for (var i = 0; i < data.length; i++) {
                var pointData = SeriesBinder.current.bindPoint(series, i);
                var value = pointData.valueFields.value;
                if (isString(value)) {
                    value = parseFloat(value);
                }
                var visible = segmentVisible(series, pointData.fields, i);
                if (isNumber(value) && visible !== false) {
                    sum += Math.abs(value);
                }
            }
            return sum;
        }
        var PIE_SECTOR_ANIM_DELAY = 70;
        var PieChart = ChartElement.extend({
            init: function (plotArea, options) {
                ChartElement.fn.init.call(this, options);
                this.plotArea = plotArea;
                this.chartService = plotArea.chartService;
                this.points = [];
                this.legendItems = [];
                this.render();
            },
            render: function () {
                this.traverseDataPoints(this.addValue.bind(this));
            },
            traverseDataPoints: function (callback) {
                var this$1 = this;
                var ref = this;
                var options = ref.options;
                var seriesColors = ref.plotArea.options.seriesColors;
                if (seriesColors === void 0) {
                    seriesColors = [];
                }
                var colorsCount = seriesColors.length;
                var series = options.series;
                var seriesCount = series.length;
                for (var seriesIx = 0; seriesIx < seriesCount; seriesIx++) {
                    var currentSeries = series[seriesIx];
                    var data = currentSeries.data;
                    var total = seriesTotal(currentSeries);
                    var anglePerValue = 360 / total;
                    var currentAngle = void 0;
                    if (defined(currentSeries.startAngle)) {
                        currentAngle = currentSeries.startAngle;
                    } else {
                        currentAngle = options.startAngle;
                    }
                    if (seriesIx !== seriesCount - 1) {
                        if (currentSeries.labels.position === OUTSIDE_END) {
                            currentSeries.labels.position = CENTER;
                        }
                    }
                    for (var i = 0; i < data.length; i++) {
                        var pointData = SeriesBinder.current.bindPoint(currentSeries, i);
                        var value = pointData.valueFields.value;
                        var plotValue = Math.abs(value);
                        var fields = pointData.fields;
                        var angle = plotValue * anglePerValue;
                        var explode = data.length !== 1 && Boolean(fields.explode);
                        if (!isFunction(currentSeries.color)) {
                            currentSeries.color = fields.color || seriesColors[i % colorsCount];
                        }
                        var visible = segmentVisible(currentSeries, fields, i);
                        callback(value, new dataviz.Ring(null, 0, 0, currentAngle, angle), {
                            owner: this$1,
                            category: fields.category || '',
                            index: i,
                            series: currentSeries,
                            seriesIx: seriesIx,
                            dataItem: data[i],
                            percentage: total !== 0 ? plotValue / total : 0,
                            explode: explode,
                            visibleInLegend: fields.visibleInLegend,
                            visible: visible,
                            zIndex: seriesCount - seriesIx,
                            animationDelay: this$1.animationDelay(i, seriesIx, seriesCount)
                        });
                        if (visible !== false) {
                            currentAngle += angle;
                        }
                    }
                }
            },
            evalSegmentOptions: function (options, value, fields) {
                var series = fields.series;
                evalOptions(options, {
                    value: value,
                    series: series,
                    dataItem: fields.dataItem,
                    category: fields.category,
                    percentage: fields.percentage
                }, {
                    defaults: series._defaults,
                    excluded: [
                        'data',
                        'template',
                        'visual',
                        'toggle'
                    ]
                });
            },
            addValue: function (value, sector, fields) {
                var segmentOptions = deepExtend({}, fields.series, { index: fields.index });
                this.evalSegmentOptions(segmentOptions, value, fields);
                this.createLegendItem(value, segmentOptions, fields);
                if (fields.visible === false) {
                    return;
                }
                var segment = new PieSegment(value, sector, segmentOptions);
                $.extend(segment, fields);
                this.append(segment);
                this.points.push(segment);
            },
            reflow: function (targetBox) {
                var ref = this;
                var options = ref.options;
                var points = ref.points;
                var seriesConfigs = ref.seriesConfigs;
                if (seriesConfigs === void 0) {
                    seriesConfigs = [];
                }
                var count = points.length;
                var box = targetBox.clone();
                var space = 5;
                var minWidth = Math.min(box.width(), box.height());
                var halfMinWidth = minWidth / 2;
                var defaultPadding = minWidth - minWidth * 0.85;
                var newBox = new Box(box.x1, box.y1, box.x1 + minWidth, box.y1 + minWidth);
                var newBoxCenter = newBox.center();
                var boxCenter = box.center();
                var seriesCount = options.series.length;
                var leftSideLabels = [];
                var rightSideLabels = [];
                var padding = valueOrDefault(options.padding, defaultPadding);
                padding = padding > halfMinWidth - space ? halfMinWidth - space : padding;
                newBox.translate(boxCenter.x - newBoxCenter.x, boxCenter.y - newBoxCenter.y);
                var radius = halfMinWidth - padding;
                var center = new Point(radius + newBox.x1 + padding, radius + newBox.y1 + padding);
                for (var i = 0; i < count; i++) {
                    var segment = points[i];
                    var sector = segment.sector;
                    var seriesIndex = segment.seriesIx;
                    sector.radius = radius;
                    sector.center = center;
                    if (seriesConfigs.length) {
                        var seriesConfig = seriesConfigs[seriesIndex];
                        sector.innerRadius = seriesConfig.innerRadius;
                        sector.radius = seriesConfig.radius;
                    }
                    if (seriesIndex === seriesCount - 1 && segment.explode) {
                        sector.center = sector.clone().setRadius(sector.radius * 0.15).point(sector.middle());
                    }
                    segment.reflow(newBox);
                    var label = segment.label;
                    if (label) {
                        if (label.options.position === OUTSIDE_END) {
                            if (seriesIndex === seriesCount - 1) {
                                if (label.orientation === RIGHT) {
                                    rightSideLabels.push(label);
                                } else {
                                    leftSideLabels.push(label);
                                }
                            }
                        }
                    }
                }
                if (leftSideLabels.length > 0) {
                    leftSideLabels.sort(this.labelComparator(true));
                    this.leftLabelsReflow(leftSideLabels);
                }
                if (rightSideLabels.length > 0) {
                    rightSideLabels.sort(this.labelComparator(false));
                    this.rightLabelsReflow(rightSideLabels);
                }
                this.box = newBox;
            },
            leftLabelsReflow: function (labels) {
                var distances = this.distanceBetweenLabels(labels);
                this.distributeLabels(distances, labels);
            },
            rightLabelsReflow: function (labels) {
                var distances = this.distanceBetweenLabels(labels);
                this.distributeLabels(distances, labels);
            },
            distanceBetweenLabels: function (labels) {
                var segment = last(this.points);
                var sector = segment.sector;
                var count = labels.length - 1;
                var lr = sector.radius + segment.options.labels.distance;
                var distances = [];
                var firstBox = labels[0].box;
                var distance = round(firstBox.y1 - (sector.center.y - lr - firstBox.height() - firstBox.height() / 2));
                distances.push(distance);
                for (var i = 0; i < count; i++) {
                    var secondBox = labels[i + 1].box;
                    firstBox = labels[i].box;
                    distance = round(secondBox.y1 - firstBox.y2);
                    distances.push(distance);
                }
                distance = round(sector.center.y + lr - labels[count].box.y2 - labels[count].box.height() / 2);
                distances.push(distance);
                return distances;
            },
            distributeLabels: function (distances, labels) {
                var this$1 = this;
                var count = distances.length;
                var left, right, remaining;
                for (var i = 0; i < count; i++) {
                    remaining = -distances[i];
                    left = right = i;
                    while (remaining > 0 && (left >= 0 || right < count)) {
                        remaining = this$1._takeDistance(distances, i, --left, remaining);
                        remaining = this$1._takeDistance(distances, i, ++right, remaining);
                    }
                }
                this.reflowLabels(distances, labels);
            },
            _takeDistance: function (distances, anchor, position, amount) {
                var result = amount;
                if (distances[position] > 0) {
                    var available = Math.min(distances[position], result);
                    result -= available;
                    distances[position] -= available;
                    distances[anchor] += available;
                }
                return result;
            },
            reflowLabels: function (distances, labels) {
                var this$1 = this;
                var segment = last(this.points);
                var sector = segment.sector;
                var labelOptions = segment.options.labels;
                var labelsCount = labels.length;
                var labelDistance = labelOptions.distance;
                var boxY = sector.center.y - (sector.radius + labelDistance) - labels[0].box.height();
                var boxX;
                distances[0] += 2;
                for (var i = 0; i < labelsCount; i++) {
                    var label = labels[i];
                    var box = label.box;
                    boxY += distances[i];
                    boxX = this$1.hAlignLabel(box.x2, sector.clone().expand(labelDistance), boxY, boxY + box.height(), label.orientation === RIGHT);
                    if (label.orientation === RIGHT) {
                        if (labelOptions.align !== CIRCLE) {
                            boxX = sector.radius + sector.center.x + labelDistance;
                        }
                        label.reflow(new Box(boxX + box.width(), boxY, boxX, boxY));
                    } else {
                        if (labelOptions.align !== CIRCLE) {
                            boxX = sector.center.x - sector.radius - labelDistance;
                        }
                        label.reflow(new Box(boxX - box.width(), boxY, boxX, boxY));
                    }
                    boxY += box.height();
                }
            },
            createVisual: function () {
                var this$1 = this;
                var ref = this;
                var connectors = ref.options.connectors;
                var points = ref.points;
                var count = points.length;
                var space = 4;
                ChartElement.fn.createVisual.call(this);
                this._connectorLines = [];
                for (var i = 0; i < count; i++) {
                    var segment = points[i];
                    var sector = segment.sector;
                    var label = segment.label;
                    var angle = sector.middle();
                    var connectorsColor = (segment.options.connectors || {}).color || connectors.color;
                    if (label) {
                        var connectorLine = new Path({
                            stroke: {
                                color: connectorsColor,
                                width: connectors.width
                            },
                            animation: {
                                type: FADEIN,
                                delay: segment.animationDelay
                            }
                        });
                        if (label.options.position === OUTSIDE_END && segment.value !== 0) {
                            var box = label.box;
                            var centerPoint = sector.center;
                            var start = sector.point(angle);
                            var middle = new Point(box.x1, box.center().y);
                            var sr = void 0, end = void 0, crossing = void 0;
                            start = sector.clone().expand(connectors.padding).point(angle);
                            connectorLine.moveTo(start.x, start.y);
                            if (label.orientation === RIGHT) {
                                end = new Point(box.x1 - connectors.padding, box.center().y);
                                crossing = intersection(centerPoint, start, middle, end);
                                middle = new Point(end.x - space, end.y);
                                crossing = crossing || middle;
                                crossing.x = Math.min(crossing.x, middle.x);
                                if (this$1.pointInCircle(crossing, sector.center, sector.radius + space) || crossing.x < sector.center.x) {
                                    sr = sector.center.x + sector.radius + space;
                                    if (segment.options.labels.align !== COLUMN) {
                                        if (sr < middle.x) {
                                            connectorLine.lineTo(sr, start.y);
                                        } else {
                                            connectorLine.lineTo(start.x + space * 2, start.y);
                                        }
                                    } else {
                                        connectorLine.lineTo(sr, start.y);
                                    }
                                    connectorLine.lineTo(middle.x, end.y);
                                } else {
                                    crossing.y = end.y;
                                    connectorLine.lineTo(crossing.x, crossing.y);
                                }
                            } else {
                                end = new Point(box.x2 + connectors.padding, box.center().y);
                                crossing = intersection(centerPoint, start, middle, end);
                                middle = new Point(end.x + space, end.y);
                                crossing = crossing || middle;
                                crossing.x = Math.max(crossing.x, middle.x);
                                if (this$1.pointInCircle(crossing, sector.center, sector.radius + space) || crossing.x > sector.center.x) {
                                    sr = sector.center.x - sector.radius - space;
                                    if (segment.options.labels.align !== COLUMN) {
                                        if (sr > middle.x) {
                                            connectorLine.lineTo(sr, start.y);
                                        } else {
                                            connectorLine.lineTo(start.x - space * 2, start.y);
                                        }
                                    } else {
                                        connectorLine.lineTo(sr, start.y);
                                    }
                                    connectorLine.lineTo(middle.x, end.y);
                                } else {
                                    crossing.y = end.y;
                                    connectorLine.lineTo(crossing.x, crossing.y);
                                }
                            }
                            connectorLine.lineTo(end.x, end.y);
                            this$1._connectorLines.push(connectorLine);
                            this$1.visual.append(connectorLine);
                        }
                    }
                }
            },
            labelComparator: function (reverse) {
                var reverseValue = reverse ? -1 : 1;
                return function (a, b) {
                    var first = (a.parent.sector.middle() + 270) % 360;
                    var second = (b.parent.sector.middle() + 270) % 360;
                    return (first - second) * reverseValue;
                };
            },
            hAlignLabel: function (originalX, sector, y1, y2, direction) {
                var radius = sector.radius;
                var sector_center = sector.center;
                var cx = sector_center.x;
                var cy = sector_center.y;
                var t = Math.min(Math.abs(cy - y1), Math.abs(cy - y2));
                if (t > radius) {
                    return originalX;
                }
                return cx + Math.sqrt(radius * radius - t * t) * (direction ? 1 : -1);
            },
            pointInCircle: function (point, center, radius) {
                return Math.pow(center.x - point.x, 2) + Math.pow(center.y - point.y, 2) < Math.pow(radius, 2);
            },
            formatPointValue: function (point, format) {
                return this.chartService.format.auto(format, point.value);
            },
            animationDelay: function (categoryIndex) {
                return categoryIndex * PIE_SECTOR_ANIM_DELAY;
            }
        });
        function intersection(a1, a2, b1, b2) {
            var uat = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x);
            var ub = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
            var result;
            if (ub !== 0) {
                var ua = uat / ub;
                result = new Point(a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y));
            }
            return result;
        }
        setDefaultOptions(PieChart, {
            startAngle: 90,
            connectors: {
                width: 2,
                color: '#939393',
                padding: 8
            },
            inactiveItems: {
                markers: {},
                labels: {}
            }
        });
        deepExtend(PieChart.prototype, PieChartMixin);
        var PiePlotArea = PlotAreaBase.extend({
            render: function () {
                this.createPieChart(this.series);
            },
            createPieChart: function (series) {
                var firstSeries = series[0];
                var pieChart = new PieChart(this, {
                    series: series,
                    padding: firstSeries.padding,
                    startAngle: firstSeries.startAngle,
                    connectors: firstSeries.connectors,
                    legend: this.options.legend
                });
                this.appendChart(pieChart);
            },
            appendChart: function (chart, pane) {
                PlotAreaBase.fn.appendChart.call(this, chart, pane);
                append(this.options.legend.items, chart.legendItems);
            }
        });
        var DonutSegment = PieSegment.extend({
            reflowLabel: function () {
                var ref = this;
                var labelsOptions = ref.options.labels;
                var label = ref.label;
                var sector = this.sector.clone();
                var angle = sector.middle();
                if (label) {
                    var labelHeight = label.box.height();
                    if (labelsOptions.position === CENTER) {
                        sector.radius -= (sector.radius - sector.innerRadius) / 2;
                        var lp = sector.point(angle);
                        label.reflow(new Box(lp.x, lp.y - labelHeight / 2, lp.x, lp.y));
                    } else {
                        PieSegment.fn.reflowLabel.call(this);
                    }
                }
            },
            createSegment: function (sector, options) {
                return dataviz.ShapeBuilder.current.createRing(sector, options);
            }
        });
        setDefaultOptions(DonutSegment, {
            overlay: { gradient: 'roundedGlass' },
            labels: { position: CENTER },
            animation: { type: PIE }
        });
        deepExtend(DonutSegment.prototype, PointEventsMixin);
        var DONUT_SECTOR_ANIM_DELAY = 50;
        var DonutChart = PieChart.extend({
            addValue: function (value, sector, fields) {
                var segmentOptions = deepExtend({}, fields.series, { index: fields.index });
                this.evalSegmentOptions(segmentOptions, value, fields);
                this.createLegendItem(value, segmentOptions, fields);
                if (!value || fields.visible === false) {
                    return;
                }
                var segment = new DonutSegment(value, sector, segmentOptions);
                $.extend(segment, fields);
                this.append(segment);
                this.points.push(segment);
            },
            reflow: function (targetBox) {
                var this$1 = this;
                var options = this.options;
                var box = targetBox.clone();
                var space = 5;
                var minWidth = Math.min(box.width(), box.height());
                var halfMinWidth = minWidth / 2;
                var defaultPadding = minWidth - minWidth * 0.85;
                var series = options.series;
                var seriesCount = series.length;
                var padding = valueOrDefault(options.padding, defaultPadding);
                padding = padding > halfMinWidth - space ? halfMinWidth - space : padding;
                var totalSize = halfMinWidth - padding;
                var seriesWithoutSize = 0;
                var holeSize;
                for (var i = 0; i < seriesCount; i++) {
                    var currentSeries = series[i];
                    if (i === 0) {
                        if (defined(currentSeries.holeSize)) {
                            holeSize = currentSeries.holeSize;
                            totalSize -= currentSeries.holeSize;
                        }
                    }
                    if (defined(currentSeries.size)) {
                        totalSize -= currentSeries.size;
                    } else {
                        seriesWithoutSize++;
                    }
                    if (defined(currentSeries.margin) && i !== seriesCount - 1) {
                        totalSize -= currentSeries.margin;
                    }
                }
                if (!defined(holeSize)) {
                    var currentSize = (halfMinWidth - padding) / (seriesCount + 0.75);
                    holeSize = currentSize * 0.75;
                    totalSize -= holeSize;
                }
                var innerRadius = holeSize;
                var margin = 0;
                var size, radius;
                this.seriesConfigs = [];
                for (var i$1 = 0; i$1 < seriesCount; i$1++) {
                    var currentSeries$1 = series[i$1];
                    size = valueOrDefault(currentSeries$1.size, totalSize / seriesWithoutSize);
                    innerRadius += margin;
                    radius = innerRadius + size;
                    this$1.seriesConfigs.push({
                        innerRadius: innerRadius,
                        radius: radius
                    });
                    margin = currentSeries$1.margin || 0;
                    innerRadius = radius;
                }
                PieChart.fn.reflow.call(this, targetBox);
            },
            animationDelay: function (categoryIndex, seriesIndex, seriesCount) {
                return categoryIndex * DONUT_SECTOR_ANIM_DELAY + INITIAL_ANIMATION_DURATION * (seriesIndex + 1) / (seriesCount + 1);
            }
        });
        setDefaultOptions(DonutChart, {
            startAngle: 90,
            connectors: {
                width: 2,
                color: '#939393',
                padding: 8
            }
        });
        var DonutPlotArea = PiePlotArea.extend({
            render: function () {
                this.createDonutChart(this.series);
            },
            createDonutChart: function (series) {
                var firstSeries = series[0];
                var donutChart = new DonutChart(this, {
                    series: series,
                    padding: firstSeries.padding,
                    connectors: firstSeries.connectors,
                    legend: this.options.legend
                });
                this.appendChart(donutChart);
            }
        });
        var DEFAULT_PADDING = 0.15;
        var PolarPlotAreaBase = PlotAreaBase.extend({
            initFields: function () {
                this.valueAxisRangeTracker = new AxisGroupRangeTracker();
            },
            render: function () {
                this.addToLegend(this.series);
                this.createPolarAxis();
                this.createCharts();
                this.createValueAxis();
            },
            alignAxes: function () {
                var axis = this.valueAxis;
                var range = axis.range();
                var crossingValue = axis.options.reverse ? range.max : range.min;
                var slot = axis.getSlot(crossingValue);
                var center = this.polarAxis.getSlot(0).center;
                var axisBox = axis.box.translate(center.x - slot.x1, center.y - slot.y1);
                axis.reflow(axisBox);
            },
            createValueAxis: function () {
                var tracker = this.valueAxisRangeTracker;
                var defaultRange = tracker.query();
                var axisOptions = this.valueAxisOptions({
                    roundToMajorUnit: false,
                    zIndex: -1
                });
                var axisType, axisDefaultRange;
                if (axisOptions.type === LOGARITHMIC) {
                    axisType = dataviz.RadarLogarithmicAxis;
                    axisDefaultRange = {
                        min: 0.1,
                        max: 1
                    };
                } else {
                    axisType = dataviz.RadarNumericAxis;
                    axisDefaultRange = {
                        min: 0,
                        max: 1
                    };
                }
                var range = tracker.query(name) || defaultRange || axisDefaultRange;
                if (range && defaultRange) {
                    range.min = Math.min(range.min, defaultRange.min);
                    range.max = Math.max(range.max, defaultRange.max);
                }
                var valueAxis = new axisType(range.min, range.max, axisOptions, this.chartService);
                this.valueAxis = valueAxis;
                this.appendAxis(valueAxis);
            },
            reflowAxes: function () {
                var ref = this;
                var options = ref.options.plotArea;
                var valueAxis = ref.valueAxis;
                var polarAxis = ref.polarAxis;
                var box = ref.box;
                var defaultPadding = Math.min(box.width(), box.height()) * DEFAULT_PADDING;
                var padding = getSpacing(options.padding || {}, defaultPadding);
                var axisBox = box.clone().unpad(padding);
                var valueAxisBox = axisBox.clone().shrink(0, axisBox.height() / 2);
                polarAxis.reflow(axisBox);
                valueAxis.reflow(valueAxisBox);
                var heightDiff = valueAxis.lineBox().height() - valueAxis.box.height();
                valueAxis.reflow(valueAxis.box.unpad({ top: heightDiff }));
                this.axisBox = axisBox;
                this.alignAxes(axisBox);
            },
            backgroundBox: function () {
                return this.box;
            }
        });
        var PolarScatterChart = ScatterChart.extend({
            pointSlot: function (slotX, slotY) {
                var valueRadius = slotX.center.y - slotY.y1;
                var slot = Point.onCircle(slotX.center, slotX.startAngle, valueRadius);
                return new Box(slot.x, slot.y, slot.x, slot.y);
            }
        });
        setDefaultOptions(PolarScatterChart, { clip: false });
        var PolarLineChart = ScatterLineChart.extend({});
        PolarLineChart.prototype.pointSlot = PolarScatterChart.prototype.pointSlot;
        setDefaultOptions(PolarLineChart, { clip: false });
        var SplinePolarAreaSegment = SplineAreaSegment.extend({
            closeFill: function (fillPath) {
                var center = this._polarAxisCenter();
                fillPath.lineTo(center.x, center.y);
            },
            _polarAxisCenter: function () {
                var polarAxis = this.parent.plotArea.polarAxis;
                var center = polarAxis.box.center();
                return center;
            },
            strokeSegments: function () {
                var segments = this._strokeSegments;
                if (!segments) {
                    var center = this._polarAxisCenter();
                    var curveProcessor = new dataviz.CurveProcessor(false);
                    var linePoints = LineSegment.prototype.points.call(this);
                    linePoints.push(center);
                    segments = this._strokeSegments = curveProcessor.process(linePoints);
                    segments.pop();
                }
                return segments;
            }
        });
        var PolarAreaSegment = AreaSegment.extend({
            points: function () {
                var ref = this;
                var polarAxis = ref.parent.plotArea.polarAxis;
                var stackPoints = ref.stackPoints;
                var center = polarAxis.box.center();
                var points = LineSegment.prototype.points.call(this, stackPoints);
                points.unshift([
                    center.x,
                    center.y
                ]);
                points.push([
                    center.x,
                    center.y
                ]);
                return points;
            }
        });
        var PolarAreaChart = PolarLineChart.extend({
            createSegment: function (linePoints, currentSeries, seriesIx) {
                var style = (currentSeries.line || {}).style;
                var segment;
                if (style === SMOOTH) {
                    segment = new SplinePolarAreaSegment(linePoints, null, false, currentSeries, seriesIx);
                } else {
                    segment = new PolarAreaSegment(linePoints, [], currentSeries, seriesIx);
                }
                return segment;
            },
            createMissingValue: function (value, missingValues) {
                var missingValue;
                if (hasValue(value.x) && missingValues !== INTERPOLATE) {
                    missingValue = {
                        x: value.x,
                        y: value.y
                    };
                    if (missingValues === ZERO) {
                        missingValue.y = 0;
                    }
                }
                return missingValue;
            },
            seriesMissingValues: function (series) {
                return series.missingValues || ZERO;
            },
            _hasMissingValuesGap: function () {
                var this$1 = this;
                var series = this.options.series;
                for (var idx = 0; idx < series.length; idx++) {
                    if (this$1.seriesMissingValues(series[idx]) === GAP) {
                        return true;
                    }
                }
            },
            sortPoints: function (points) {
                var this$1 = this;
                points.sort(xComparer);
                if (this._hasMissingValuesGap()) {
                    for (var idx = 0; idx < points.length; idx++) {
                        var point = points[idx];
                        if (point) {
                            var value = point.value;
                            if (!hasValue(value.y) && this$1.seriesMissingValues(point.series) === GAP) {
                                delete points[idx];
                            }
                        }
                    }
                }
                return points;
            }
        });
        function xComparer(a, b) {
            return a.value.x - b.value.x;
        }
        var PolarPlotArea = PolarPlotAreaBase.extend({
            createPolarAxis: function () {
                var polarAxis = new dataviz.PolarAxis(this.options.xAxis, this.chartService);
                this.polarAxis = polarAxis;
                this.axisX = polarAxis;
                this.appendAxis(polarAxis);
            },
            valueAxisOptions: function (defaults) {
                return deepExtend(defaults, {
                    majorGridLines: { type: ARC },
                    minorGridLines: { type: ARC }
                }, this.options.yAxis);
            },
            createValueAxis: function () {
                PolarPlotAreaBase.fn.createValueAxis.call(this);
                this.axisY = this.valueAxis;
            },
            appendChart: function (chart, pane) {
                this.valueAxisRangeTracker.update(chart.yAxisRanges);
                PlotAreaBase.prototype.appendChart.call(this, chart, pane);
            },
            createCharts: function () {
                var series = this.filterVisibleSeries(this.series);
                var pane = this.panes[0];
                this.createLineChart(filterSeriesByType(series, [POLAR_LINE]), pane);
                this.createScatterChart(filterSeriesByType(series, [POLAR_SCATTER]), pane);
                this.createAreaChart(filterSeriesByType(series, [POLAR_AREA]), pane);
            },
            createLineChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var lineChart = new PolarLineChart(this, { series: series });
                this.appendChart(lineChart, pane);
            },
            createScatterChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var scatterChart = new PolarScatterChart(this, { series: series });
                this.appendChart(scatterChart, pane);
            },
            createAreaChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var areaChart = new PolarAreaChart(this, { series: series });
                this.appendChart(areaChart, pane);
            },
            _dispatchEvent: function (chart, e, eventType) {
                var coords = chart._eventCoordinates(e);
                var point = new Point(coords.x, coords.y);
                var xValue = this.axisX.getValue(point);
                var yValue = this.axisY.getValue(point);
                if (xValue !== null && yValue !== null) {
                    chart.trigger(eventType, {
                        element: eventElement(e),
                        x: xValue,
                        y: yValue
                    });
                }
            },
            createCrosshairs: function () {
            }
        });
        setDefaultOptions(PolarPlotArea, {
            xAxis: {},
            yAxis: {}
        });
        deepExtend(PolarPlotArea.prototype, PlotAreaEventsMixin);
        var RadarLineChart = LineChart.extend({
            pointSlot: function (categorySlot, valueSlot) {
                var valueRadius = categorySlot.center.y - valueSlot.y1;
                var slot = Point.onCircle(categorySlot.center, categorySlot.middle(), valueRadius);
                return new Box(slot.x, slot.y, slot.x, slot.y);
            },
            createSegment: function (linePoints, currentSeries, seriesIx) {
                var style = currentSeries.style;
                var pointType;
                if (style === SMOOTH) {
                    pointType = SplineSegment;
                } else {
                    pointType = LineSegment;
                }
                var segment = new pointType(linePoints, currentSeries, seriesIx);
                if (linePoints.length === currentSeries.data.length) {
                    segment.options.closed = true;
                }
                return segment;
            }
        });
        setDefaultOptions(RadarLineChart, { clip: false });
        var SplineRadarAreaSegment = SplineAreaSegment.extend({
            closeFill: function () {
            }
        });
        var RadarAreaSegment = AreaSegment.extend({
            points: function () {
                return LineSegment.prototype.points.call(this, this.stackPoints);
            }
        });
        var RadarAreaChart = RadarLineChart.extend({
            createSegment: function (linePoints, currentSeries, seriesIx, prevSegment) {
                var isStacked = this.options.isStacked;
                var style = (currentSeries.line || {}).style;
                var segment;
                if (style === SMOOTH) {
                    segment = new SplineRadarAreaSegment(linePoints, prevSegment, isStacked, currentSeries, seriesIx);
                    segment.options.closed = true;
                } else {
                    var stackPoints;
                    if (isStacked && seriesIx > 0 && prevSegment) {
                        stackPoints = prevSegment.linePoints.slice(0).reverse();
                    }
                    linePoints.push(linePoints[0]);
                    segment = new RadarAreaSegment(linePoints, stackPoints, currentSeries, seriesIx);
                }
                return segment;
            },
            seriesMissingValues: function (series) {
                return series.missingValues || ZERO;
            }
        });
        var RadarSegment = DonutSegment.extend({
            init: function (value, options) {
                DonutSegment.fn.init.call(this, value, null, options);
            }
        });
        setDefaultOptions(RadarSegment, {
            overlay: { gradient: 'none' },
            labels: { distance: 10 }
        });
        var RadarClusterLayout = ChartElement.extend({
            reflow: function (sector) {
                var ref = this;
                var options = ref.options;
                var children = ref.children;
                var gap = options.gap;
                var spacing = options.spacing;
                var count = children.length;
                var slots = count + gap + spacing * (count - 1);
                var slotAngle = sector.angle / slots;
                var angle = sector.startAngle + slotAngle * (gap / 2);
                for (var i = 0; i < count; i++) {
                    var slotSector = sector.clone();
                    slotSector.startAngle = angle;
                    slotSector.angle = slotAngle;
                    if (children[i].sector) {
                        slotSector.radius = children[i].sector.radius;
                    }
                    children[i].reflow(slotSector);
                    children[i].sector = slotSector;
                    angle += slotAngle + slotAngle * spacing;
                }
            }
        });
        setDefaultOptions(RadarClusterLayout, {
            gap: 1,
            spacing: 0
        });
        var RadarStackLayout = ChartElement.extend({
            reflow: function (sector) {
                var ref = this;
                var reverse = ref.options.reverse;
                var children = ref.children;
                var childrenCount = children.length;
                var first = reverse ? childrenCount - 1 : 0;
                var step = reverse ? -1 : 1;
                this.box = new Box();
                for (var i = first; i >= 0 && i < childrenCount; i += step) {
                    var childSector = children[i].sector;
                    childSector.startAngle = sector.startAngle;
                    childSector.angle = sector.angle;
                }
            }
        });
        var RadarBarChart = BarChart.extend({
            pointType: function () {
                return RadarSegment;
            },
            clusterType: function () {
                return RadarClusterLayout;
            },
            stackType: function () {
                return RadarStackLayout;
            },
            categorySlot: function (categoryAxis, categoryIx) {
                return categoryAxis.getSlot(categoryIx);
            },
            pointSlot: function (categorySlot, valueSlot) {
                var slot = categorySlot.clone();
                var y = categorySlot.center.y;
                slot.radius = y - valueSlot.y1;
                slot.innerRadius = y - valueSlot.y2;
                return slot;
            },
            reflowPoint: function (point, pointSlot) {
                point.sector = pointSlot;
                point.reflow();
            },
            createAnimation: function () {
                this.options.animation.center = this.box.toRect().center();
                BarChart.fn.createAnimation.call(this);
            }
        });
        RadarBarChart.prototype.reflow = CategoricalChart.prototype.reflow;
        setDefaultOptions(RadarBarChart, {
            clip: false,
            animation: { type: 'pie' }
        });
        var RadarPlotArea = PolarPlotAreaBase.extend({
            createPolarAxis: function () {
                var categoryAxis = new dataviz.RadarCategoryAxis(this.options.categoryAxis, this.chartService);
                this.polarAxis = categoryAxis;
                this.categoryAxis = categoryAxis;
                this.appendAxis(categoryAxis);
                this.aggregateCategories();
                this.createCategoryAxesLabels();
            },
            valueAxisOptions: function (defaults) {
                if (this._hasBarCharts) {
                    deepExtend(defaults, {
                        majorGridLines: { type: ARC },
                        minorGridLines: { type: ARC }
                    });
                }
                if (this._isStacked100) {
                    deepExtend(defaults, {
                        roundToMajorUnit: false,
                        labels: { format: 'P0' }
                    });
                }
                return deepExtend(defaults, this.options.valueAxis);
            },
            aggregateCategories: function () {
                CategoricalPlotArea.prototype.aggregateCategories.call(this, this.panes);
            },
            createCategoryAxesLabels: function () {
                CategoricalPlotArea.prototype.createCategoryAxesLabels.call(this, this.panes);
            },
            filterSeries: function (currentSeries) {
                return currentSeries;
            },
            createCharts: function () {
                var series = this.filterVisibleSeries(this.series);
                var pane = this.panes[0];
                this.createAreaChart(filterSeriesByType(series, [RADAR_AREA]), pane);
                this.createLineChart(filterSeriesByType(series, [RADAR_LINE]), pane);
                this.createBarChart(filterSeriesByType(series, [RADAR_COLUMN]), pane);
            },
            chartOptions: function (series) {
                var options = { series: series };
                var firstSeries = series[0];
                if (firstSeries) {
                    var filteredSeries = this.filterVisibleSeries(series);
                    var stack = firstSeries.stack;
                    options.isStacked = stack && filteredSeries.length > 1;
                    options.isStacked100 = stack && stack.type === '100%' && filteredSeries.length > 1;
                    if (options.isStacked100) {
                        this._isStacked100 = true;
                    }
                }
                return options;
            },
            createAreaChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var areaChart = new RadarAreaChart(this, this.chartOptions(series));
                this.appendChart(areaChart, pane);
            },
            createLineChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var lineChart = new RadarLineChart(this, this.chartOptions(series));
                this.appendChart(lineChart, pane);
            },
            createBarChart: function (series, pane) {
                if (series.length === 0) {
                    return;
                }
                var firstSeries = series[0];
                var options = this.chartOptions(series);
                options.gap = firstSeries.gap;
                options.spacing = firstSeries.spacing;
                var barChart = new RadarBarChart(this, options);
                this.appendChart(barChart, pane);
                this._hasBarCharts = true;
            },
            seriesCategoryAxis: function () {
                return this.categoryAxis;
            },
            _dispatchEvent: function (chart, e, eventType) {
                var coords = chart._eventCoordinates(e);
                var point = new Point(coords.x, coords.y);
                var category = this.categoryAxis.getCategory(point);
                var value = this.valueAxis.getValue(point);
                if (category !== null && value !== null) {
                    chart.trigger(eventType, {
                        element: eventElement(e),
                        category: category,
                        value: value
                    });
                }
            },
            createCrosshairs: function () {
            }
        });
        deepExtend(RadarPlotArea.prototype, PlotAreaEventsMixin, {
            appendChart: CategoricalPlotArea.prototype.appendChart,
            aggregateSeries: CategoricalPlotArea.prototype.aggregateSeries
        });
        setDefaultOptions(RadarPlotArea, {
            categoryAxis: { categories: [] },
            valueAxis: {}
        });
        var FunnelSegment = ChartElement.extend({
            init: function (value, options, segmentOptions) {
                ChartElement.fn.init.call(this, options);
                this.value = value;
                this.options.index = segmentOptions.index;
            },
            reflow: function (chartBox) {
                var points = this.points;
                var label = this.children[0];
                this.box = new Box(points[0].x, points[0].y, points[1].x, points[2].y);
                if (label) {
                    label.reflow(new Box(chartBox.x1, points[0].y, chartBox.x2, points[2].y));
                }
            },
            createVisual: function () {
                var this$1 = this;
                var options = this.options;
                var visual;
                ChartElement.fn.createVisual.call(this);
                if (options.visual) {
                    visual = options.visual({
                        category: this.category,
                        dataItem: this.dataItem,
                        value: this.value,
                        series: this.series,
                        percentage: this.percentage,
                        points: this.points,
                        options: options,
                        sender: this.getSender(),
                        createVisual: function () {
                            return this$1.createPath();
                        }
                    });
                } else {
                    visual = this.createPath();
                }
                if (visual) {
                    this.visual.append(visual);
                }
            },
            createPath: function () {
                var options = this.options;
                var border = options.border;
                var path = Path.fromPoints(this.points, {
                    fill: {
                        color: options.color,
                        opacity: options.opacity
                    },
                    stroke: {
                        color: border.color,
                        opacity: border.opacity,
                        width: border.width
                    }
                }).close();
                return path;
            },
            createHighlight: function (style) {
                return Path.fromPoints(this.points, style);
            },
            highlightVisual: function () {
                return this.visual.children[0];
            },
            highlightVisualArgs: function () {
                var path = Path.fromPoints(this.points).close();
                return {
                    options: this.options,
                    path: path
                };
            },
            tooltipAnchor: function () {
                var box = this.box;
                return {
                    point: new Point(box.center().x, box.y1),
                    align: {
                        horizontal: 'center',
                        vertical: 'top'
                    }
                };
            },
            formatValue: function (format) {
                var point = this;
                return point.owner.formatPointValue(point, format);
            }
        });
        setDefaultOptions(FunnelSegment, {
            color: WHITE,
            border: { width: 1 }
        });
        deepExtend(FunnelSegment.prototype, PointEventsMixin);
        var FunnelChart = ChartElement.extend({
            init: function (plotArea, options) {
                ChartElement.fn.init.call(this, options);
                this.plotArea = plotArea;
                this.points = [];
                this.labels = [];
                this.legendItems = [];
                this.render();
            },
            formatPointValue: function (point, format) {
                return this.chartService.format.auto(format, point.value);
            },
            render: function () {
                var this$1 = this;
                var ref = this;
                var options = ref.options;
                var seriesColors = ref.plotArea.options.seriesColors;
                if (seriesColors === void 0) {
                    seriesColors = [];
                }
                var series = options.series[0];
                var data = series.data;
                if (!data) {
                    return;
                }
                var total = seriesTotal(series);
                for (var i = 0; i < data.length; i++) {
                    var pointData = SeriesBinder.current.bindPoint(series, i);
                    var value = pointData.valueFields.value;
                    if (value === null || value === undefined) {
                        continue;
                    }
                    var fields = pointData.fields;
                    if (!isFunction(series.color)) {
                        series.color = fields.color || seriesColors[i % seriesColors.length];
                    }
                    var visible = segmentVisible(series, fields, i);
                    fields = deepExtend({
                        index: i,
                        owner: this$1,
                        series: series,
                        dataItem: data[i],
                        percentage: Math.abs(value) / total
                    }, fields, { visible: visible });
                    var segment = this$1.createSegment(value, fields);
                    var label = this$1.createLabel(value, fields);
                    if (segment && label) {
                        segment.append(label);
                    }
                }
            },
            evalSegmentOptions: function (options, value, fields) {
                var series = fields.series;
                evalOptions(options, {
                    value: value,
                    series: series,
                    dataItem: fields.dataItem,
                    index: fields.index
                }, {
                    defaults: series._defaults,
                    excluded: [
                        'data',
                        'toggle',
                        'visual'
                    ]
                });
            },
            createSegment: function (value, fields) {
                var seriesOptions = deepExtend({}, fields.series);
                this.evalSegmentOptions(seriesOptions, value, fields);
                this.createLegendItem(value, seriesOptions, fields);
                if (fields.visible !== false) {
                    var segment = new FunnelSegment(value, seriesOptions, fields);
                    $.extend(segment, fields);
                    this.append(segment);
                    this.points.push(segment);
                    return segment;
                }
            },
            createLabel: function (value, fields) {
                var series = fields.series;
                var dataItem = fields.dataItem;
                var labels = deepExtend({}, this.options.labels, series.labels);
                var text = value;
                if (labels.visible) {
                    if (labels.template) {
                        var labelTemplate = TemplateService.compile(labels.template);
                        text = labelTemplate({
                            dataItem: dataItem,
                            value: value,
                            percentage: fields.percentage,
                            category: fields.category,
                            series: series
                        });
                    } else if (labels.format) {
                        text = this.plotArea.chartService.format.auto(labels.format, text);
                    }
                    if (!labels.color) {
                        var brightnessValue = new Color(series.color).percBrightness();
                        if (brightnessValue > 180) {
                            labels.color = BLACK;
                        } else {
                            labels.color = WHITE;
                        }
                        if (!labels.background) {
                            labels.background = series.color;
                        }
                    }
                    this.evalSegmentOptions(labels, value, fields);
                    var textBox = new TextBox(text, deepExtend({ vAlign: labels.position }, labels));
                    this.labels.push(textBox);
                    return textBox;
                }
            },
            labelPadding: function () {
                var labels = this.labels;
                var padding = {
                    left: 0,
                    right: 0
                };
                for (var i = 0; i < labels.length; i++) {
                    var label = labels[i];
                    var align = label.options.align;
                    if (align !== CENTER) {
                        var width = labels[i].box.width();
                        if (align === LEFT) {
                            padding.left = Math.max(padding.left, width);
                        } else {
                            padding.right = Math.max(padding.right, width);
                        }
                    }
                }
                return padding;
            },
            dynamicSlopeReflow: function (box, width, totalHeight) {
                var ref = this;
                var options = ref.options;
                var segments = ref.points;
                var count = segments.length;
                var firstSegment = segments[0];
                var maxSegment = firstSegment;
                for (var idx = 0; idx < segments.length; idx++) {
                    if (segments[idx].percentage > maxSegment.percentage) {
                        maxSegment = segments[idx];
                    }
                }
                var lastUpperSide = firstSegment.percentage / maxSegment.percentage * width;
                var previousOffset = (width - lastUpperSide) / 2;
                var previousHeight = 0;
                for (var idx$1 = 0; idx$1 < count; idx$1++) {
                    var percentage = segments[idx$1].percentage;
                    var nextSegment = segments[idx$1 + 1];
                    var nextPercentage = nextSegment ? nextSegment.percentage : percentage;
                    var points = segments[idx$1].points = [];
                    var height = options.dynamicHeight ? totalHeight * percentage : totalHeight / count;
                    var offset = void 0;
                    if (!percentage) {
                        offset = nextPercentage ? 0 : width / 2;
                    } else {
                        offset = (width - lastUpperSide * (nextPercentage / percentage)) / 2;
                    }
                    offset = limitValue(offset, 0, width);
                    points.push(new GeometryPoint(box.x1 + previousOffset, box.y1 + previousHeight));
                    points.push(new GeometryPoint(box.x1 + width - previousOffset, box.y1 + previousHeight));
                    points.push(new GeometryPoint(box.x1 + width - offset, box.y1 + height + previousHeight));
                    points.push(new GeometryPoint(box.x1 + offset, box.y1 + height + previousHeight));
                    previousOffset = offset;
                    previousHeight += height + options.segmentSpacing;
                    lastUpperSide = limitValue(width - 2 * offset, 0, width);
                }
            },
            constantSlopeReflow: function (box, width, totalHeight) {
                var ref = this;
                var options = ref.options;
                var segments = ref.points;
                var count = segments.length;
                var decreasingWidth = options.neckRatio <= 1;
                var neckRatio = decreasingWidth ? options.neckRatio * width : width;
                var previousOffset = decreasingWidth ? 0 : (width - width / options.neckRatio) / 2;
                var topMostWidth = decreasingWidth ? width : width - previousOffset * 2;
                var finalNarrow = (topMostWidth - neckRatio) / 2;
                var previousHeight = 0;
                for (var idx = 0; idx < count; idx++) {
                    var points = segments[idx].points = [];
                    var percentage = segments[idx].percentage;
                    var offset = options.dynamicHeight ? finalNarrow * percentage : finalNarrow / count;
                    var height = options.dynamicHeight ? totalHeight * percentage : totalHeight / count;
                    points.push(new GeometryPoint(box.x1 + previousOffset, box.y1 + previousHeight));
                    points.push(new GeometryPoint(box.x1 + width - previousOffset, box.y1 + previousHeight));
                    points.push(new GeometryPoint(box.x1 + width - previousOffset - offset, box.y1 + height + previousHeight));
                    points.push(new GeometryPoint(box.x1 + previousOffset + offset, box.y1 + height + previousHeight));
                    previousOffset += offset;
                    previousHeight += height + options.segmentSpacing;
                }
            },
            reflow: function (chartBox) {
                var points = this.points;
                var count = points.length;
                if (!count) {
                    return;
                }
                var options = this.options;
                var box = chartBox.clone().unpad(this.labelPadding());
                var totalHeight = box.height() - options.segmentSpacing * (count - 1);
                var width = box.width();
                if (options.dynamicSlope) {
                    this.dynamicSlopeReflow(box, width, totalHeight);
                } else {
                    this.constantSlopeReflow(box, width, totalHeight);
                }
                for (var idx = 0; idx < count; idx++) {
                    points[idx].reflow(chartBox);
                }
            }
        });
        setDefaultOptions(FunnelChart, {
            neckRatio: 0.3,
            width: 300,
            dynamicSlope: false,
            dynamicHeight: true,
            segmentSpacing: 0,
            labels: {
                visible: false,
                align: CENTER,
                position: CENTER,
                zIndex: 1
            }
        });
        deepExtend(FunnelChart.prototype, PieChartMixin);
        var FunnelPlotArea = PlotAreaBase.extend({
            render: function () {
                this.createFunnelChart(this.series);
            },
            createFunnelChart: function (series) {
                var firstSeries = series[0];
                var funnelChart = new FunnelChart(this, {
                    series: series,
                    legend: this.options.legend,
                    neckRatio: firstSeries.neckRatio,
                    dynamicHeight: firstSeries.dynamicHeight,
                    dynamicSlope: firstSeries.dynamicSlope,
                    segmentSpacing: firstSeries.segmentSpacing,
                    highlight: firstSeries.highlight
                });
                this.appendChart(funnelChart);
            },
            appendChart: function (chart, pane) {
                PlotAreaBase.fn.appendChart.call(this, chart, pane);
                append(this.options.legend.items, chart.legendItems);
            }
        });
        var COLOR = 'color';
        var FIRST = 'first';
        var FROM = 'from';
        var MAX = 'max';
        var MIN = 'min';
        var NOTE_TEXT = 'noteText';
        var SUMMARY_FIELD = 'summary';
        var TO = 'to';
        PlotAreaFactory.current.register(CategoricalPlotArea, [
            BAR,
            COLUMN,
            LINE,
            VERTICAL_LINE,
            AREA,
            VERTICAL_AREA,
            CANDLESTICK,
            OHLC,
            BULLET,
            VERTICAL_BULLET,
            BOX_PLOT,
            VERTICAL_BOX_PLOT,
            RANGE_COLUMN,
            RANGE_BAR,
            WATERFALL,
            HORIZONTAL_WATERFALL
        ]);
        PlotAreaFactory.current.register(XYPlotArea, [
            SCATTER,
            SCATTER_LINE,
            BUBBLE
        ]);
        PlotAreaFactory.current.register(PiePlotArea, [PIE]);
        PlotAreaFactory.current.register(DonutPlotArea, [DONUT]);
        PlotAreaFactory.current.register(FunnelPlotArea, [FUNNEL]);
        PlotAreaFactory.current.register(PolarPlotArea, [
            POLAR_AREA,
            POLAR_LINE,
            POLAR_SCATTER
        ]);
        PlotAreaFactory.current.register(RadarPlotArea, [
            RADAR_AREA,
            RADAR_COLUMN,
            RADAR_LINE
        ]);
        SeriesBinder.current.register([
            BAR,
            COLUMN,
            LINE,
            VERTICAL_LINE,
            AREA,
            VERTICAL_AREA
        ], [VALUE], [
            CATEGORY,
            COLOR,
            NOTE_TEXT,
            ERROR_LOW_FIELD,
            ERROR_HIGH_FIELD
        ]);
        SeriesBinder.current.register([
            RANGE_COLUMN,
            RANGE_BAR
        ], [
            FROM,
            TO
        ], [
            CATEGORY,
            COLOR,
            NOTE_TEXT
        ]);
        SeriesBinder.current.register([
            WATERFALL,
            HORIZONTAL_WATERFALL
        ], [VALUE], [
            CATEGORY,
            COLOR,
            NOTE_TEXT,
            SUMMARY_FIELD
        ]);
        SeriesBinder.current.register([
            POLAR_AREA,
            POLAR_LINE,
            POLAR_SCATTER
        ], [
            X,
            Y
        ], [COLOR]);
        SeriesBinder.current.register([
            RADAR_AREA,
            RADAR_COLUMN,
            RADAR_LINE
        ], [VALUE], [COLOR]);
        SeriesBinder.current.register([FUNNEL], [VALUE], [
            CATEGORY,
            COLOR,
            'visibleInLegend',
            'visible'
        ]);
        DefaultAggregates.current.register([
            BAR,
            COLUMN,
            LINE,
            VERTICAL_LINE,
            AREA,
            VERTICAL_AREA,
            WATERFALL,
            HORIZONTAL_WATERFALL
        ], {
            value: MAX,
            color: FIRST,
            noteText: FIRST,
            errorLow: MIN,
            errorHigh: MAX
        });
        DefaultAggregates.current.register([
            RANGE_COLUMN,
            RANGE_BAR
        ], {
            from: MIN,
            to: MAX,
            color: FIRST,
            noteText: FIRST
        });
        DefaultAggregates.current.register([
            RADAR_AREA,
            RADAR_COLUMN,
            RADAR_LINE
        ], {
            value: MAX,
            color: FIRST
        });
        SeriesBinder.current.register([
            SCATTER,
            SCATTER_LINE,
            BUBBLE
        ], [
            X,
            Y
        ], [
            COLOR,
            NOTE_TEXT,
            X_ERROR_LOW_FIELD,
            X_ERROR_HIGH_FIELD,
            Y_ERROR_LOW_FIELD,
            Y_ERROR_HIGH_FIELD
        ]);
        SeriesBinder.current.register([BUBBLE], [
            X,
            Y,
            'size'
        ], [
            COLOR,
            CATEGORY,
            NOTE_TEXT
        ]);
        SeriesBinder.current.register([
            CANDLESTICK,
            OHLC
        ], [
            'open',
            'high',
            'low',
            'close'
        ], [
            CATEGORY,
            COLOR,
            'downColor',
            NOTE_TEXT
        ]);
        DefaultAggregates.current.register([
            CANDLESTICK,
            OHLC
        ], {
            open: MAX,
            high: MAX,
            low: MIN,
            close: MAX,
            color: FIRST,
            downColor: FIRST,
            noteText: FIRST
        });
        SeriesBinder.current.register([
            BOX_PLOT,
            VERTICAL_BOX_PLOT
        ], [
            'lower',
            'q1',
            'median',
            'q3',
            'upper',
            'mean',
            'outliers'
        ], [
            CATEGORY,
            COLOR,
            NOTE_TEXT
        ]);
        DefaultAggregates.current.register([
            BOX_PLOT,
            VERTICAL_BOX_PLOT
        ], {
            lower: MAX,
            q1: MAX,
            median: MAX,
            q3: MAX,
            upper: MAX,
            mean: MAX,
            outliers: FIRST,
            color: FIRST,
            noteText: FIRST
        });
        SeriesBinder.current.register([
            BULLET,
            VERTICAL_BULLET
        ], [
            'current',
            'target'
        ], [
            CATEGORY,
            COLOR,
            'visibleInLegend',
            NOTE_TEXT
        ]);
        DefaultAggregates.current.register([
            BULLET,
            VERTICAL_BULLET
        ], {
            current: MAX,
            target: MAX,
            color: FIRST,
            noteText: FIRST
        });
        SeriesBinder.current.register([
            PIE,
            DONUT
        ], [VALUE], [
            CATEGORY,
            COLOR,
            'explode',
            'visibleInLegend',
            'visible'
        ]);
        var AXIS_NAMES = [
            CATEGORY,
            VALUE,
            X,
            Y
        ];
        var MOUSEMOVE = 'mousemove';
        var CONTEXTMENU = 'contextmenu';
        var MOUSEMOVE_DELAY = 20;
        var Chart = Class.extend({
            init: function (element, userOptions, themeOptions, context) {
                var this$1 = this;
                if (context === void 0) {
                    context = {};
                }
                this.observers = [];
                this.addObserver(context.observer);
                this.chartService = new services.ChartService(this, context);
                this.chartService.theme = themeOptions;
                this._initElement(element);
                var options = deepExtend({}, this.options, userOptions);
                this._originalOptions = deepExtend({}, options);
                this._theme = themeOptions;
                this._initTheme(options, themeOptions);
                this._initSurface();
                this._initHandlers();
                this.bindCategories();
                dataviz.FontLoader.preloadFonts(userOptions, function () {
                    if (!this$1._destroyed) {
                        this$1._redraw();
                        this$1._attachEvents();
                    }
                });
            },
            _initElement: function (element) {
                this._setElementClass(element);
                element.style.position = 'relative';
                while (element.firstChild) {
                    element.removeChild(element.firstChild);
                }
                this.element = element;
            },
            _setElementClass: function (element) {
                dataviz.addClass(element, 'k-chart');
            },
            _initTheme: function (options, themeOptions) {
                var seriesCopies = [];
                var series = options.series || [];
                for (var i = 0; i < series.length; i++) {
                    seriesCopies.push($.extend({}, series[i]));
                }
                options.series = seriesCopies;
                resolveAxisAliases(options);
                this.applyDefaults(options, themeOptions);
                if (options.seriesColors === null) {
                    delete options.seriesColors;
                }
                this.options = deepExtend({}, themeOptions, options);
                this.applySeriesColors();
            },
            getSize: function () {
                return {
                    width: this.element.offsetWidth,
                    height: this.element.offsetHeight
                };
            },
            resize: function (force) {
                var size = this.getSize();
                var currentSize = this._size;
                if (force || (size.width > 0 || size.height > 0) && (!currentSize || size.width !== currentSize.width || size.height !== currentSize.height)) {
                    this._size = size;
                    this._resize(size, force);
                    this.trigger('resize', size);
                }
            },
            _resize: function () {
                this._noTransitionsRedraw();
            },
            redraw: function (paneName) {
                this.applyDefaults(this.options);
                this.applySeriesColors();
                if (paneName) {
                    var plotArea = this._model._plotArea;
                    var pane = plotArea.findPane(paneName);
                    plotArea.redraw(pane);
                } else {
                    this._redraw();
                }
            },
            getAxis: function (name) {
                var axes = this._plotArea.axes;
                for (var idx = 0; idx < axes.length; idx++) {
                    if (axes[idx].options.name === name) {
                        return new ChartAxis(axes[idx]);
                    }
                }
            },
            findAxisByName: function (name) {
                return this.getAxis(name);
            },
            plotArea: function () {
                return new ChartPlotArea(this._plotArea);
            },
            toggleHighlight: function (show, filter) {
                var plotArea = this._plotArea;
                var firstSeries = (plotArea.srcSeries || plotArea.series || [])[0];
                var points;
                if (isFunction(filter)) {
                    points = plotArea.filterPoints(filter);
                } else {
                    var seriesName, categoryName;
                    if (isObject(filter)) {
                        seriesName = filter.series;
                        categoryName = filter.category;
                    } else {
                        seriesName = categoryName = filter;
                    }
                    if (firstSeries.type === DONUT) {
                        points = pointByCategoryName(plotArea.pointsBySeriesName(seriesName), categoryName);
                    } else if (firstSeries.type === PIE || firstSeries.type === FUNNEL) {
                        points = pointByCategoryName((plotArea.charts[0] || {}).points, categoryName);
                    } else {
                        points = plotArea.pointsBySeriesName(seriesName);
                    }
                }
                if (points) {
                    this.togglePointsHighlight(show, points);
                }
            },
            togglePointsHighlight: function (show, points) {
                var highlight = this._highlight;
                for (var idx = 0; idx < points.length; idx++) {
                    highlight.togglePointHighlight(points[idx], show);
                }
            },
            showTooltip: function (filter) {
                var shared = this._sharedTooltip();
                var ref = this;
                var tooltip = ref._tooltip;
                var plotArea = ref._plotArea;
                var point, categoryIndex;
                if (isFunction(filter)) {
                    point = plotArea.findPoint(filter);
                    if (point && shared) {
                        categoryIndex = point.categoryIx;
                    }
                } else if (shared && defined(filter)) {
                    categoryIndex = plotArea.categoryAxis.categoryIndex(filter);
                }
                if (shared) {
                    if (categoryIndex >= 0) {
                        var points = this._plotArea.pointsByCategoryIndex(categoryIndex);
                        tooltip.showAt(points);
                    }
                } else if (point) {
                    tooltip.show(point);
                }
            },
            hideTooltip: function () {
                this._tooltip.hide();
            },
            _initSurface: function () {
                var surface = this.surface;
                var wrap = this._surfaceWrap();
                var chartArea = this.options.chartArea;
                if (chartArea.width) {
                    dataviz.elementSize(wrap, { width: chartArea.width });
                }
                if (chartArea.height) {
                    dataviz.elementSize(wrap, { height: chartArea.height });
                }
                if (!surface || surface.options.type !== this.options.renderAs) {
                    if (surface) {
                        surface.destroy();
                    }
                    this.surface = drawing.Surface.create(wrap, { type: this.options.renderAs });
                } else {
                    this.surface.clear();
                    this.surface.resize();
                }
            },
            _surfaceWrap: function () {
                return this.element;
            },
            _redraw: function () {
                var model = this._getModel();
                this._destroyView();
                this._model = model;
                this._plotArea = model._plotArea;
                model.renderVisual();
                if (this.options.transitions !== false) {
                    model.traverse(function (element) {
                        if (element.animation) {
                            element.animation.setup();
                        }
                    });
                }
                this._initSurface();
                this.surface.draw(model.visual);
                if (this.options.transitions !== false) {
                    model.traverse(function (element) {
                        if (element.animation) {
                            element.animation.play();
                        }
                    });
                }
                this._tooltip = this._createTooltip();
                this._highlight = new Highlight();
                this._setupSelection();
                this._createPannable();
                this._createZoomSelection();
                this._createMousewheelZoom();
                this.trigger(RENDER);
                if (!this._navState) {
                    this._cancelDomEvents();
                }
            },
            exportVisual: function (options) {
                var visual;
                if (options && (options.width || options.height)) {
                    var chartArea = this.options.chartArea;
                    var originalChartArea = this._originalOptions.chartArea;
                    deepExtend(chartArea, options);
                    var model = this._getModel();
                    chartArea.width = originalChartArea.width;
                    chartArea.height = originalChartArea.height;
                    model.renderVisual();
                    visual = model.visual;
                } else {
                    visual = this.surface.exportVisual();
                }
                return visual;
            },
            _sharedTooltip: function () {
                return this._plotArea instanceof CategoricalPlotArea && this.options.tooltip.shared;
            },
            _createPannable: function () {
                var options = this.options;
                if (options.pannable !== false) {
                    this._pannable = new Pannable(this._plotArea, options.pannable);
                }
            },
            _createZoomSelection: function () {
                var zoomable = this.options.zoomable;
                var selection = (zoomable || {}).selection;
                if (zoomable !== false && selection !== false) {
                    this._zoomSelection = new ZoomSelection(this, selection);
                }
            },
            _createMousewheelZoom: function () {
                var zoomable = this.options.zoomable;
                var mousewheel = (zoomable || {}).mousewheel;
                if (zoomable !== false && mousewheel !== false) {
                    this._mousewheelZoom = new MousewheelZoom(this, mousewheel);
                }
            },
            _createTooltip: function () {
                var ref = this;
                var tooltipOptions = ref.options.tooltip;
                var tooltip;
                if (this._sharedTooltip()) {
                    tooltip = this._createSharedTooltip(tooltipOptions);
                } else {
                    tooltip = new Tooltip(this.chartService, tooltipOptions);
                }
                return tooltip;
            },
            _createSharedTooltip: function (options) {
                return new SharedTooltip(this._plotArea, options);
            },
            applyDefaults: function (options, themeOptions) {
                applyAxisDefaults(options, themeOptions);
                applySeriesDefaults(options, themeOptions);
            },
            applySeriesColors: function () {
                var options = this.options;
                var series = options.series;
                var colors = options.seriesColors || [];
                for (var i = 0; i < series.length; i++) {
                    var currentSeries = series[i];
                    var seriesColor = colors[i % colors.length];
                    var defaults = currentSeries._defaults;
                    currentSeries.color = currentSeries.color || seriesColor;
                    if (defaults) {
                        defaults.color = defaults.color || seriesColor;
                    }
                }
            },
            _getModel: function () {
                var options = this.options;
                var plotArea = this._createPlotArea();
                var model = new dataviz.RootElement(this._modelOptions());
                model.chart = this;
                model._plotArea = plotArea;
                dataviz.Title.buildTitle(options.title, model);
                if (options.legend.visible) {
                    model.append(new Legend(plotArea.options.legend, this.chartService));
                }
                model.append(plotArea);
                model.reflow();
                return model;
            },
            _modelOptions: function () {
                var ref = this;
                var options = ref.options;
                var element = ref.element;
                var size = dataviz.elementSize(element);
                this._size = null;
                return deepExtend({
                    width: Math.floor(size.width) || datavizConstants.DEFAULT_WIDTH,
                    height: Math.floor(size.height) || datavizConstants.DEFAULT_HEIGHT,
                    transitions: options.transitions
                }, options.chartArea);
            },
            _createPlotArea: function (skipSeries) {
                var options = this.options;
                var plotArea = PlotAreaFactory.current.create(skipSeries ? [] : options.series, options, this.chartService);
                return plotArea;
            },
            _hasSelection: function () {
                return this._selections && this._selections.length;
            },
            _setupSelection: function () {
                var this$1 = this;
                var ref = this;
                var axes = ref._plotArea.axes;
                var selections = this._selections = [];
                for (var i = 0; i < axes.length; i++) {
                    var axis = axes[i];
                    var options = axis.options;
                    if (axis instanceof CategoryAxis && options.select && !options.vertical) {
                        var min = 0;
                        var max = options.categories.length - 1;
                        if (axis instanceof DateCategoryAxis) {
                            min = options.categories[min];
                            max = options.categories[max];
                        }
                        if (!options.justified) {
                            if (axis instanceof DateCategoryAxis) {
                                max = dataviz.addDuration(max, 1, options.baseUnit, options.weekStartDay);
                            } else {
                                max++;
                            }
                        }
                        var selection = new Selection(this$1, axis, deepExtend({
                            min: min,
                            max: max
                        }, options.select));
                        selections.push(selection);
                    }
                }
            },
            _selectStart: function (e) {
                return this.trigger(SELECT_START, e);
            },
            _select: function (e) {
                return this.trigger(SELECT, e);
            },
            _selectEnd: function (e) {
                return this.trigger(SELECT_END, e);
            },
            _initHandlers: function () {
                this._clickHandler = this._click.bind(this);
                this._mousewheelHandler = this._mousewheel.bind(this);
                this._surfaceMouseenterHandler = this._mouseover.bind(this);
                this._surfaceMouseleaveHandler = this._mouseout.bind(this);
                this._mousemove = kendo.throttle(this._mousemove.bind(this), MOUSEMOVE_DELAY);
            },
            addObserver: function (observer) {
                if (observer) {
                    this.observers.push(observer);
                }
            },
            removeObserver: function (observer) {
                var index = this.observers.indexOf(observer);
                if (index >= 0) {
                    this.observers.splice(index, 1);
                }
            },
            requiresHandlers: function (eventNames) {
                var observers = this.observers;
                for (var idx = 0; idx < observers.length; idx++) {
                    if (observers[idx].requiresHandlers(eventNames)) {
                        return true;
                    }
                }
            },
            trigger: function (name, args) {
                if (args === void 0) {
                    args = {};
                }
                if (name === SHOW_TOOLTIP) {
                    args.anchor.point = this._toDocumentCoordinates(args.anchor.point);
                }
                args.sender = this;
                var observers = this.observers;
                var isDefaultPrevented = false;
                for (var idx = 0; idx < observers.length; idx++) {
                    if (observers[idx].trigger(name, args)) {
                        isDefaultPrevented = true;
                    }
                }
                return isDefaultPrevented;
            },
            _attachEvents: function () {
                var ref = this;
                var element = ref.element;
                var surface = ref.surface;
                surface.bind('mouseenter', this._surfaceMouseenterHandler);
                surface.bind('mouseleave', this._surfaceMouseleaveHandler);
                var obj;
                bindEvents(element, (obj = {}, obj[CONTEXTMENU] = this._clickHandler, obj[MOUSEWHEEL] = this._mousewheelHandler, obj));
                if (this._shouldAttachMouseMove()) {
                    var obj$1;
                    bindEvents(element, (obj$1 = {}, obj$1[MOUSEMOVE] = this._mousemove, obj$1));
                }
                this.domEvents = services.DomEventsBuilder.create(this.element, {
                    start: this._start.bind(this),
                    move: this._move.bind(this),
                    end: this._end.bind(this),
                    tap: this._tap.bind(this),
                    gesturestart: this._gesturestart.bind(this),
                    gesturechange: this._gesturechange.bind(this),
                    gestureend: this._gestureend.bind(this)
                });
            },
            _cancelDomEvents: function () {
                if (this.domEvents && this.domEvents.cancel) {
                    this.domEvents.cancel();
                }
            },
            _gesturestart: function (e) {
                if (this._mousewheelZoom && !this._stopDragEvent(e)) {
                    this._gestureDistance = e.distance;
                    this._unsetActivePoint();
                    this.surface.suspendTracking();
                }
            },
            _gestureend: function (e) {
                if (this._zooming && !this._stopDragEvent(e)) {
                    if (this.surface) {
                        this.surface.resumeTracking();
                    }
                    this._zooming = false;
                    this.trigger(ZOOM_END, {});
                }
            },
            _gesturechange: function (e) {
                var mousewheelZoom = this._mousewheelZoom;
                if (mousewheelZoom && !this._stopDragEvent(e)) {
                    e.preventDefault();
                    var previousGestureDistance = this._gestureDistance;
                    var scaleDelta = -e.distance / previousGestureDistance + 1;
                    if (Math.abs(scaleDelta) >= 0.1) {
                        scaleDelta = Math.round(scaleDelta * 10);
                        this._gestureDistance = e.distance;
                        var args = {
                            delta: scaleDelta,
                            axisRanges: axisRanges(this._plotArea.axes),
                            originalEvent: e
                        };
                        if (this._zooming || !this.trigger(ZOOM_START, args)) {
                            if (!this._zooming) {
                                this._zooming = true;
                            }
                            var ranges = args.axisRanges = mousewheelZoom.updateRanges(scaleDelta);
                            if (ranges && !this.trigger(ZOOM, args)) {
                                mousewheelZoom.zoom();
                            }
                        }
                    }
                }
            },
            _mouseout: function (e) {
                if (e.element) {
                    var element = this._drawingChartElement(e.element, e);
                    if (element && element.leave) {
                        element.leave(this, e.originalEvent);
                    }
                }
            },
            _start: function (e) {
                var coords = this._eventCoordinates(e);
                if (this._stopDragEvent(e) || !this._plotArea.backgroundContainsPoint(coords)) {
                    return;
                }
                if (this.requiresHandlers([
                        DRAG_START,
                        DRAG,
                        DRAG_END
                    ])) {
                    this._startNavigation(e, coords, DRAG_START);
                }
                if (this._pannable && this._pannable.start(e)) {
                    this.surface.suspendTracking();
                    this._unsetActivePoint();
                    this._suppressHover = true;
                }
                if (this._zoomSelection) {
                    if (this._zoomSelection.start(e)) {
                        this.trigger(ZOOM_START, {
                            axisRanges: axisRanges(this._plotArea.axes),
                            originalEvent: e
                        });
                    }
                }
            },
            _move: function (e) {
                var ref = this;
                var state = ref._navState;
                var pannable = ref._pannable;
                if (this._stopDragEvent(e)) {
                    return;
                }
                if (pannable) {
                    var ranges = pannable.move(e);
                    if (ranges && !this.trigger(DRAG, {
                            axisRanges: ranges,
                            originalEvent: e
                        })) {
                        pannable.pan();
                    }
                } else if (state) {
                    var ranges$1 = {};
                    var axes = state.axes;
                    for (var i = 0; i < axes.length; i++) {
                        var currentAxis = axes[i];
                        var axisName = currentAxis.options.name;
                        if (axisName) {
                            var axis = currentAxis.options.vertical ? e.y : e.x;
                            var delta = axis.startLocation - axis.location;
                            if (delta !== 0) {
                                ranges$1[currentAxis.options.name] = currentAxis.translateRange(delta);
                            }
                        }
                    }
                    state.axisRanges = ranges$1;
                    this.trigger(DRAG, {
                        axisRanges: ranges$1,
                        originalEvent: e
                    });
                }
                if (this._zoomSelection) {
                    this._zoomSelection.move(e);
                }
            },
            _end: function (e) {
                if (this._stopDragEvent(e)) {
                    return;
                }
                var pannable = this._pannable;
                if (pannable && pannable.end(e)) {
                    this.surface.resumeTracking();
                    this.trigger(DRAG_END, {
                        axisRanges: axisRanges(this._plotArea.axes),
                        originalEvent: e
                    });
                    this._suppressHover = false;
                } else {
                    this._endNavigation(e, DRAG_END);
                }
                if (this._zoomSelection) {
                    var ranges = this._zoomSelection.end(e);
                    if (ranges && !this.trigger(ZOOM, {
                            axisRanges: ranges,
                            originalEvent: e
                        })) {
                        this._zoomSelection.zoom();
                        this.trigger(ZOOM_END, {
                            axisRanges: ranges,
                            originalEvent: e
                        });
                    }
                }
            },
            _stopDragEvent: function () {
                return this._hasSelection();
            },
            _mousewheel: function (e) {
                var this$1 = this;
                var delta = dataviz.mousewheelDelta(e);
                var mousewheelZoom = this._mousewheelZoom;
                var coords = this._eventCoordinates(e);
                if (!this._plotArea.backgroundContainsPoint(coords)) {
                    return;
                }
                if (mousewheelZoom) {
                    var args = {
                        delta: delta,
                        axisRanges: axisRanges(this._plotArea.axes),
                        originalEvent: e
                    };
                    if (this._zooming || !this.trigger(ZOOM_START, args)) {
                        e.preventDefault();
                        if (!this._zooming) {
                            this._unsetActivePoint();
                            this.surface.suspendTracking();
                            this._zooming = true;
                        }
                        if (this._mwTimeout) {
                            clearTimeout(this._mwTimeout);
                        }
                        args.axisRanges = mousewheelZoom.updateRanges(delta);
                        if (args.axisRanges && !this.trigger(ZOOM, args)) {
                            mousewheelZoom.zoom();
                        }
                        this._mwTimeout = setTimeout(function () {
                            this$1.trigger(ZOOM_END, args);
                            this$1._zooming = false;
                            if (this$1.surface) {
                                this$1.surface.resumeTracking();
                            }
                        }, MOUSEWHEEL_DELAY);
                    }
                } else {
                    var state = this._navState;
                    if (!state) {
                        var prevented = this._startNavigation(e, coords, ZOOM_START);
                        if (!prevented) {
                            state = this._navState;
                        }
                    }
                    if (state) {
                        var totalDelta = state.totalDelta || delta;
                        state.totalDelta = totalDelta + delta;
                        var axes = this._navState.axes;
                        var ranges = {};
                        for (var i = 0; i < axes.length; i++) {
                            var currentAxis = axes[i];
                            var axisName = currentAxis.options.name;
                            if (axisName) {
                                ranges[axisName] = currentAxis.scaleRange(-totalDelta);
                            }
                        }
                        this.trigger(ZOOM, {
                            delta: delta,
                            axisRanges: ranges,
                            originalEvent: e
                        });
                        if (this._mwTimeout) {
                            clearTimeout(this._mwTimeout);
                        }
                        this._mwTimeout = setTimeout(function () {
                            this$1._endNavigation(e, ZOOM_END);
                        }, MOUSEWHEEL_DELAY);
                    }
                }
            },
            _startNavigation: function (e, coords, chartEvent) {
                var plotArea = this._model._plotArea;
                var pane = plotArea.findPointPane(coords);
                var axes = plotArea.axes.slice(0);
                if (!pane) {
                    return;
                }
                var ranges = axisRanges(axes);
                var prevented = this.trigger(chartEvent, {
                    axisRanges: ranges,
                    originalEvent: e
                });
                if (prevented) {
                    this._cancelDomEvents();
                } else {
                    this._suppressHover = true;
                    this._unsetActivePoint();
                    this._navState = {
                        axisRanges: ranges,
                        pane: pane,
                        axes: axes
                    };
                }
            },
            _endNavigation: function (e, chartEvent) {
                if (this._navState) {
                    this.trigger(chartEvent, {
                        axisRanges: this._navState.axisRanges,
                        originalEvent: e
                    });
                    this._suppressHover = false;
                    this._navState = null;
                }
            },
            _getChartElement: function (e, match) {
                var element = this.surface.eventTarget(e);
                if (element) {
                    return this._drawingChartElement(element, e, match);
                }
            },
            _drawingChartElement: function (element, e, match) {
                var current = element;
                var chartElement;
                while (current && !chartElement) {
                    chartElement = current.chartElement;
                    current = current.parent;
                }
                if (chartElement) {
                    if (chartElement.aliasFor) {
                        chartElement = chartElement.aliasFor(e, this._eventCoordinates(e));
                    }
                    if (match) {
                        chartElement = chartElement.closest(match);
                    }
                    return chartElement;
                }
            },
            _eventCoordinates: function (e) {
                var coordinates = dataviz.eventCoordinates(e);
                return this._toModelCoordinates(coordinates.x, coordinates.y);
            },
            _elementPadding: function () {
                if (!this._padding) {
                    var ref = elementStyles(this.element, [
                        'paddingLeft',
                        'paddingTop'
                    ]);
                    var paddingLeft = ref.paddingLeft;
                    var paddingTop = ref.paddingTop;
                    this._padding = {
                        top: paddingTop,
                        left: paddingLeft
                    };
                }
                return this._padding;
            },
            _toDocumentCoordinates: function (point) {
                var padding = this._elementPadding();
                var offset = dataviz.elementOffset(this.element);
                return {
                    left: round(point.x + padding.left + offset.left),
                    top: round(point.y + padding.top + offset.top)
                };
            },
            _toModelCoordinates: function (clientX, clientY) {
                var element = this.element;
                var offset = dataviz.elementOffset(element);
                var padding = this._elementPadding();
                return new Point(clientX - offset.left - padding.left, clientY - offset.top - padding.top);
            },
            _tap: function (e) {
                var this$1 = this;
                var drawingElement = this.surface.eventTarget(e);
                var element = this._drawingChartElement(drawingElement, e);
                if (this._activePoint === element) {
                    this._propagateClick(element, e);
                } else {
                    if (!this._startHover(drawingElement, e)) {
                        this._unsetActivePoint();
                    }
                    this._propagateClick(element, e);
                }
                this.handlingTap = true;
                setTimeout(function () {
                    this$1.handlingTap = false;
                }, 0);
            },
            _click: function (e) {
                var element = this._getChartElement(e);
                this._propagateClick(element, e);
            },
            _propagateClick: function (element, e) {
                var this$1 = this;
                var current = element;
                while (current) {
                    if (current.click) {
                        current.click(this$1, e);
                    }
                    current = current.parent;
                }
            },
            _startHover: function (element, e) {
                var chartElement = this._drawingChartElement(element, e);
                var ref = this;
                var tooltip = ref._tooltip;
                var highlight = ref._highlight;
                if (this._suppressHover || !highlight || highlight.isHighlighted(chartElement) || this._sharedTooltip()) {
                    return false;
                }
                var point = this._drawingChartElement(element, e, function (element) {
                    return element.hover && !(element instanceof PlotAreaBase);
                });
                if (point && !point.hover(this, e)) {
                    this._activePoint = point;
                    var tooltipOptions = deepExtend({}, tooltipOptions, point.options.tooltip);
                    if (tooltipOptions.visible) {
                        tooltip.show(point);
                    }
                    highlight.show(point);
                    return point;
                }
            },
            _mouseover: function (e) {
                var point = this._startHover(e.element, e.originalEvent);
                if (point && point.tooltipTracking) {
                    this._mouseMoveTrackHandler = this._mouseMoveTrackHandler || this._mouseMoveTracking.bind(this);
                    var obj;
                    bindEvents(document, (obj = {}, obj[MOUSEMOVE] = this._mouseMoveTrackHandler, obj));
                }
            },
            _mouseMoveTracking: function (e) {
                var ref = this;
                var options = ref.options;
                var tooltip = ref._tooltip;
                var highlight = ref._highlight;
                var point = ref._activePoint;
                var coords = this._eventCoordinates(e);
                if (this._plotArea.box.containsPoint(coords)) {
                    if (point && point.tooltipTracking && point.series && point.parent.getNearestPoint) {
                        var seriesPoint = point.parent.getNearestPoint(coords.x, coords.y, point.seriesIx);
                        if (seriesPoint && seriesPoint !== point) {
                            seriesPoint.hover(this, e);
                            this._activePoint = seriesPoint;
                            var tooltipOptions = deepExtend({}, options.tooltip, point.options.tooltip);
                            if (tooltipOptions.visible) {
                                tooltip.show(seriesPoint);
                            }
                            highlight.show(seriesPoint);
                        }
                    }
                } else {
                    var obj;
                    unbindEvents(document, (obj = {}, obj[MOUSEMOVE] = this._mouseMoveTrackHandler, obj));
                    this._unsetActivePoint();
                }
            },
            _mousemove: function (e) {
                var coords = this._eventCoordinates(e);
                this._trackCrosshairs(coords);
                if (this._plotArea.hover) {
                    this._plotArea.hover(this, e);
                }
                if (this._sharedTooltip()) {
                    this._trackSharedTooltip(coords, e);
                }
            },
            _trackCrosshairs: function (coords) {
                var crosshairs = this._plotArea.crosshairs;
                for (var i = 0; i < crosshairs.length; i++) {
                    var current = crosshairs[i];
                    if (current.box.containsPoint(coords)) {
                        current.showAt(coords);
                    } else {
                        current.hide();
                    }
                }
            },
            _trackSharedTooltip: function (coords, e) {
                var ref = this;
                var tooltipOptions = ref.options.tooltip;
                var plotArea = ref._plotArea;
                var categoryAxis = ref._plotArea.categoryAxis;
                var tooltip = ref._tooltip;
                var highlight = ref._highlight;
                if (plotArea.box.containsPoint(coords)) {
                    var index = categoryAxis.pointCategoryIndex(coords);
                    if (index !== this._tooltipCategoryIx) {
                        var points = plotArea.pointsByCategoryIndex(index);
                        var pointArgs = points.map(function (point) {
                            return point.eventArgs(e);
                        });
                        var hoverArgs = pointArgs[0] || {};
                        hoverArgs.categoryPoints = pointArgs;
                        if (points.length > 0 && !this.trigger(SERIES_HOVER, hoverArgs)) {
                            if (tooltipOptions.visible) {
                                tooltip.showAt(points, coords);
                            }
                            highlight.show(points);
                        } else {
                            tooltip.hide();
                        }
                        this._tooltipCategoryIx = index;
                    }
                }
            },
            hideElements: function () {
                var ref = this;
                var plotArea = ref._plotArea;
                var tooltip = ref._tooltip;
                var highlight = ref._highlight;
                this._mousemove.cancel();
                plotArea.hideCrosshairs();
                highlight.hide();
                tooltip.hide();
                delete this._tooltipCategoryIx;
            },
            _unsetActivePoint: function () {
                var ref = this;
                var tooltip = ref._tooltip;
                var highlight = ref._highlight;
                this._activePoint = null;
                if (tooltip) {
                    tooltip.hide();
                }
                if (highlight) {
                    highlight.hide();
                }
            },
            _deferRedraw: function () {
                this._redraw();
            },
            _clearRedrawTimeout: function () {
                if (this._redrawTimeout) {
                    clearInterval(this._redrawTimeout);
                    this._redrawTimeout = null;
                }
            },
            bindCategories: function () {
                var this$1 = this;
                var options = this.options;
                var definitions = [].concat(options.categoryAxis);
                for (var axisIx = 0; axisIx < definitions.length; axisIx++) {
                    var axis = definitions[axisIx];
                    if (axis.autoBind !== false) {
                        this$1.bindCategoryAxisFromSeries(axis, axisIx);
                    }
                }
            },
            bindCategoryAxisFromSeries: function (axis, axisIx) {
                var this$1 = this;
                var series = this.options.series;
                var seriesLength = series.length;
                var uniqueCategories = {};
                var items = [];
                var dateAxis;
                for (var seriesIx = 0; seriesIx < seriesLength; seriesIx++) {
                    var s = series[seriesIx];
                    var onAxis = s.categoryAxis === axis.name || !s.categoryAxis && axisIx === 0;
                    var data = s.data;
                    var dataLength = data.length;
                    if (s.categoryField && onAxis && dataLength > 0) {
                        dateAxis = isDateAxis(axis, getField(s.categoryField, data[0]));
                        var getFn = dateAxis ? getDateField : getField;
                        for (var dataIx = 0; dataIx < dataLength; dataIx++) {
                            var dataRow = data[dataIx];
                            var category = getFn(s.categoryField, dataRow, this$1.chartService.intl);
                            if (dateAxis || !uniqueCategories[category]) {
                                items.push([
                                    category,
                                    dataRow
                                ]);
                                if (!dateAxis) {
                                    uniqueCategories[category] = true;
                                }
                            }
                        }
                    }
                }
                if (items.length > 0) {
                    if (dateAxis) {
                        items = uniqueDates(items, function (a, b) {
                            return dataviz.dateComparer(a[0], b[0]);
                        });
                    }
                    var result = transpose(items);
                    axis.categories = result[0];
                }
            },
            _isBindable: function (series) {
                var valueFields = SeriesBinder.current.valueFields(series);
                var result = true;
                for (var i = 0; i < valueFields.length; i++) {
                    var field = valueFields[i];
                    if (field === VALUE) {
                        field = 'field';
                    } else {
                        field = field + 'Field';
                    }
                    if (!defined(series[field])) {
                        result = false;
                        break;
                    }
                }
                return result;
            },
            _noTransitionsRedraw: function () {
                var options = this.options;
                var transitionsState;
                if (options.transitions) {
                    options.transitions = false;
                    transitionsState = true;
                }
                this._redraw();
                if (transitionsState) {
                    options.transitions = true;
                }
            },
            _legendItemHover: function (seriesIndex, pointIndex) {
                var ref = this;
                var plotArea = ref._plotArea;
                var highlight = ref._highlight;
                var currentSeries = (plotArea.srcSeries || plotArea.series)[seriesIndex];
                var items;
                if (inArray(currentSeries.type, [
                        PIE,
                        DONUT,
                        FUNNEL
                    ])) {
                    items = plotArea.findPoint(function (point) {
                        return point.series.index === seriesIndex && point.index === pointIndex;
                    });
                } else {
                    items = plotArea.pointsBySeriesIndex(seriesIndex);
                }
                highlight.show(items);
            },
            _shouldAttachMouseMove: function () {
                return this._plotArea.crosshairs.length || this._tooltip && this._sharedTooltip() || this.requiresHandlers([PLOT_AREA_HOVER]);
            },
            updateMouseMoveHandler: function () {
                var obj;
                unbindEvents(this.element, (obj = {}, obj[MOUSEMOVE] = this._mousemove, obj));
                if (this._shouldAttachMouseMove()) {
                    var obj$1;
                    bindEvents(this.element, (obj$1 = {}, obj$1[MOUSEMOVE] = this._mousemove, obj$1));
                }
            },
            applyOptions: function (options, theme) {
                clearMissingValues(this._originalOptions, options);
                this._originalOptions = deepExtend(this._originalOptions, options);
                this.options = deepExtend({}, this._originalOptions);
                if (theme) {
                    this._theme = theme;
                    this.chartService.theme = theme;
                }
                this._initTheme(this.options, this._theme);
            },
            setOptions: function (options, theme) {
                this.applyOptions(options, theme);
                this.bindCategories();
                this.redraw();
                this.updateMouseMoveHandler();
            },
            destroy: function () {
                this._destroyed = true;
                var obj;
                unbindEvents(this.element, (obj = {}, obj[CONTEXTMENU] = this._clickHandler, obj[MOUSEWHEEL] = this._mousewheelHandler, obj[MOUSEMOVE] = this._mousemove, obj));
                if (this.domEvents) {
                    this.domEvents.destroy();
                    delete this.domEvents;
                }
                var obj$1;
                unbindEvents(document, (obj$1 = {}, obj$1[MOUSEMOVE] = this._mouseMoveTrackHandler, obj$1));
                this._destroyView();
                if (this.surface) {
                    this.surface.destroy();
                    this.surface = null;
                }
                this._clearRedrawTimeout();
            },
            _destroyView: function () {
                var ref = this;
                var model = ref._model;
                var selections = ref._selections;
                if (model) {
                    model.destroy();
                    this._model = null;
                }
                if (selections) {
                    while (selections.length > 0) {
                        selections.shift().destroy();
                    }
                }
                this._unsetActivePoint();
                if (this._tooltip) {
                    this._tooltip.destroy();
                }
                if (this._highlight) {
                    this._highlight.destroy();
                }
                if (this._zoomSelection) {
                    this._zoomSelection.destroy();
                    delete this._zoomSelection;
                }
                if (this._pannable) {
                    this._pannable.destroy();
                    delete this._pannable;
                }
                if (this._mousewheelZoom) {
                    this._mousewheelZoom.destroy();
                    delete this._mousewheelZoom;
                }
            }
        });
        function resolveAxisAliases(options) {
            var aliases = AXIS_NAMES;
            for (var idx = 0; idx < aliases.length; idx++) {
                var alias = aliases[idx] + 'Axes';
                if (options[alias]) {
                    options[aliases[idx] + 'Axis'] = options[alias];
                    delete options[alias];
                }
            }
        }
        function pointByCategoryName(points, name) {
            if (points) {
                for (var idx = 0; idx < points.length; idx++) {
                    if (points[idx].category === name) {
                        return [points[idx]];
                    }
                }
            }
        }
        function applyAxisDefaults(options, themeOptions) {
            var themeAxisDefaults = (themeOptions || {}).axisDefaults || {};
            var axisName, axisDefaults, axes;
            function mapAxisOptions(axisOptions) {
                var axisColor = (axisOptions || {}).color || axisDefaults.color;
                var result = deepExtend({}, themeAxisDefaults, themeAxisDefaults[axisName], axisDefaults, axisDefaults[axisName], {
                    line: { color: axisColor },
                    labels: { color: axisColor },
                    title: { color: axisColor }
                }, axisOptions);
                delete result[axisName];
                return result;
            }
            for (var idx = 0; idx < AXIS_NAMES.length; idx++) {
                axisName = AXIS_NAMES[idx] + 'Axis';
                axisDefaults = options.axisDefaults || {};
                axes = [].concat(options[axisName]);
                axes = axes.map(mapAxisOptions);
                options[axisName] = axes.length > 1 ? axes : axes[0];
            }
        }
        function applySeriesDefaults(options, themeOptions) {
            var series = options.series;
            var seriesLength = series.length;
            var seriesDefaults = options.seriesDefaults;
            var commonDefaults = deepExtend({}, options.seriesDefaults);
            var themeSeriesDefaults = themeOptions ? deepExtend({}, themeOptions.seriesDefaults) : {};
            var commonThemeDefaults = deepExtend({}, themeSeriesDefaults);
            cleanupNestedSeriesDefaults(commonDefaults);
            cleanupNestedSeriesDefaults(commonThemeDefaults);
            for (var i = 0; i < seriesLength; i++) {
                var seriesType = series[i].type || options.seriesDefaults.type;
                var baseOptions = deepExtend({ data: [] }, commonThemeDefaults, themeSeriesDefaults[seriesType], { tooltip: options.tooltip }, commonDefaults, seriesDefaults[seriesType]);
                series[i]._defaults = baseOptions;
                series[i] = deepExtend({}, baseOptions, series[i]);
            }
        }
        function cleanupNestedSeriesDefaults(seriesDefaults) {
            delete seriesDefaults.bar;
            delete seriesDefaults.column;
            delete seriesDefaults.rangeColumn;
            delete seriesDefaults.line;
            delete seriesDefaults.verticalLine;
            delete seriesDefaults.pie;
            delete seriesDefaults.donut;
            delete seriesDefaults.area;
            delete seriesDefaults.verticalArea;
            delete seriesDefaults.scatter;
            delete seriesDefaults.scatterLine;
            delete seriesDefaults.bubble;
            delete seriesDefaults.candlestick;
            delete seriesDefaults.ohlc;
            delete seriesDefaults.boxPlot;
            delete seriesDefaults.bullet;
            delete seriesDefaults.verticalBullet;
            delete seriesDefaults.polarArea;
            delete seriesDefaults.polarLine;
            delete seriesDefaults.radarArea;
            delete seriesDefaults.radarLine;
            delete seriesDefaults.waterfall;
        }
        function axisRanges(axes) {
            var ranges = {};
            for (var i = 0; i < axes.length; i++) {
                var axis = axes[i];
                var axisName = axis.options.name;
                if (axisName) {
                    ranges[axisName] = axis.range();
                }
            }
            return ranges;
        }
        function sortDates(dates, comparer) {
            if (comparer === void 0) {
                comparer = dataviz.dateComparer;
            }
            for (var i = 1, length = dates.length; i < length; i++) {
                if (comparer(dates[i], dates[i - 1]) < 0) {
                    dates.sort(comparer);
                    break;
                }
            }
            return dates;
        }
        function uniqueDates(srcDates, comparer) {
            if (comparer === void 0) {
                comparer = dataviz.dateComparer;
            }
            var dates = sortDates(srcDates, comparer);
            var length = dates.length;
            var result = length > 0 ? [dates[0]] : [];
            for (var i = 1; i < length; i++) {
                if (comparer(dates[i], last(result)) !== 0) {
                    result.push(dates[i]);
                }
            }
            return result;
        }
        function transpose(rows) {
            var rowCount = rows.length;
            var result = [];
            for (var rowIx = 0; rowIx < rowCount; rowIx++) {
                var row = rows[rowIx];
                var colCount = row.length;
                for (var colIx = 0; colIx < colCount; colIx++) {
                    result[colIx] = result[colIx] || [];
                    result[colIx].push(row[colIx]);
                }
            }
            return result;
        }
        function clearMissingValues(originalOptions, options) {
            for (var field in options) {
                var fieldValue = options[field];
                var originalValue = originalOptions[field];
                if (defined(originalValue)) {
                    var nullValue = fieldValue === null;
                    if (nullValue || !defined(fieldValue)) {
                        delete originalOptions[field];
                        if (nullValue) {
                            delete options[field];
                        }
                    } else if (originalValue && isObject(fieldValue)) {
                        if (isObject(originalValue)) {
                            clearMissingValues(originalValue, fieldValue);
                        }
                    }
                }
            }
        }
        setDefaultOptions(Chart, {
            renderAs: '',
            chartArea: {},
            legend: {
                visible: true,
                labels: {}
            },
            categoryAxis: {},
            seriesDefaults: {
                type: COLUMN,
                data: [],
                highlight: { visible: true },
                labels: {},
                negativeValues: { visible: false }
            },
            series: [],
            seriesColors: null,
            tooltip: { visible: false },
            transitions: true,
            valueAxis: {},
            plotArea: {},
            title: {},
            xAxis: {},
            yAxis: {},
            panes: [{}],
            pannable: false,
            zoomable: false
        });
        kendo.deepExtend(kendo.dataviz, {
            constants: constants,
            Aggregates: Aggregates,
            AreaChart: AreaChart,
            AreaSegment: AreaSegment,
            AxisGroupRangeTracker: AxisGroupRangeTracker,
            Bar: Bar,
            BarChart: BarChart,
            BarLabel: BarLabel,
            BoxPlotChart: BoxPlotChart,
            BoxPlot: BoxPlot,
            BubbleChart: BubbleChart,
            Bullet: Bullet,
            BulletChart: BulletChart,
            CandlestickChart: CandlestickChart,
            Candlestick: Candlestick,
            CategoricalChart: CategoricalChart,
            CategoricalErrorBar: CategoricalErrorBar,
            CategoricalPlotArea: CategoricalPlotArea,
            Chart: Chart,
            ChartContainer: ChartContainer,
            ClipAnimation: ClipAnimation,
            ClusterLayout: ClusterLayout,
            Crosshair: Crosshair,
            CrosshairTooltip: CrosshairTooltip,
            DefaultAggregates: DefaultAggregates,
            DonutChart: DonutChart,
            DonutPlotArea: DonutPlotArea,
            DonutSegment: DonutSegment,
            ErrorBarBase: ErrorBarBase,
            ErrorRangeCalculator: ErrorRangeCalculator,
            Highlight: Highlight,
            SharedTooltip: SharedTooltip,
            Legend: Legend,
            LegendItem: LegendItem,
            LegendLayout: LegendLayout,
            LineChart: LineChart,
            LinePoint: LinePoint,
            LineSegment: LineSegment,
            Pane: Pane,
            PieAnimation: PieAnimation,
            PieChart: PieChart,
            PieChartMixin: PieChartMixin,
            PiePlotArea: PiePlotArea,
            PieSegment: PieSegment,
            PlotAreaBase: PlotAreaBase,
            PlotAreaEventsMixin: PlotAreaEventsMixin,
            PlotAreaFactory: PlotAreaFactory,
            PointEventsMixin: PointEventsMixin,
            RangeBar: RangeBar,
            RangeBarChart: RangeBarChart,
            ScatterChart: ScatterChart,
            ScatterErrorBar: ScatterErrorBar,
            ScatterLineChart: ScatterLineChart,
            Selection: Selection,
            SeriesAggregator: SeriesAggregator,
            SeriesBinder: SeriesBinder,
            SplineSegment: SplineSegment,
            SplineAreaSegment: SplineAreaSegment,
            StackWrap: StackWrap,
            Tooltip: Tooltip,
            OHLCChart: OHLCChart,
            OHLCPoint: OHLCPoint,
            WaterfallChart: WaterfallChart,
            WaterfallSegment: WaterfallSegment,
            XYPlotArea: XYPlotArea,
            MousewheelZoom: MousewheelZoom,
            ZoomSelection: ZoomSelection,
            Pannable: Pannable,
            ChartAxis: ChartAxis,
            ChartPlotArea: ChartPlotArea,
            anyHasZIndex: anyHasZIndex,
            appendIfNotNull: areNumbers,
            areNumbers: areNumbers,
            categoriesCount: categoriesCount,
            countNumbers: countNumbers,
            equalsIgnoreCase: equalsIgnoreCase,
            evalOptions: evalOptions,
            filterSeriesByType: filterSeriesByType,
            getDateField: getDateField,
            getField: getField,
            hasGradientOverlay: hasGradientOverlay,
            hasValue: hasValue,
            isDateAxis: isDateAxis,
            segmentVisible: segmentVisible,
            seriesTotal: seriesTotal,
            singleItemOrArray: singleItemOrArray
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/chart/chart', [
        'dataviz/chart/kendo-chart',
        'kendo.data',
        'kendo.dataviz.core',
        'kendo.dataviz.themes',
        'kendo.drawing',
        'kendo.userevents'
    ], f);
}(function () {
    (function ($, undefined) {
        var NS = '.kendoChart';
        var kendo = window.kendo;
        var Class = kendo.Class;
        var outerWidth = kendo._outerWidth;
        var outerHeight = kendo._outerHeight;
        var dataviz = kendo.dataviz;
        var constants = dataviz.constants;
        var KendoChart = dataviz.Chart;
        var SeriesBinder = dataviz.SeriesBinder;
        var Widget = kendo.ui.Widget;
        var DataSource = kendo.data.DataSource;
        var deepExtend = kendo.deepExtend;
        var defined = dataviz.defined;
        var getField = dataviz.getField;
        var InstanceObserver = dataviz.InstanceObserver;
        var inArray = dataviz.inArray;
        var services = dataviz.services;
        var proxy = $.proxy;
        var isArray = $.isArray;
        var extend = $.extend;
        var template = kendo.template;
        var MOUSELEAVE_NS = 'mouseleave' + NS;
        var AXIS_LABEL_CLICK = constants.AXIS_LABEL_CLICK;
        var LEGEND_ITEM_CLICK = constants.LEGEND_ITEM_CLICK;
        var LEGEND_ITEM_HOVER = constants.LEGEND_ITEM_HOVER;
        var SERIES_CLICK = constants.SERIES_CLICK;
        var SERIES_HOVER = constants.SERIES_HOVER;
        var PLOT_AREA_CLICK = constants.PLOT_AREA_CLICK;
        var PLOT_AREA_HOVER = constants.PLOT_AREA_HOVER;
        var DRAG = constants.DRAG;
        var DRAG_END = constants.DRAG_END;
        var DRAG_START = constants.DRAG_START;
        var ZOOM_START = constants.ZOOM_START;
        var ZOOM = constants.ZOOM;
        var ZOOM_END = constants.ZOOM_END;
        var SELECT_START = constants.SELECT_START;
        var SELECT = constants.SELECT;
        var SELECT_END = constants.SELECT_END;
        var RENDER = constants.RENDER;
        var NOTE_CLICK = constants.NOTE_CLICK;
        var NOTE_HOVER = constants.NOTE_HOVER;
        var CHANGE = 'change';
        var DATABOUND = 'dataBound';
        var LEAVE = 'leave';
        var VALUE = constants.VALUE;
        var PIE = constants.PIE;
        var DONUT = constants.DONUT;
        var FUNNEL = constants.FUNNEL;
        var Observable = kendo.Observable;
        var TOOLTIP_ANIMATION_DURATION = 150;
        var TOOLTIP_SHOW_DELAY = 100;
        var TOOLTIP_INVERSE = 'k-chart-tooltip-inverse';
        var SHARED_TOOLTIP_CLASS = 'k-chart-shared-tooltip';
        services.DomEventsBuilder.register({
            create: function (element, events) {
                return new kendo.UserEvents(element, deepExtend({
                    global: true,
                    multiTouch: true,
                    fastTap: true
                }, events));
            }
        });
        var ChartInstanceObserver = InstanceObserver.extend({
            handlerMap: {
                showTooltip: '_showTooltip',
                hideTooltip: '_hideTooltip',
                legendItemClick: '_onLegendItemClick',
                render: '_onRender'
            }
        });
        var Chart = Widget.extend({
            init: function (element, userOptions) {
                var dataSource;
                kendo.destroy(element);
                Widget.fn.init.call(this, element);
                if (userOptions) {
                    dataSource = userOptions.dataSource;
                    delete userOptions.dataSource;
                }
                this.options = deepExtend({}, this.options, userOptions);
                this.wrapper = this.element;
                this._attachEvents();
                if (userOptions) {
                    userOptions.dataSource = dataSource;
                }
                this._seriesVisibility = new SeriesVisibilityState();
                this.bind(this.events, this.options);
                this._initDataSource(userOptions);
                kendo.notify(this, dataviz.ui);
            },
            events: [
                DATABOUND,
                SERIES_CLICK,
                SERIES_HOVER,
                AXIS_LABEL_CLICK,
                LEGEND_ITEM_CLICK,
                LEGEND_ITEM_HOVER,
                PLOT_AREA_CLICK,
                PLOT_AREA_HOVER,
                DRAG_START,
                DRAG,
                DRAG_END,
                ZOOM_START,
                ZOOM,
                ZOOM_END,
                SELECT_START,
                SELECT,
                SELECT_END,
                NOTE_CLICK,
                NOTE_HOVER,
                RENDER
            ],
            options: {
                name: 'Chart',
                renderAs: '',
                theme: 'default',
                chartArea: {},
                legend: {},
                categoryAxis: {},
                autoBind: true,
                seriesDefaults: {},
                series: [],
                seriesColors: null,
                tooltip: {},
                transitions: true,
                valueAxis: {},
                plotArea: {},
                title: {},
                xAxis: {},
                yAxis: {},
                panes: [{}],
                pannable: false,
                zoomable: false
            },
            items: function () {
                return $();
            },
            refresh: function () {
                var chart = this;
                var instance = chart._instance;
                instance.applyDefaults(chart.options);
                instance.applySeriesColors();
                chart._bindSeries();
                chart._bindCategories();
                chart.trigger(DATABOUND);
                chart._redraw();
            },
            getSize: function () {
                return kendo.dimensions(this.element);
            },
            redraw: function (paneName) {
                this._size = null;
                this._instance.redraw(paneName);
            },
            setOptions: function (options) {
                var chart = this, dataSource = options.dataSource;
                delete options.dataSource;
                Widget.fn._setEvents.call(chart, options);
                this._instance.applyOptions(options, this._getThemeOptions(options));
                this.options = this._instance.options;
                this._tooltip.setOptions(this.options.tooltip);
                this._sourceSeries = null;
                if (dataSource) {
                    chart.setDataSource(dataSource);
                }
                if (chart._hasDataSource) {
                    chart._onDataChanged();
                } else {
                    chart._bindCategories();
                    chart.redraw();
                }
                chart._instance.updateMouseMoveHandler();
            },
            setDataSource: function (dataSource) {
                var chart = this;
                chart.dataSource.unbind(CHANGE, chart._dataChangeHandler);
                chart.dataSource = dataSource = DataSource.create(dataSource);
                chart._hasDataSource = true;
                chart._hasData = false;
                dataSource.bind(CHANGE, chart._dataChangeHandler);
                if (chart.options.autoBind) {
                    dataSource.fetch();
                }
            },
            destroy: function () {
                var chart = this, dataSource = chart.dataSource;
                chart.element.off(NS);
                if (dataSource) {
                    dataSource.unbind(CHANGE, chart._dataChangeHandler);
                }
                if (chart._instance) {
                    chart._instance.destroy();
                    delete this._instance;
                }
                if (this._tooltip) {
                    this._tooltip.destroy();
                    delete this._tooltip;
                }
                this._destroyCrosshairTooltips();
                Widget.fn.destroy.call(chart);
            },
            findPaneByName: function (name) {
                var panes = this._plotArea.panes;
                for (var idx = 0; idx < panes.length; idx++) {
                    if (panes[idx].options.name === name) {
                        return new ChartPane(this, panes[idx]);
                    }
                }
            },
            findPaneByIndex: function (idx) {
                var panes = this._plotArea.panes;
                if (panes[idx]) {
                    return new ChartPane(this, panes[idx]);
                }
            },
            findSeries: function (callback) {
                var plotArea = this._plotArea;
                var series = plotArea.srcSeries || plotArea.series;
                for (var idx = 0; idx < series.length; idx++) {
                    if (callback(series[idx])) {
                        return new ChartSeries(this, series[idx]);
                    }
                }
            },
            findSeriesByName: function (name) {
                return this._createSeries({ name: name });
            },
            findSeriesByIndex: function (index) {
                return this._createSeries({ index: index });
            },
            _createSeries: function (options) {
                var seriesOptions = this._seriesOptions(options);
                if (seriesOptions) {
                    return new ChartSeries(this, seriesOptions);
                }
            },
            _seriesOptions: function (options) {
                var plotArea = this._plotArea;
                var series = plotArea.srcSeries || plotArea.series;
                var seriesOptions;
                if (defined(options.index)) {
                    seriesOptions = series[options.index];
                } else if (defined(options.name)) {
                    for (var idx = 0; idx < series.length; idx++) {
                        if (series[idx].name === options.name) {
                            seriesOptions = series[idx];
                            break;
                        }
                    }
                }
                return seriesOptions;
            },
            _attachEvents: function () {
                this.element.on(MOUSELEAVE_NS, proxy(this._mouseleave, this));
            },
            _mouseleave: function (e) {
                var instance = this._instance;
                var tooltip = this._tooltip;
                var target = e.relatedTarget;
                if (!(target && $(target).closest(tooltip.element).length) && instance && !instance.handlingTap) {
                    instance.hideElements();
                }
            },
            _getThemeOptions: function (userOptions) {
                var themeName = (userOptions || {}).theme;
                if (themeName === 'sass' || themeName === 'default-v2' || themeName === 'bootstrap-v4') {
                    return dataviz.autoTheme().chart;
                }
                if (defined(themeName)) {
                    var themes = dataviz.ui.themes || {};
                    var theme = themes[themeName] || themes[themeName.toLowerCase()] || {};
                    return theme.chart || {};
                }
            },
            _initChart: function () {
                this._createChart(this.options, this._getThemeOptions(this.options));
                this.options = this._instance.options;
            },
            _createChart: function (options, themeOptions) {
                this._instance = new KendoChart(this.element[0], options, themeOptions, {
                    observer: new ChartInstanceObserver(this),
                    sender: this
                });
            },
            _initDataSource: function (userOptions) {
                var chart = this, dataSource = (userOptions || {}).dataSource;
                chart._dataChangeHandler = proxy(chart._onDataChanged, chart);
                chart.dataSource = DataSource.create(dataSource).bind('change', chart._dataChangeHandler);
                chart._bindCategories();
                if (dataSource) {
                    chart._hasDataSource = true;
                }
                this._initChart();
                this._initTooltip();
                if (dataSource) {
                    if (chart.options.autoBind) {
                        chart.dataSource.fetch();
                    }
                }
            },
            _destroyCrosshairTooltips: function () {
                var tooltips = this._crosshairTooltips;
                if (tooltips) {
                    for (var key in tooltips) {
                        tooltips[key].destroy();
                    }
                }
                this._crosshairTooltips = {};
            },
            _getCrosshairTooltip: function (name, index) {
                var tooltips = this._crosshairTooltips = this._crosshairTooltips || {};
                var key = name + index;
                var tooltip = tooltips[key];
                if (!tooltip) {
                    tooltip = tooltips[key] = new CrosshairTooltip(this.element);
                }
                return tooltip;
            },
            _showTooltip: function (e) {
                if (e.crosshair) {
                    var tooltip = this._getCrosshairTooltip(e.axisName, e.axisIndex);
                    tooltip.show(e);
                } else if (this._tooltip) {
                    this._tooltip.show(e);
                }
            },
            _hideTooltip: function (e) {
                if (e.crosshair) {
                    var tooltip = this._getCrosshairTooltip(e.axisName, e.axisIndex);
                    tooltip.hide();
                } else if (this._tooltip) {
                    this._tooltip.hide(e);
                }
            },
            _onRender: function (e) {
                this._destroyCrosshairTooltips();
                this._copyMembers(e.sender);
                if (!this._hasDataSource || this._hasData || !this.options.autoBind) {
                    this.trigger(RENDER);
                }
            },
            _copyMembers: function (instance) {
                this._instance = instance;
                this.options = instance.options;
                this._originalOptions = instance._originalOptions;
                this.surface = instance.surface;
                this._plotArea = instance._plotArea;
                this._model = instance._model;
                this._highlight = instance._highlight;
                this._selections = instance._selections;
                this._pannable = instance._pannable;
                this._zoomSelection = instance._zoomSelection;
                this._mousewheelZoom = instance._mousewheelZoom;
            },
            requiresHandlers: function (names) {
                var events = this._events;
                for (var idx = 0; idx < names.length; idx++) {
                    if (defined(events[names[idx]])) {
                        return true;
                    }
                }
            },
            _initTooltip: function () {
                this._tooltip = this._createTooltip();
                this._tooltip.bind(LEAVE, proxy(this._tooltipleave, this));
            },
            _onLegendItemClick: function (e) {
                if (!this.trigger(LEGEND_ITEM_CLICK, e)) {
                    this._legendItemClick(e.seriesIndex, e.pointIndex);
                }
            },
            _legendItemClick: function (seriesIndex, pointIndex) {
                var chart = this._instance, plotArea = chart._plotArea, currentSeries = (plotArea.srcSeries || plotArea.series)[seriesIndex];
                if ($.inArray(currentSeries.type, [
                        PIE,
                        DONUT,
                        FUNNEL
                    ]) >= 0) {
                    var pointVisibility = currentSeries.pointVisibility = currentSeries.pointVisibility || {};
                    var visible = pointVisibility[pointIndex];
                    pointVisibility[pointIndex] = defined(visible) ? !visible : false;
                } else {
                    currentSeries.visible = !currentSeries.visible;
                    this._seriesVisibility.save(currentSeries);
                }
                chart._noTransitionsRedraw();
            },
            _createTooltip: function () {
                return new Tooltip(this.element, this.options.tooltip);
            },
            _tooltipleave: function () {
                var chart = this._instance, plotArea = chart._plotArea, highlight = chart._highlight;
                plotArea.hideCrosshairs();
                highlight.hide();
            },
            _bindData: function (e) {
                var chart = this, options = chart.options, series = chart._sourceSeries || options.series, seriesIx, seriesLength = series.length, data = chart.dataSource.view(), grouped = (chart.dataSource.group() || []).length > 0, processedSeries = [], seriesVisibility = this._seriesVisibility, currentSeries, groupedSeries;
                for (seriesIx = 0; seriesIx < seriesLength; seriesIx++) {
                    currentSeries = series[seriesIx];
                    if (chart._isBindable(currentSeries) && grouped) {
                        groupedSeries = groupSeries(currentSeries, data);
                        processedSeries = processedSeries.concat(groupedSeries);
                        seriesVisibility.applyByGroup(groupedSeries, e);
                    } else {
                        currentSeries = extend({}, currentSeries);
                        processedSeries.push(currentSeries);
                        seriesVisibility.applyByIndex(currentSeries, e);
                    }
                }
                chart._sourceSeries = series;
                options.series = processedSeries;
                this._instance.applySeriesColors();
                chart._bindSeries();
                chart._bindCategories();
                this._hasData = true;
            },
            _onDataChanged: function (e) {
                this._bindData(e);
                this.trigger(DATABOUND);
                this._redraw();
            },
            _bindSeries: function () {
                var chart = this, data = chart.dataSource.view(), series = chart.options.series, seriesIx, seriesLength = series.length, currentSeries, groupIx, seriesData;
                for (seriesIx = 0; seriesIx < seriesLength; seriesIx++) {
                    currentSeries = series[seriesIx];
                    if (chart._isBindable(currentSeries)) {
                        groupIx = currentSeries._groupIx;
                        seriesData = defined(groupIx) ? (data[groupIx] || {}).items : data;
                        if (currentSeries.autoBind !== false) {
                            currentSeries.data = seriesData;
                        }
                    }
                }
            },
            _bindCategories: function () {
                var chart = this, data = chart.dataSource.view() || [], grouped = (chart.dataSource.group() || []).length > 0, categoriesData = data, options = chart.options, definitions = [].concat(options.categoryAxis), axisIx, axis;
                if (grouped) {
                    if (data.length) {
                        categoriesData = data[0].items;
                    }
                }
                for (axisIx = 0; axisIx < definitions.length; axisIx++) {
                    axis = definitions[axisIx];
                    if (axis.autoBind !== false) {
                        chart._bindCategoryAxis(axis, categoriesData, axisIx);
                    }
                }
            },
            _bindCategoryAxis: function (axis, data, axisIx) {
                var count = (data || []).length, categoryIx, category, row;
                if (axis.field) {
                    axis.categories = [];
                    for (categoryIx = 0; categoryIx < count; categoryIx++) {
                        row = data[categoryIx];
                        category = getField(axis.field, row);
                        if (categoryIx === 0) {
                            axis.categories = [category];
                            axis.dataItems = [row];
                        } else {
                            axis.categories.push(category);
                            axis.dataItems.push(row);
                        }
                    }
                } else if (this._instance) {
                    this._instance.bindCategoryAxisFromSeries(axis, axisIx);
                }
            },
            _isBindable: function (series) {
                var valueFields = SeriesBinder.current.valueFields(series), result = true, field, i;
                for (i = 0; i < valueFields.length; i++) {
                    field = valueFields[i];
                    if (field === VALUE) {
                        field = 'field';
                    } else {
                        field = field + 'Field';
                    }
                    if (!defined(series[field])) {
                        result = false;
                        break;
                    }
                }
                return result;
            }
        });
        var proxyMembers = [
            'getAxis',
            'findAxisByName',
            'plotArea',
            'toggleHighlight',
            'showTooltip',
            'hideTooltip',
            'exportVisual',
            '_resize',
            '_redraw',
            '_noTransitionsRedraw',
            '_legendItemHover',
            '_eventCoordinates'
        ];
        function createProxyMember(name) {
            Chart.fn[name] = function () {
                var instance = this._instance;
                if (instance) {
                    return instance[name].apply(instance, arguments);
                }
            };
        }
        for (var idx = 0; idx < proxyMembers.length; idx++) {
            createProxyMember(proxyMembers[idx]);
        }
        function groupSeries(series, data) {
            var result = [], nameTemplate, legacyTemplate = series.groupNameTemplate, groupIx, dataLength = data.length, seriesClone;
            if (dataLength === 0) {
                seriesClone = deepExtend({}, series);
                seriesClone.visibleInLegend = false;
                return [seriesClone];
            }
            if (defined(legacyTemplate)) {
                kendo.logToConsole('\'groupNameTemplate\' is obsolete and will be removed in future versions. ' + 'Specify the group name template as \'series.name\'');
                if (legacyTemplate) {
                    nameTemplate = template(legacyTemplate);
                }
            } else {
                nameTemplate = template(series.name || '');
                if (nameTemplate._slotCount === 0) {
                    nameTemplate = template(defined(series.name) ? '#= group.value #: #= series.name #' : '#= group.value #');
                }
            }
            for (groupIx = 0; groupIx < dataLength; groupIx++) {
                seriesClone = deepExtend({}, series);
                if (!kendo.isFunction(seriesClone.color)) {
                    seriesClone.color = undefined;
                }
                seriesClone._groupIx = groupIx;
                seriesClone._groupValue = data[groupIx].value;
                result.push(seriesClone);
                if (nameTemplate) {
                    seriesClone.name = nameTemplate({
                        series: seriesClone,
                        group: data[groupIx]
                    });
                }
            }
            return result;
        }
        dataviz.ExportMixin.extend(Chart.fn);
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Chart.fn);
        }
        dataviz.ui.plugin(Chart);
        var SeriesVisibilityState = Class.extend({
            init: function () {
                this.groups = {};
                this.index = {};
            },
            applyByGroup: function (series, e) {
                if (e && e.action) {
                    for (var idx = 0; idx < series.length; idx++) {
                        if (this.groups[series[idx]._groupValue] === false) {
                            series[idx].visible = false;
                        }
                    }
                } else {
                    this.groups = {};
                }
            },
            applyByIndex: function (series, e) {
                if (e && e.action) {
                    if (this.index[series.index] === false) {
                        series.visible = false;
                    }
                } else {
                    this.index = {};
                }
            },
            save: function (series) {
                if (!series) {
                    return;
                }
                if (defined(series._groupValue)) {
                    this.groups[series._groupValue] = series.visible;
                } else {
                    this.index[series.index] = series.visible;
                }
            }
        });
        var geom = kendo.geometry;
        var Tooltip = Observable.extend({
            init: function (chartElement, options) {
                var tooltip = this;
                Observable.fn.init.call(tooltip);
                this.setOptions(options);
                tooltip.chartElement = chartElement;
                tooltip.template = Tooltip.template;
                if (!tooltip.template) {
                    tooltip.template = Tooltip.template = kendo.template('<div class=\'k-tooltip k-chart-tooltip\' ' + 'style=\'display:none; position: absolute; font: #= d.font #;' + '#if (d.border) {# border: #= d.border.width #px solid; #}#' + 'opacity: #= d.opacity #; filter: alpha(opacity=#= d.opacity * 100 #);\'>' + '</div>', {
                        useWithBlock: false,
                        paramName: 'd'
                    });
                }
                tooltip.element = $(tooltip.template(tooltip.options));
                tooltip.move = proxy(tooltip.move, tooltip);
                tooltip._mouseleave = proxy(tooltip._mouseleave, tooltip);
                var mobileScrollerSelector = kendo.format('[{0}=\'content\'],[{0}=\'scroller\']', kendo.attr('role'));
                tooltip._mobileScroller = chartElement.closest(mobileScrollerSelector).data('kendoMobileScroller');
            },
            destroy: function () {
                this._clearShowTimeout();
                if (this.element) {
                    this.element.off(MOUSELEAVE_NS).remove();
                    this.element = null;
                }
            },
            setOptions: function (options) {
                this.options = deepExtend({}, this.options, options);
            },
            options: {
                opacity: 1,
                animation: { duration: TOOLTIP_ANIMATION_DURATION },
                sharedTemplate: '<table>' + '<th colspan=\'#= colspan #\'>#= categoryText #</th>' + '# for(var i = 0; i < points.length; i++) { #' + '# var point = points[i]; #' + '<tr>' + '# if(colorMarker) { # ' + '<td><span class=\'k-chart-shared-tooltip-marker\' style=\'background-color:#:point.series.color#\'></span></td>' + '# } #' + '# if(nameColumn) { # ' + '<td> #if (point.series.name) {# #: point.series.name #: #} else {# &nbsp; #}#</td>' + '# } #' + '<td>#= content(point) #</td>' + '</tr>' + '# } #' + '</table>',
                categoryFormat: '{0:d}'
            },
            move: function () {
                var tooltip = this, options = tooltip.options, element = tooltip.element, offset;
                if (!tooltip.anchor || !tooltip.element) {
                    return;
                }
                offset = tooltip._offset();
                if (!tooltip.visible) {
                    element.css({
                        top: offset.top,
                        left: offset.left
                    });
                }
                tooltip.visible = true;
                tooltip._ensureElement(document.body);
                element.stop(true, true).show().animate({
                    left: offset.left,
                    top: offset.top
                }, options.animation.duration);
            },
            _clearShowTimeout: function () {
                if (this.showTimeout) {
                    clearTimeout(this.showTimeout);
                    this.showTimeout = null;
                }
            },
            getAnchor: function (size) {
                var anchor = this.anchor;
                var point = anchor.point;
                var align = anchor.align;
                var x = point.left;
                var y = point.top;
                if (align.horizontal === 'center') {
                    x -= size.width / 2;
                } else if (align.horizontal === 'right') {
                    x -= size.width;
                }
                if (align.vertical === 'center') {
                    y -= size.height / 2;
                } else if (align.vertical === 'bottom') {
                    y -= size.height;
                }
                return {
                    x: x,
                    y: y
                };
            },
            _offset: function () {
                var tooltip = this, size = tooltip._measure(), anchor = tooltip.getAnchor(size), top = anchor.y, left = anchor.x, zoomLevel = kendo.support.zoomLevel(), viewport = $(window), scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0, scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || 0, movable = (this._mobileScroller || {}).movable;
                if (!movable || movable.scale === 1) {
                    top += tooltip._fit(top - scrollTop, size.height, outerHeight(viewport) / zoomLevel);
                    left += tooltip._fit(left - scrollLeft, size.width, outerWidth(viewport) / zoomLevel);
                } else {
                    var transform = geom.transform().scale(movable.scale, movable.scale, [
                        movable.x,
                        movable.y
                    ]);
                    var point = new geom.Point(left, top).transform(transform);
                    left = point.x;
                    top = point.y;
                }
                return {
                    top: top,
                    left: left
                };
            },
            show: function (e) {
                this.anchor = e.anchor;
                this.element.css(e.style);
                this.element.toggleClass(TOOLTIP_INVERSE, !!e.className);
                this.element.toggleClass(SHARED_TOOLTIP_CLASS, !!e.shared);
                var content = e.shared ? this._sharedContent(e) : this._pointContent(e.point);
                this.element.html(content);
                this._clearShowTimeout();
                this.showTimeout = setTimeout(this.move, TOOLTIP_SHOW_DELAY);
            },
            hide: function () {
                var tooltip = this;
                clearTimeout(tooltip.showTimeout);
                tooltip._hideElement();
                if (tooltip.visible) {
                    tooltip.point = null;
                    tooltip.visible = false;
                    tooltip.index = null;
                }
            },
            _sharedContent: function (e) {
                var points = e.points;
                var nameColumn = dataviz.grep(points, function (point) {
                    return defined(point.series.name);
                }).length;
                var colorMarker = e.series.length > 1;
                var colspan = 1;
                if (nameColumn) {
                    colspan++;
                }
                if (colorMarker) {
                    colspan++;
                }
                var template = kendo.template(this.options.sharedTemplate);
                var content = template({
                    points: points,
                    category: e.category,
                    categoryText: e.categoryText,
                    content: this._pointContent,
                    colorMarker: colorMarker,
                    nameColumn: nameColumn,
                    colspan: colspan
                });
                return content;
            },
            _measure: function () {
                this._ensureElement();
                var size = {
                    width: outerWidth(this.element),
                    height: outerHeight(this.element)
                };
                return size;
            },
            _ensureElement: function () {
                if (this.element) {
                    this.element.appendTo(document.body).on(MOUSELEAVE_NS, this._mouseleave);
                }
            },
            _mouseleave: function (e) {
                var target = e.relatedTarget;
                var chart = this.chartElement[0];
                if (target && target !== chart && !$.contains(chart, target)) {
                    this.trigger(LEAVE);
                    this.hide();
                }
            },
            _hideElement: function () {
                var tooltip = this;
                var element = this.element;
                if (element) {
                    element.fadeOut({
                        always: function () {
                            if (!tooltip.visible) {
                                element.off(MOUSELEAVE_NS).remove();
                            }
                        }
                    });
                }
            },
            _pointContent: function (point) {
                var tooltip = this, options = deepExtend({}, tooltip.options, point.options.tooltip), content, tooltipTemplate;
                if (defined(point.value)) {
                    content = point.value.toString();
                }
                if (options.template) {
                    tooltipTemplate = template(options.template);
                    content = tooltipTemplate({
                        value: point.value,
                        category: point.category,
                        series: point.series,
                        dataItem: point.dataItem,
                        percentage: point.percentage,
                        runningTotal: point.runningTotal,
                        total: point.total,
                        low: point.low,
                        high: point.high,
                        xLow: point.xLow,
                        xHigh: point.xHigh,
                        yLow: point.yLow,
                        yHigh: point.yHigh
                    });
                } else if (options.format) {
                    content = point.formatValue(options.format);
                }
                return content;
            },
            _fit: function (offset, size, viewPortSize) {
                var output = 0;
                if (offset + size > viewPortSize) {
                    output = viewPortSize - (offset + size);
                }
                if (offset < 0) {
                    output = -offset;
                }
                return output;
            }
        });
        var CrosshairTooltip = Tooltip.extend({
            init: function (chartElement, options) {
                Tooltip.fn.init.call(this, chartElement, options);
                this.element.addClass('k-chart-crosshair-tooltip');
            },
            show: function (e) {
                var element = this.element;
                if (element) {
                    this.anchor = e.anchor;
                    this.element.css(e.style);
                    this.element.html(this.content(e));
                    this.move();
                }
            },
            move: function () {
                var tooltip = this, element = tooltip.element, offset = tooltip._offset();
                tooltip._ensureElement();
                element.css({
                    top: offset.top,
                    left: offset.left
                }).show();
            },
            content: function (e) {
                var content = e.value, options = e.crosshair.options.tooltip;
                if (options.template) {
                    content = template(options.template)({ value: content });
                }
                return content;
            },
            hide: function () {
                this.element.hide();
            }
        });
        var ChartPane = Class.extend({
            init: function (chart, pane) {
                this._chart = chart;
                this._pane = pane;
                this.visual = pane.visual;
                this.chartsVisual = pane.chartContainer.visual;
                this.name = pane.options.name;
            },
            series: function () {
                var chart = this._chart;
                var seriesByPane = chart._plotArea.groupSeriesByPane();
                var series = seriesByPane[this.name || 'default'];
                var result = [];
                if (series) {
                    for (var idx = 0; idx < series.length; idx++) {
                        result.push(new ChartSeries(chart, series[idx]));
                    }
                }
                return result;
            }
        });
        var ChartSeries = Class.extend({
            init: function (chart, options) {
                this._chart = chart;
                this._options = options;
            },
            points: function (filter) {
                var points = this._points;
                if (!points) {
                    var series = this._seriesOptions();
                    var plotArea = this._chart._plotArea;
                    this._points = points = plotArea.pointsBySeriesIndex(series.index);
                }
                if (kendo.isFunction(filter)) {
                    points = this._filterPoints(points, filter);
                }
                return points;
            },
            data: function (data) {
                var series = this._seriesOptions();
                if (data) {
                    var chart = this._chart;
                    var plotArea = chart._plotArea;
                    series.data = data;
                    if (series.categoryField) {
                        var axis = plotArea.seriesCategoryAxis(series);
                        var options = [].concat(chart.options.categoryAxis);
                        chart._instance.bindCategoryAxisFromSeries(options[axis.axisIndex], axis.axisIndex);
                    }
                    chart._noTransitionsRedraw();
                    this._clearFields();
                }
                return series.data;
            },
            findPoint: function (filter) {
                var points = this.points();
                for (var idx = 0; idx < points.length; idx++) {
                    if (filter(points[idx])) {
                        return points[idx];
                    }
                }
            },
            toggleHighlight: function (show, elements) {
                if (!elements) {
                    elements = this.points();
                } else if (kendo.isFunction(elements)) {
                    elements = this.points(elements);
                } else {
                    elements = isArray(elements) ? elements : [elements];
                }
                this._chart._instance.togglePointsHighlight(show, elements);
            },
            toggleVisibility: function (visible, filter) {
                var chart = this._chart;
                var seriesOptions = this._seriesOptions();
                var hasFilter = kendo.isFunction(filter);
                if (!hasFilter) {
                    seriesOptions.visible = visible;
                    chart._seriesVisibility.save(seriesOptions);
                } else {
                    if (inArray(seriesOptions.type, [
                            PIE,
                            DONUT,
                            FUNNEL
                        ])) {
                        var data = this._filterData(filter);
                        for (var idx = 0; idx < data.length; idx++) {
                            data[idx].visible = visible;
                        }
                    } else {
                        seriesOptions.visible = function (data) {
                            return filter(data.dataItem) ? visible : true;
                        };
                    }
                }
                chart._noTransitionsRedraw();
                this._clearFields();
            },
            _filterData: function (filter) {
                var data = this._seriesOptions().data;
                var length = data.length;
                var result = [];
                for (var idx = 0; idx < length; idx++) {
                    if (filter(data[idx])) {
                        result.push(data[idx]);
                    }
                }
                return result;
            },
            _filterPoints: function (points, filter) {
                var result = [];
                var length = points.length;
                for (var idx = 0; idx < length; idx++) {
                    if (filter(points[idx])) {
                        result.push(points[idx]);
                    }
                }
                return result;
            },
            _seriesOptions: function () {
                var series = this._series;
                if (!series) {
                    series = this._series = this._chart._seriesOptions(this._options);
                }
                return series;
            },
            _clearFields: function () {
                delete this._points;
                delete this._series;
            }
        });
        dataviz.Tooltip = Tooltip;
        dataviz.CrosshairTooltip = CrosshairTooltip;
        dataviz.ChartInstanceObserver = ChartInstanceObserver;
        dataviz.ChartPane = ChartPane;
        dataviz.ChartSeries = ChartSeries;
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.chart', [
        'dataviz/chart/kendo-chart',
        'dataviz/chart/chart'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.chart',
        name: 'Chart',
        category: 'dataviz',
        description: 'The Chart widget uses modern browser technologies to render high-quality data visualizations in the browser.',
        depends: [
            'data',
            'userevents',
            'drawing',
            'dataviz.core',
            'dataviz.themes'
        ],
        features: [{
                id: 'dataviz.chart-pdf-export',
                name: 'PDF export',
                description: 'Export Chart as PDF',
                depends: ['pdf']
            }]
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.gauge', [
        'kendo.dataviz.core',
        'kendo.drawing',
        'kendo.dataviz.themes'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.gauge',
        name: 'Gauge',
        category: 'dataviz',
        description: 'Radial and Linear gauges.',
        depends: [
            'dataviz.core',
            'dataviz.themes'
        ]
    };
    (function ($, undefined) {
        var math = Math, kendo = window.kendo, Widget = kendo.ui.Widget, deepExtend = kendo.deepExtend, dataviz = kendo.dataviz, autoMajorUnit = dataviz.autoMajorUnit, ChartElement = dataviz.ChartElement, NumericAxis = dataviz.NumericAxis, Axis = dataviz.Axis, Box2D = dataviz.Box2D, Class = kendo.Class, defined = dataviz.defined, isNumber = dataviz.isNumber, interpolateValue = dataviz.interpolateValue, getSpacing = dataviz.getSpacing, round = dataviz.round, geo = dataviz.geometry, draw = dataviz.drawing, Point = geo.Point, Group = draw.Group, Path = draw.Path, Rect = geo.Rect, Text = draw.Text;
        var ANGULAR_SPEED = 150, LINEAR_SPEED = 250, ARROW = 'arrow', ARROW_POINTER = 'arrowPointer', BAR_POINTER = 'barPointer', BLACK = '#000', CAP_SIZE = 0.05, COORD_PRECISION = dataviz.COORD_PRECISION, MAX_VALUE = Number.MAX_VALUE, MIN_VALUE = -Number.MAX_VALUE, DEFAULT_HEIGHT = 200, DEFAULT_LINE_WIDTH = 0.5, DEFAULT_WIDTH = 200, DEFAULT_MIN_WIDTH = 60, DEFAULT_MIN_HEIGHT = 60, DEFAULT_MARGIN = 5, DEGREE = math.PI / 180, GEO_ARC_ADJUST_ANGLE = 180, INSIDE = 'inside', LINEAR = 'linear', NEEDLE = 'needle', OUTSIDE = 'outside', RADIAL_POINTER = 'radialPointer', X = 'x', Y = 'y';
        var Pointer = Class.extend({
            init: function (scale, options) {
                var pointer = this;
                var scaleOptions = scale.options;
                ChartElement.fn.init.call(pointer, options);
                options = pointer.options;
                options.fill = options.color;
                pointer.scale = scale;
                if (defined(options.value)) {
                    options.value = math.min(math.max(options.value, scaleOptions.min), scaleOptions.max);
                } else {
                    options.value = scaleOptions.min;
                }
            },
            options: { color: BLACK },
            value: function (newValue) {
                var that = this;
                var options = that.options;
                var value = options.value;
                var scaleOptions = that.scale.options;
                if (arguments.length === 0) {
                    return value;
                }
                options._oldValue = options._oldValue !== undefined ? options.value : scaleOptions.min;
                options.value = math.min(math.max(newValue, scaleOptions.min), scaleOptions.max);
                if (that.elements) {
                    that.repaint();
                }
            }
        });
        var RadialPointer = Pointer.extend({
            options: {
                shape: NEEDLE,
                cap: { size: CAP_SIZE },
                arrow: {
                    width: 16,
                    height: 14
                },
                animation: {
                    type: RADIAL_POINTER,
                    duration: ANGULAR_SPEED
                }
            },
            setRadius: function (radius) {
                var that = this;
                if (radius) {
                    that.elements.clear();
                    that.render(that.parent, that.center, radius);
                }
            },
            setAngle: function (angle) {
                this.elements.transform(geo.transform().rotate(angle, this.center));
            },
            repaint: function () {
                var that = this;
                var scale = that.scale;
                var options = that.options;
                var oldAngle = scale.slotAngle(options._oldValue);
                var newAngle = scale.slotAngle(options.value);
                if (options.animation.transitions === false) {
                    that.setAngle(newAngle);
                } else {
                    new RadialPointerAnimation(that.elements, deepExtend(options.animation, {
                        oldAngle: oldAngle,
                        newAngle: newAngle
                    })).play();
                }
            },
            render: function () {
                var that = this;
                var scale = that.scale;
                var center = scale.arc.center;
                var options = that.options;
                var elements = new Group();
                if (options.animation !== false) {
                    deepExtend(options.animation, {
                        startAngle: 0,
                        center: center,
                        reverse: scale.options.reverse
                    });
                }
                if (options.shape === NEEDLE) {
                    elements.append(that._renderNeedle(), that._renderCap());
                } else {
                    elements.append(that._renderArrow());
                }
                that.elements = elements;
                that.setAngle(DEGREE);
                return elements;
            },
            reflow: function (arc) {
                var that = this;
                var center = that.center = arc.center;
                var radius = that.radius = arc.getRadiusX();
                var capSize = that.capSize = Math.round(radius * that.options.cap.size);
                that.bbox = Rect.fromPoints(new Point(center.x - capSize, center.y - capSize), new Point(center.x + capSize, center.y + capSize));
            },
            _renderNeedle: function () {
                var that = this;
                var options = that.options;
                var minorTickSize = that.scale.options.minorTicks.size;
                var center = that.center;
                var needleColor = options.color;
                var needlePath = new Path({
                    fill: { color: needleColor },
                    stroke: {
                        color: needleColor,
                        width: DEFAULT_LINE_WIDTH
                    }
                });
                needlePath.moveTo(center.x + that.radius - minorTickSize, center.y).lineTo(center.x, center.y - that.capSize / 2).lineTo(center.x, center.y + that.capSize / 2).close();
                return needlePath;
            },
            _renderCap: function () {
                var that = this;
                var options = that.options;
                var capColor = options.cap.color || options.color;
                var circle = new geo.Circle(that.center, that.capSize);
                var cap = new draw.Circle(circle, {
                    fill: { color: capColor },
                    stroke: { color: capColor }
                });
                return cap;
            }
        });
        var RadialScale = NumericAxis.extend({
            init: function (options) {
                var scale = this;
                scale.options = deepExtend({}, scale.options, options);
                scale.options.majorUnit = scale.options.majorUnit || autoMajorUnit(scale.options.min, scale.options.max);
                scale.options.minorUnit = scale.options.minorUnit || scale.options.majorUnit / 10;
                Axis.fn.init.call(scale, scale.options);
            },
            options: {
                min: 0,
                max: 100,
                majorTicks: {
                    size: 15,
                    align: INSIDE,
                    color: BLACK,
                    width: DEFAULT_LINE_WIDTH,
                    visible: true
                },
                minorTicks: {
                    size: 10,
                    align: INSIDE,
                    color: BLACK,
                    width: DEFAULT_LINE_WIDTH,
                    visible: true
                },
                startAngle: -30,
                endAngle: 210,
                labels: {
                    position: INSIDE,
                    padding: 2
                }
            },
            render: function (center, radius) {
                var that = this;
                var arc = that.renderArc(center, radius);
                that.bbox = arc.bbox();
                that.labelElements = that.renderLabels();
                that.ticks = that.renderTicks();
                that.ranges = that.renderRanges();
            },
            reflow: function (bbox) {
                var that = this;
                var center = bbox.center();
                var radius = math.min(bbox.height(), bbox.width()) / 2;
                if (that.bbox !== undefined) {
                    that.bbox = that.arc.bbox();
                    that.radius(that.arc.getRadiusX());
                    that.repositionRanges();
                    that.renderLabels();
                } else {
                    return that.render(center, radius);
                }
            },
            slotAngle: function (value) {
                var options = this.options;
                var startAngle = options.startAngle;
                var reverse = options.reverse;
                var angle = options.endAngle - startAngle;
                var min = options.min;
                var max = options.max;
                var result;
                if (reverse) {
                    result = options.endAngle - (value - min) / (max - min) * angle;
                } else {
                    result = (value - min) / (max - min) * angle + startAngle;
                }
                return result + GEO_ARC_ADJUST_ANGLE;
            },
            renderLabels: function () {
                var that = this;
                var options = that.options;
                var majorTickSize = options.majorTicks.size;
                var arc = that.arc.clone();
                var radius = arc.getRadiusX();
                var tickAngles = that.tickAngles(arc, options.majorUnit);
                var labels = that.labels;
                var count = labels.length;
                var labelsOptions = options.labels;
                var padding = labelsOptions.padding;
                var rangeDistance = radius * 0.05;
                var rangeSize = options.rangeSize = options.rangeSize || radius * 0.1;
                var ranges = options.ranges || [];
                var halfWidth, halfHeight, labelAngle;
                var angle, label, lp, i, cx, cy, isInside;
                var labelsGroup = new Group();
                var lbl, labelPos, prevLabelPos, labelTransform;
                if (that.options.rangeDistance !== undefined) {
                    rangeDistance = that.options.rangeDistance;
                } else {
                    that.options.rangeDistance = rangeDistance;
                }
                if (labelsOptions.position === INSIDE) {
                    radius -= majorTickSize;
                    if (ranges.length && that.labelElements === undefined) {
                        radius -= rangeSize + rangeDistance;
                    }
                    arc.setRadiusX(radius).setRadiusY(radius);
                }
                for (i = 0; i < count; i++) {
                    label = labels[i];
                    halfWidth = label.box.width() / 2;
                    halfHeight = label.box.height() / 2;
                    angle = tickAngles[i];
                    labelAngle = (angle - GEO_ARC_ADJUST_ANGLE) * DEGREE;
                    isInside = labelsOptions.position === INSIDE;
                    lp = arc.pointAt(angle);
                    cx = lp.x + math.cos(labelAngle) * (halfWidth + padding) * (isInside ? 1 : -1);
                    cy = lp.y + math.sin(labelAngle) * (halfHeight + padding) * (isInside ? 1 : -1);
                    label.reflow(new dataviz.Box2D(cx - halfWidth, cy - halfHeight, cx + halfWidth, cy + halfHeight));
                    labelPos = new Point(label.box.x1, label.box.y1);
                    if (that.labelElements === undefined) {
                        lbl = _buildLabel(label, options.labels);
                        labelsGroup.append(lbl);
                    } else {
                        lbl = that.labelElements.children[i];
                        prevLabelPos = lbl.bbox().origin;
                        labelTransform = lbl.transform() || geo.transform();
                        labelTransform.translate(labelPos.x - prevLabelPos.x, labelPos.y - prevLabelPos.y);
                        lbl.transform(labelTransform);
                    }
                    that.bbox = Rect.union(that.bbox, lbl.bbox());
                }
                return labelsGroup;
            },
            repositionRanges: function () {
                var that = this;
                var ranges = that.ranges.children;
                var rangeSize = that.options.rangeSize;
                var rangeDistance = that.options.rangeDistance;
                var rangeRadius, newRadius;
                if (ranges.length > 0) {
                    rangeRadius = that.getRangeRadius();
                    if (that.options.labels.position === INSIDE) {
                        rangeRadius += rangeSize + rangeDistance;
                    }
                    newRadius = rangeRadius + rangeSize / 2;
                    for (var i = 0; i < ranges.length; i++) {
                        ranges[i]._geometry.setRadiusX(newRadius).setRadiusY(newRadius);
                    }
                    that.bbox = Rect.union(that.bbox, that.ranges.bbox());
                }
            },
            renderRanges: function () {
                var that = this;
                var arc = that.arc;
                var result = new Group();
                var from, to;
                var segments = that.rangeSegments();
                var segmentsCount = segments.length;
                var reverse = that.options.reverse;
                var rangeSize = that.options.rangeSize;
                var rangeDistance = that.options.rangeDistance;
                var segment, rangeRadius, rangeGeom, i;
                if (segmentsCount) {
                    rangeRadius = that.getRangeRadius();
                    that.radius(that.radius() - rangeSize - rangeDistance);
                    for (i = 0; i < segmentsCount; i++) {
                        segment = segments[i];
                        from = that.slotAngle(segment[reverse ? 'to' : 'from']);
                        to = that.slotAngle(segment[!reverse ? 'to' : 'from']);
                        if (to - from !== 0) {
                            rangeGeom = new geo.Arc(arc.center, {
                                radiusX: rangeRadius + rangeSize / 2,
                                radiusY: rangeRadius + rangeSize / 2,
                                startAngle: from,
                                endAngle: to
                            });
                            result.append(new draw.Arc(rangeGeom, {
                                stroke: {
                                    width: rangeSize,
                                    color: segment.color,
                                    opacity: segment.opacity
                                }
                            }));
                        }
                    }
                }
                return result;
            },
            rangeSegments: function () {
                var gauge = this;
                var options = gauge.options;
                var ranges = options.ranges || [];
                var count = ranges.length;
                var range;
                var segmentsCount;
                var defaultColor = options.rangePlaceholderColor;
                var segments = [];
                var segment;
                var min = options.min;
                var max = options.max;
                var i, j;
                function rangeSegment(from, to, color, opacity) {
                    return {
                        from: from,
                        to: to,
                        color: color,
                        opacity: opacity
                    };
                }
                if (count) {
                    segments.push(rangeSegment(min, max, defaultColor));
                    for (i = 0; i < count; i++) {
                        range = getRange(ranges[i], min, max);
                        segmentsCount = segments.length;
                        for (j = 0; j < segmentsCount; j++) {
                            segment = segments[j];
                            if (segment.from <= range.from && range.from <= segment.to) {
                                segments.push(rangeSegment(range.from, range.to, range.color, range.opacity));
                                if (segment.from <= range.to && range.to <= segment.to) {
                                    segments.push(rangeSegment(range.to, segment.to, defaultColor, range.opacity));
                                }
                                segment.to = range.from;
                                break;
                            }
                        }
                    }
                }
                return segments;
            },
            getRangeRadius: function () {
                var that = this;
                var options = that.options;
                var majorTickSize = options.majorTicks.size;
                var rangeSize = options.rangeSize;
                var rangeDistance = options.rangeDistance;
                var arc = that.arc;
                var r;
                if (options.labels.position === OUTSIDE) {
                    r = arc.getRadiusX() - majorTickSize - rangeDistance - rangeSize;
                } else {
                    r = arc.getRadiusX() - rangeSize;
                }
                return r;
            },
            renderArc: function (center, radius) {
                var that = this;
                var options = that.options;
                var arc = that.arc = new geo.Arc(center, {
                    radiusX: radius,
                    radiusY: radius,
                    startAngle: options.startAngle + GEO_ARC_ADJUST_ANGLE,
                    endAngle: options.endAngle + GEO_ARC_ADJUST_ANGLE
                });
                return arc;
            },
            renderTicks: function () {
                var that = this;
                var arc = that.arc;
                var options = that.options;
                var labelsPosition = options.labels.position;
                var allTicks = new Group();
                var majorTickSize = options.majorTicks.size;
                var minorTickSize = options.minorTicks.size;
                var tickArc = arc.clone();
                var radius = tickArc.getRadiusX();
                function drawTicks(arc, tickAngles, unit, tickOptions) {
                    var ticks = new Group(), center = arc.center, radius = arc.getRadiusX(), i, tickStart, tickEnd, visible = tickOptions.visible;
                    if (visible) {
                        for (i = 0; i < tickAngles.length; i++) {
                            tickStart = arc.pointAt(tickAngles[i]);
                            tickEnd = new Point(center.x + radius - tickOptions.size, center.y).rotate(tickAngles[i], center);
                            ticks.append(new Path({
                                stroke: {
                                    color: tickOptions.color,
                                    width: tickOptions.width
                                }
                            }).moveTo(tickStart).lineTo(tickEnd));
                        }
                    }
                    return ticks;
                }
                that.majorTickAngles = that.tickAngles(arc, options.majorUnit);
                that.majorTicks = drawTicks(tickArc, that.majorTickAngles, options.majorUnit, options.majorTicks);
                allTicks.append(that.majorTicks);
                that._tickDifference = majorTickSize - minorTickSize;
                if (labelsPosition === OUTSIDE) {
                    tickArc.setRadiusX(radius - majorTickSize + minorTickSize).setRadiusY(radius - majorTickSize + minorTickSize);
                }
                that.minorTickAngles = that.normalizeTickAngles(that.tickAngles(arc, options.minorUnit));
                that.minorTicks = drawTicks(tickArc, that.minorTickAngles, options.minorUnit, options.minorTicks, options.majorUnit);
                allTicks.append(that.minorTicks);
                return allTicks;
            },
            normalizeTickAngles: function (angles) {
                var that = this;
                var options = that.options;
                var skip = options.majorUnit / options.minorUnit;
                for (var i = angles.length - 1; i >= 0; i--) {
                    if (i % skip === 0) {
                        angles.splice(i, 1);
                    }
                }
                return angles;
            },
            tickAngles: function (ring, stepValue) {
                var scale = this;
                var options = scale.options;
                var reverse = options.reverse;
                var range = options.max - options.min;
                var angle = ring.endAngle - ring.startAngle;
                var pos = ring.startAngle;
                var tickCount = range / stepValue;
                var step = angle / tickCount;
                var positions = [];
                var i;
                if (reverse) {
                    pos += angle;
                    step = -step;
                }
                for (i = 0; i < tickCount; i++) {
                    positions.push(round(pos, COORD_PRECISION));
                    pos += step;
                }
                if (round(pos) <= ring.endAngle) {
                    positions.push(pos);
                }
                return positions;
            },
            radius: function (radius) {
                var that = this;
                if (radius) {
                    that.arc.setRadiusX(radius).setRadiusY(radius);
                    that.repositionTicks(that.majorTicks.children, that.majorTickAngles);
                    that.repositionTicks(that.minorTicks.children, that.minorTickAngles, true);
                } else {
                    return that.arc.getRadiusX();
                }
            },
            repositionTicks: function (ticks, tickAngles, minor) {
                var that = this;
                var diff = minor ? that._tickDifference || 0 : 0;
                var tickArc = that.arc;
                var radius = tickArc.getRadiusX();
                if (minor && that.options.labels.position === OUTSIDE && diff !== 0) {
                    tickArc = that.arc.clone();
                    tickArc.setRadiusX(radius - diff).setRadiusY(radius - diff);
                }
                for (var i = 0; i < ticks.length; i++) {
                    var newPoint = tickArc.pointAt(tickAngles[i]);
                    var segments = ticks[i].segments;
                    var xDiff = newPoint.x - segments[0].anchor().x;
                    var yDiff = newPoint.y - segments[0].anchor().y;
                    ticks[i].transform(new geo.Transformation().translate(xDiff, yDiff));
                }
            }
        });
        var Gauge = Widget.extend({
            init: function (element, userOptions) {
                var gauge = this;
                var options;
                var themeOptions;
                var themeName;
                var themes = dataviz.ui.themes || {};
                var theme;
                kendo.destroy(element);
                $(element).empty();
                Widget.fn.init.call(gauge, element);
                gauge.wrapper = gauge.element;
                gauge._originalOptions = deepExtend({}, userOptions);
                options = deepExtend({}, gauge.options, userOptions);
                themeName = options.theme;
                theme = themes[themeName] || themes[themeName.toLowerCase()];
                themeOptions = themeName && theme ? theme.gauge : {};
                gauge.options = deepExtend({}, themeOptions, options);
                if ($.isArray(options.pointer)) {
                    for (var i = 0; i < options.pointer.length; i++) {
                        gauge.options.pointer[i] = deepExtend({}, themeOptions.pointer, options.pointer[i]);
                    }
                }
                gauge.element.addClass('k-gauge');
                gauge.surface = gauge._createSurface();
                gauge.redraw();
            },
            options: {
                plotArea: {},
                theme: 'default',
                renderAs: '',
                pointer: {},
                scale: {},
                gaugeArea: {}
            },
            destroy: function () {
                this.surface.destroy();
                Widget.fn.destroy.call(this);
            },
            value: function (value) {
                var that = this;
                var pointer = that.pointers[0];
                if (arguments.length === 0) {
                    return pointer.value();
                }
                pointer.value(value);
                that._setValueOptions(value);
            },
            _draw: function () {
                var surface = this.surface;
                surface.clear();
                surface.draw(this._visuals);
            },
            exportVisual: function () {
                return this._visuals;
            },
            allValues: function (values) {
                var that = this;
                var pointers = that.pointers;
                var allValues = [];
                var i;
                if (arguments.length === 0) {
                    for (i = 0; i < pointers.length; i++) {
                        allValues.push(pointers[i].value());
                    }
                    return allValues;
                }
                if ($.isArray(values)) {
                    for (i = 0; i < values.length; i++) {
                        if (isNumber(values[i])) {
                            pointers[i].value(values[i]);
                        }
                    }
                }
                that._setValueOptions(values);
            },
            _setValueOptions: function (values) {
                var pointers = [].concat(this.options.pointer);
                values = [].concat(values);
                for (var i = 0; i < values.length; i++) {
                    pointers[i].value = values[i];
                }
            },
            _resize: function () {
                var that = this;
                var t = that.options.transitions;
                var i;
                that.options.transitions = false;
                for (i = 0; i < that.pointers.length; i++) {
                    that.pointers[i].options.animation.transitions = false;
                }
                that.redraw();
                that.options.transitions = t;
                for (i = 0; i < that.pointers.length; i++) {
                    that.pointers[i].options.animation.transitions = t;
                }
            },
            redraw: function () {
                var that = this;
                var size = deepExtend(that._getSize(), that.options.gaugeArea);
                var wrapper = new Rect([
                    0,
                    0
                ], [
                    size.width,
                    size.height
                ]);
                var bbox;
                that.surface.clear();
                that.gaugeArea = that._createGaugeArea();
                that.surface.element.css({
                    width: size.width,
                    height: size.height
                });
                that._createModel();
                bbox = _unpad(wrapper.bbox(), that._gaugeAreaMargin);
                that.reflow(bbox);
            },
            _createGaugeArea: function () {
                var that = this;
                var options = that.options.gaugeArea;
                var size = that.surface.size();
                var border = options.border || {};
                var areaGeometry = new Rect([
                    0,
                    0
                ], [
                    size.width,
                    size.height
                ]);
                that._gaugeAreaMargin = options.margin || DEFAULT_MARGIN;
                if (border.width > 0) {
                    areaGeometry = _unpad(areaGeometry, border.width);
                }
                var gaugeArea = Path.fromRect(areaGeometry, {
                    stroke: {
                        color: border.width ? border.color : '',
                        width: border.width,
                        dashType: border.dashType,
                        lineJoin: 'round',
                        lineCap: 'round'
                    },
                    fill: { color: options.background }
                });
                return gaugeArea;
            },
            _createSurface: function () {
                var that = this;
                var options = that.options;
                var size = that._getSize();
                size = options.gaugeArea ? deepExtend(size, options.gaugeArea) : size;
                var wrap = $('<div></div>').appendTo(that.element).css({
                    width: size.width,
                    height: size.height
                });
                return new draw.Surface.create(wrap, { type: options.renderAs });
            },
            getSize: function () {
                return this._getSize();
            },
            _getSize: function () {
                var that = this;
                var element = that.element;
                var width = element.width();
                var height = element.height();
                if (!width) {
                    width = DEFAULT_WIDTH;
                }
                if (!height) {
                    height = DEFAULT_HEIGHT;
                }
                return {
                    width: width,
                    height: height
                };
            }
        });
        var RadialGauge = Gauge.extend({
            init: function (element, options) {
                var radialGauge = this;
                Gauge.fn.init.call(radialGauge, element, options);
                kendo.notify(radialGauge, dataviz.ui);
            },
            options: {
                name: 'RadialGauge',
                transitions: true,
                gaugeArea: { background: '' }
            },
            reflow: function (bbox) {
                var that = this;
                var pointers = that.pointers;
                that.scale.reflow(bbox);
                that._initialPlotArea = that.scale.bbox;
                for (var i = 0; i < pointers.length; i++) {
                    pointers[i].reflow(that.scale.arc);
                    that._initialPlotArea = Rect.union(that._initialPlotArea, pointers[i].bbox);
                }
                that.fitScale(bbox);
                that.alignScale(bbox);
                that._buildVisual(that.gaugeArea, pointers, that.scale);
                that._draw();
            },
            _buildVisual: function (gaugeArea, pointers, scale) {
                var visuals = new Group();
                var current;
                visuals.append(gaugeArea);
                visuals.append(scale.ticks);
                visuals.append(scale.ranges);
                for (var i = 0; i < pointers.length; i++) {
                    current = pointers[i];
                    current.render();
                    visuals.append(current.elements);
                    current.value(current.options.value);
                }
                visuals.append(scale.labelElements);
                this._visuals = visuals;
            },
            fitScale: function (bbox) {
                var that = this;
                var scale = that.scale;
                var arc = scale.arc;
                var plotAreaBox = that._initialPlotArea;
                var step = math.abs(that.getDiff(plotAreaBox, bbox));
                var min = round(step, COORD_PRECISION);
                var max = round(-step, COORD_PRECISION);
                var minDiff, midDiff, maxDiff, mid, oldDiff;
                var staleFlag = 0;
                var i = 0;
                while (i++ < 100) {
                    staleFlag = oldDiff === maxDiff ? staleFlag + 1 : 0;
                    if (staleFlag > 5) {
                        break;
                    }
                    if (min != mid) {
                        minDiff = that.getPlotBox(min, bbox, arc);
                        if (0 <= minDiff && minDiff <= 2) {
                            break;
                        }
                    }
                    if (max != mid) {
                        maxDiff = that.getPlotBox(max, bbox, arc);
                        if (0 <= maxDiff && maxDiff <= 2) {
                            break;
                        }
                    }
                    if (minDiff > 0 && maxDiff > 0) {
                        mid = min * 2;
                    } else if (minDiff < 0 && maxDiff < 0) {
                        mid = max * 2;
                    } else {
                        mid = round((min + max) / 2 || 1, COORD_PRECISION);
                    }
                    midDiff = that.getPlotBox(mid, bbox, arc);
                    if (0 <= midDiff && midDiff <= 2) {
                        break;
                    }
                    oldDiff = maxDiff;
                    if (midDiff > 0) {
                        max = mid;
                        maxDiff = midDiff;
                    } else {
                        min = mid;
                        minDiff = midDiff;
                    }
                }
            },
            getPlotBox: function (step, bbox, arc) {
                var that = this;
                var scale = that.scale;
                var pointers = that.pointers;
                var radius = arc.getRadiusX();
                arc = arc.clone();
                arc.setRadiusX(radius + step).setRadiusY(radius + step);
                scale.arc = arc;
                scale.reflow(bbox);
                that.plotBbox = scale.bbox;
                for (var i = 0; i < pointers.length; i++) {
                    pointers[i].reflow(arc);
                    that.plotBbox = Rect.union(that.plotBbox, pointers[i].bbox);
                }
                return that.getDiff(that.plotBbox, bbox);
            },
            getDiff: function (plotBox, box) {
                return math.min(box.width() - plotBox.width(), box.height() - plotBox.height());
            },
            alignScale: function (bbox) {
                var that = this;
                var plotBoxCenter = that.plotBbox.center();
                var boxCenter = bbox.center();
                var paddingX = plotBoxCenter.x - boxCenter.x;
                var paddingY = plotBoxCenter.y - boxCenter.y;
                var scale = that.scale;
                var pointers = that.pointers;
                scale.arc.center.x -= paddingX;
                scale.arc.center.y -= paddingY;
                scale.reflow(bbox);
                for (var i = 0; i < pointers.length; i++) {
                    pointers[i].reflow(scale.arc);
                    that.plotBbox = Rect.union(scale.bbox, pointers[i].bbox);
                }
            },
            _createModel: function () {
                var that = this;
                var options = that.options;
                var pointers = options.pointer;
                var scale = that.scale = new RadialScale(options.scale);
                var current;
                that.pointers = [];
                pointers = $.isArray(pointers) ? pointers : [pointers];
                for (var i = 0; i < pointers.length; i++) {
                    current = new RadialPointer(scale, deepExtend({}, pointers[i], { animation: { transitions: options.transitions } }));
                    that.pointers.push(current);
                }
            }
        });
        var LinearGauge = Gauge.extend({
            init: function (element, options) {
                var linearGauge = this;
                Gauge.fn.init.call(linearGauge, element, options);
                kendo.notify(linearGauge, dataviz.ui);
            },
            options: {
                name: 'LinearGauge',
                transitions: true,
                gaugeArea: { background: '' },
                scale: { vertical: true }
            },
            reflow: function (bbox) {
                var that = this;
                var pointers = that.pointers;
                var bboxX = bbox.origin.x;
                var bboxY = bbox.origin.y;
                var bbox2D = new dataviz.Box2D(bboxX, bboxY, bboxX + bbox.width(), bboxY + bbox.height());
                that.scale.reflow(bbox2D);
                for (var i = 0; i < pointers.length; i++) {
                    pointers[i].reflow();
                }
                that.bbox = that._getBox(bbox2D);
                that._alignElements();
                that._shrinkElements();
                that._buildVisual();
                that._draw();
            },
            _buildVisual: function () {
                var that = this;
                var visuals = new Group();
                var scaleElements = that.scale.render();
                var pointers = that.pointers;
                var current;
                visuals.append(that.gaugeArea);
                visuals.append(scaleElements);
                for (var i = 0; i < pointers.length; i++) {
                    current = pointers[i];
                    visuals.append(current.render());
                    current.value(current.options.value);
                }
                that._visuals = visuals;
            },
            _createModel: function () {
                var that = this;
                var options = that.options;
                var pointers = options.pointer;
                var scale = that.scale = new LinearScale(options.scale);
                var current, currentOptions;
                that.pointers = [];
                pointers = $.isArray(pointers) ? pointers : [pointers];
                for (var i = 0; i < pointers.length; i++) {
                    currentOptions = deepExtend({}, pointers[i], { animation: { transitions: options.transitions } });
                    if (currentOptions.shape === ARROW) {
                        current = new ArrowLinearPointer(scale, currentOptions);
                    } else {
                        current = new BarLinearPointer(scale, currentOptions);
                    }
                    that.pointers.push(current);
                }
            },
            _getSize: function () {
                var gauge = this;
                var element = gauge.element;
                var width = element.width();
                var height = element.height();
                var vertical = gauge.options.scale.vertical;
                if (!width) {
                    width = vertical ? DEFAULT_MIN_WIDTH : DEFAULT_WIDTH;
                }
                if (!height) {
                    height = vertical ? DEFAULT_HEIGHT : DEFAULT_MIN_HEIGHT;
                }
                return {
                    width: width,
                    height: height
                };
            },
            _getBox: function (box) {
                var that = this;
                var scale = that.scale;
                var pointers = that.pointers;
                var boxCenter = box.center();
                var plotAreaBox = pointers[0].box.clone().wrap(scale.box);
                var size;
                for (var i = 0; i < pointers.length; i++) {
                    plotAreaBox.wrap(pointers[i].box.clone());
                }
                if (scale.options.vertical) {
                    size = plotAreaBox.width() / 2;
                    plotAreaBox = new Box2D(boxCenter.x - size, box.y1, boxCenter.x + size, box.y2);
                } else {
                    size = plotAreaBox.height() / 2;
                    plotAreaBox = new Box2D(box.x1, boxCenter.y - size, box.x2, boxCenter.y + size);
                }
                return plotAreaBox;
            },
            _alignElements: function () {
                var that = this;
                var scale = that.scale;
                var pointers = that.pointers;
                var scaleBox = scale.box;
                var box = pointers[0].box.clone().wrap(scale.box);
                var plotAreaBox = that.bbox;
                var diff, i;
                for (i = 0; i < pointers.length; i++) {
                    box.wrap(pointers[i].box.clone());
                }
                if (scale.options.vertical) {
                    diff = plotAreaBox.center().x - box.center().x;
                    scale.reflow(new Box2D(scaleBox.x1 + diff, plotAreaBox.y1, scaleBox.x2 + diff, plotAreaBox.y2));
                } else {
                    diff = plotAreaBox.center().y - box.center().y;
                    scale.reflow(new Box2D(plotAreaBox.x1, scaleBox.y1 + diff, plotAreaBox.x2, scaleBox.y2 + diff));
                }
                for (i = 0; i < pointers.length; i++) {
                    pointers[i].reflow(that.bbox);
                }
            },
            _shrinkElements: function () {
                var that = this;
                var scale = that.scale;
                var pointers = that.pointers;
                var scaleBox = scale.box.clone();
                var pos = scale.options.vertical ? 'y' : 'x';
                var pointerBox = pointers[0].box;
                var i;
                for (i = 0; i < pointers.length; i++) {
                    pointerBox.wrap(pointers[i].box.clone());
                }
                scaleBox[pos + 1] += math.max(scaleBox[pos + 1] - pointerBox[pos + 1], 0);
                scaleBox[pos + 2] -= math.max(pointerBox[pos + 2] - scaleBox[pos + 2], 0);
                scale.reflow(scaleBox);
                for (i = 0; i < pointers.length; i++) {
                    pointers[i].reflow(that.bbox);
                }
            }
        });
        var LinearScale = NumericAxis.extend({
            init: function (options) {
                var scale = this;
                scale.options = deepExtend({}, scale.options, options);
                scale.options = deepExtend({}, scale.options, { labels: { mirror: scale.options.mirror } });
                scale.options.majorUnit = scale.options.majorUnit || autoMajorUnit(scale.options.min, scale.options.max);
                Axis.fn.init.call(scale, scale.options);
                scale.options.minorUnit = scale.options.minorUnit || scale.options.majorUnit / 10;
            },
            options: {
                min: 0,
                max: 50,
                majorTicks: {
                    size: 15,
                    align: INSIDE,
                    color: BLACK,
                    width: DEFAULT_LINE_WIDTH,
                    visible: true
                },
                minorTicks: {
                    size: 10,
                    align: INSIDE,
                    color: BLACK,
                    width: DEFAULT_LINE_WIDTH,
                    visible: true
                },
                line: { width: DEFAULT_LINE_WIDTH },
                labels: {
                    position: INSIDE,
                    padding: 2
                },
                mirror: false,
                _alignLines: false
            },
            render: function () {
                var that = this;
                var elements = that.elements = new Group();
                var labels = that.renderLabels();
                var scaleLine = that.renderLine();
                var scaleTicks = that.renderTicks();
                var ranges = that.renderRanges();
                elements.append(scaleLine, labels, scaleTicks, ranges);
                return elements;
            },
            renderRanges: function () {
                var that = this;
                var options = that.options;
                var min = options.min;
                var max = options.max;
                var ranges = options.ranges || [];
                var vertical = options.vertical;
                var mirror = options.labels.mirror;
                var elements = new Group();
                var count = ranges.length;
                var rangeSize = options.rangeSize || options.minorTicks.size / 2;
                var range, slot, slotX, slotY, i;
                if (count) {
                    for (i = 0; i < count; i++) {
                        range = getRange(ranges[i], min, max);
                        slot = that.getSlot(range.from, range.to);
                        slotX = vertical ? that.lineBox() : slot;
                        slotY = vertical ? slot : that.lineBox();
                        if (vertical) {
                            slotX.x1 -= rangeSize * (mirror ? -1 : 1);
                        } else {
                            slotY.y2 += rangeSize * (mirror ? -1 : 1);
                        }
                        elements.append(Path.fromRect(new Rect([
                            slotX.x1,
                            slotY.y1
                        ], [
                            slotX.x2 - slotX.x1,
                            slotY.y2 - slotY.y1
                        ]), {
                            fill: {
                                color: range.color,
                                opacity: range.opacity
                            },
                            stroke: {}
                        }));
                    }
                }
                return elements;
            },
            renderLabels: function () {
                var that = this;
                var options = that.options;
                var labels = that.labels;
                var elements = new Group();
                for (var i = 0; i < labels.length; i++) {
                    elements.append(_buildLabel(labels[i], options.labels));
                }
                return elements;
            },
            renderLine: function () {
                var that = this;
                var options = that.options;
                var line = options.line;
                var lineBox = that.lineBox();
                var linePath;
                var elements = new Group();
                if (line.width > 0 && line.visible) {
                    linePath = new Path({
                        stroke: {
                            color: line.color,
                            dashType: line.dashType,
                            width: line.width
                        }
                    });
                    linePath.moveTo(lineBox.x1, lineBox.y1).lineTo(lineBox.x2, lineBox.y2);
                    elements.append(linePath);
                }
                return elements;
            },
            renderTicks: function () {
                var that = this;
                var ticks = new Group();
                var options = that.options;
                var lineBox = that.lineBox();
                var mirror = options.labels.mirror;
                var majorUnit = options.majorTicks.visible ? options.majorUnit : 0;
                var tickLineOptions = {
                    _alignLines: options._alignLines,
                    vertical: options.vertical
                };
                function render(tickPositions, tickOptions) {
                    var i, count = tickPositions.length;
                    if (tickOptions.visible) {
                        for (i = tickOptions.skip; i < count; i += tickOptions.step) {
                            if (i % tickOptions.skipUnit === 0) {
                                continue;
                            }
                            tickLineOptions.tickX = mirror ? lineBox.x2 : lineBox.x2 - tickOptions.size;
                            tickLineOptions.tickY = mirror ? lineBox.y1 - tickOptions.size : lineBox.y1;
                            tickLineOptions.position = tickPositions[i];
                            ticks.append(that.renderAxisTick(tickLineOptions, tickOptions));
                        }
                    }
                }
                render(that.getMajorTickPositions(), options.majorTicks);
                render(that.getMinorTickPositions(), deepExtend({}, { skipUnit: majorUnit / options.minorUnit }, options.minorTicks));
                return ticks;
            },
            renderAxisTick: function (options, tickOptions) {
                var tickX = options.tickX;
                var tickY = options.tickY;
                var position = options.position;
                var start, end, tickPath;
                if (options.vertical) {
                    start = new Point(tickX, position);
                    end = new Point(tickX + tickOptions.size, position);
                } else {
                    start = new Point(position, tickY);
                    end = new Point(position, tickY + tickOptions.size);
                }
                tickPath = new Path({
                    stroke: {
                        color: tickOptions.color,
                        width: tickOptions.width
                    }
                }).moveTo(start).lineTo(end);
                return tickPath;
            }
        });
        var LinearPointer = Pointer.extend({
            init: function (scale, options) {
                var pointer = this;
                Pointer.fn.init.call(pointer, scale, options);
                pointer.options = deepExtend({ track: { visible: defined(options.track) } }, pointer.options);
            },
            options: {
                shape: BAR_POINTER,
                track: { border: { width: 1 } },
                color: BLACK,
                border: { width: 1 },
                opacity: 1,
                margin: getSpacing(3),
                animation: { type: BAR_POINTER },
                visible: true
            },
            reflow: function () {
                var pointer = this;
                var options = pointer.options;
                var scale = pointer.scale;
                var scaleLine = scale.lineBox();
                var trackSize = options.track.size || options.size;
                var pointerHalfSize = options.size / 2;
                var mirror = scale.options.mirror;
                var margin = getSpacing(options.margin);
                var vertical = scale.options.vertical;
                var space = vertical ? margin[mirror ? 'left' : 'right'] : margin[mirror ? 'bottom' : 'top'];
                var pointerBox, pointerRangeBox, trackBox;
                space = mirror ? -space : space;
                if (vertical) {
                    trackBox = new Box2D(scaleLine.x1 + space, scaleLine.y1, scaleLine.x1 + space, scaleLine.y2);
                    if (mirror) {
                        trackBox.x1 -= trackSize;
                    } else {
                        trackBox.x2 += trackSize;
                    }
                    if (options.shape !== BAR_POINTER) {
                        pointerRangeBox = new Box2D(scaleLine.x2 + space, scaleLine.y1 - pointerHalfSize, scaleLine.x2 + space, scaleLine.y2 + pointerHalfSize);
                        pointerBox = pointerRangeBox;
                    }
                } else {
                    trackBox = new Box2D(scaleLine.x1, scaleLine.y1 - space, scaleLine.x2, scaleLine.y1 - space);
                    if (mirror) {
                        trackBox.y2 += trackSize;
                    } else {
                        trackBox.y1 -= trackSize;
                    }
                    if (options.shape !== BAR_POINTER) {
                        pointerRangeBox = new Box2D(scaleLine.x1 - pointerHalfSize, scaleLine.y1 - space, scaleLine.x2 + pointerHalfSize, scaleLine.y1 - space);
                        pointerBox = pointerRangeBox;
                    }
                }
                pointer.trackBox = trackBox;
                pointer.pointerRangeBox = pointerRangeBox;
                pointer.box = pointerBox || trackBox.clone().pad(options.border.width);
            },
            getElementOptions: function () {
                var options = this.options;
                return {
                    fill: {
                        color: options.color,
                        opacity: options.opacity
                    },
                    stroke: defined(options.border) ? {
                        color: options.border.width ? options.border.color || options.color : '',
                        width: options.border.width,
                        dashType: options.border.dashType,
                        opacity: options.opacity
                    } : null
                };
            },
            _margin: function () {
                var pointer = this;
                var options = pointer.options;
                var scale = pointer.scale;
                var mirror = scale.options.mirror;
                var margin = getSpacing(options.margin);
                var vertical = scale.options.vertical;
                var space = vertical ? margin[mirror ? 'left' : 'right'] : margin[mirror ? 'bottom' : 'top'];
                return space;
            }
        });
        var ArrowLinearPointer = LinearPointer.extend({
            init: function (scale, options) {
                LinearPointer.fn.init.call(this, scale, options);
                if (this.options.size === undefined) {
                    this.options.size = this.scale.options.majorTicks.size * 0.6;
                }
            },
            pointerShape: function () {
                var that = this;
                var options = that.options;
                var scale = that.scale;
                var size = options.size;
                var vertical = scale.options.vertical;
                var halfSize = size / 2;
                var sign = scale.options.mirror ? -1 : 1;
                var reverse = scale.options.reverse;
                var pos, shape;
                if (vertical) {
                    pos = reverse ? 'y2' : 'y1';
                    shape = [
                        new Point(0, 0 - halfSize),
                        new Point(0 - sign * size, 0),
                        new Point(0, 0 + halfSize)
                    ];
                } else {
                    pos = reverse ? 'x1' : 'x2';
                    shape = [
                        new Point(0 - halfSize, 0),
                        new Point(0, 0 + sign * size),
                        new Point(0 + halfSize, 0)
                    ];
                }
                return shape;
            },
            repaint: function () {
                var that = this;
                var scale = that.scale;
                var options = that.options;
                var animation = new ArrowLinearPointerAnimation(that.elements, deepExtend(options.animation, {
                    vertical: scale.options.vertical,
                    mirror: scale.options.mirror,
                    margin: that._margin(options.margin),
                    from: scale.getSlot(options._oldValue),
                    to: scale.getSlot(options.value)
                }));
                if (options.animation.transitions === false) {
                    animation.options.duration = 0;
                }
                animation.setup();
                animation.play();
            },
            render: function () {
                var that = this;
                var options = that.options;
                var elements = new Group();
                var scale = that.scale;
                var elementOptions = that.getElementOptions();
                var shape = that.pointerShape(options.value);
                options.animation.type = ARROW_POINTER;
                elements = new Path({
                    stroke: elementOptions.stroke,
                    fill: elementOptions.fill
                }).moveTo(shape[0]).lineTo(shape[1]).lineTo(shape[2]).close();
                var slot = scale.getSlot(options.value);
                elements.transform(geo.transform().translate(slot.x1, slot.y1));
                that.elements = elements;
                return elements;
            }
        });
        var BarLinearPointer = LinearPointer.extend({
            init: function (scale, options) {
                LinearPointer.fn.init.call(this, scale, options);
                if (this.options.size === undefined) {
                    this.options.size = this.scale.options.majorTicks.size * 0.3;
                }
            },
            pointerShape: function (value) {
                var that = this;
                var options = that.options;
                var scale = that.scale;
                var vertical = scale.options.vertical;
                var mirror = scale.options.mirror;
                var dir = mirror == vertical ? -1 : 1;
                var size = options.size * dir;
                var minSlot = scale.getSlot(scale.options.min);
                var slot = scale.getSlot(value);
                var axis = vertical ? Y : X;
                var sizeAxis = vertical ? X : Y;
                var margin = that._margin() * dir;
                var p1 = new Point();
                p1[axis] = minSlot[axis + '1'];
                p1[sizeAxis] = minSlot[sizeAxis + '1'];
                var p2 = new Point();
                p2[axis] = slot[axis + '1'];
                p2[sizeAxis] = slot[sizeAxis + '1'];
                if (vertical) {
                    p1.translate(margin, 0);
                    p2.translate(margin, 0);
                } else {
                    p1.translate(0, margin);
                    p2.translate(0, margin);
                }
                var p3 = p2.clone();
                var p4 = p1.clone();
                if (vertical) {
                    p3.translate(size, 0);
                    p4.translate(size, 0);
                } else {
                    p3.translate(0, size);
                    p4.translate(0, size);
                }
                return [
                    p1,
                    p2,
                    p3,
                    p4
                ];
            },
            repaint: function () {
                var that = this;
                var scale = that.scale;
                var options = that.options;
                var shape = that.pointerShape(options.value);
                var pointerPath = that.elements.children[0];
                var oldShape = that.pointerShape(options._oldValue);
                pointerPath.moveTo(shape[0]).lineTo(shape[1]).lineTo(shape[2]).lineTo(shape[3]).close();
                var animation = new BarLinearPointerAnimation(pointerPath, deepExtend(options.animation, {
                    reverse: scale.options.reverse,
                    vertical: scale.options.vertical,
                    oldPoints: [
                        oldShape[1],
                        oldShape[2]
                    ],
                    newPoints: [
                        shape[1],
                        shape[2]
                    ]
                }));
                if (options.animation.transitions === false) {
                    animation.options.duration = 0;
                }
                animation.setup();
                animation.play();
            },
            render: function () {
                var that = this;
                var group = new Group();
                var elementOptions = that.getElementOptions();
                var pointer = new Path({
                    stroke: elementOptions.stroke,
                    fill: elementOptions.fill
                });
                group.append(pointer);
                that.elements = group;
                return group;
            }
        });
        var RadialPointerAnimation = draw.Animation.extend({
            init: function (element, options) {
                draw.Animation.fn.init.call(this, element, options);
                options = this.options;
                options.duration = math.max(math.abs(options.newAngle - options.oldAngle) / options.duration * 1000, 1);
            },
            options: {
                easing: LINEAR,
                duration: ANGULAR_SPEED
            },
            step: function (pos) {
                var anim = this;
                var options = anim.options;
                var angle = interpolateValue(options.oldAngle, options.newAngle, pos);
                anim.element.transform(geo.transform().rotate(angle, options.center));
            }
        });
        draw.AnimationFactory.current.register(RADIAL_POINTER, RadialPointerAnimation);
        var ArrowLinearPointerAnimation = draw.Animation.extend({
            options: {
                easing: LINEAR,
                duration: LINEAR_SPEED
            },
            setup: function () {
                var options = this.options;
                var margin = options.margin;
                var from = options.from;
                var to = options.to;
                var axis = options.vertical ? 'x1' : 'y1';
                if (options.mirror == options.vertical) {
                    from[axis] -= margin;
                    to[axis] -= margin;
                } else {
                    from[axis] += margin;
                    to[axis] += margin;
                }
                var fromScale = this.fromScale = new Point(from.x1, from.y1);
                var toScale = this.toScale = new Point(to.x1, to.y1);
                if (options.duration !== 0) {
                    options.duration = math.max(fromScale.distanceTo(toScale) / options.duration * 1000, 1);
                }
            },
            step: function (pos) {
                var translateX = interpolateValue(this.fromScale.x, this.toScale.x, pos);
                var translateY = interpolateValue(this.fromScale.y, this.toScale.y, pos);
                this.element.transform(geo.transform().translate(translateX, translateY));
            }
        });
        draw.AnimationFactory.current.register(ARROW_POINTER, ArrowLinearPointerAnimation);
        var BarLinearPointerAnimation = draw.Animation.extend({
            options: {
                easing: LINEAR,
                speed: LINEAR_SPEED
            },
            setup: function () {
                var options = this.options;
                var newPoints = options.newPoints;
                var oldPoints = options.oldPoints;
                var axis = this.axis = options.vertical ? Y : X;
                var to = this.to = newPoints[0][axis];
                var from = this.from = oldPoints[0][axis];
                if (options.duration !== 0) {
                    options.duration = math.max(math.abs(to - from) / options.speed * 1000, 1);
                }
                this._set(from);
            },
            step: function (pos) {
                var value = interpolateValue(this.from, this.to, pos);
                this._set(value);
            },
            _set: function (value) {
                var setter = 'set' + this.axis.toUpperCase();
                var points = this.options.newPoints;
                points[0][setter](value);
                points[1][setter](value);
            }
        });
        draw.AnimationFactory.current.register(BAR_POINTER, BarLinearPointerAnimation);
        function _buildLabel(label, options) {
            var labelBox = label.box;
            var textBox = label.children[0].box;
            var border = options.border || {};
            var background = options.background || '';
            var elements = new Group();
            var styleBox, styleGeometry, wrapper;
            wrapper = Path.fromRect(new Rect([
                labelBox.x1,
                labelBox.y1
            ], [
                labelBox.width(),
                labelBox.height()
            ]), { stroke: {} });
            var text = new Text(label.text, new Point(textBox.x1, textBox.y1), {
                font: options.font,
                fill: { color: options.color }
            });
            styleGeometry = _pad(text.bbox().clone(), options.padding);
            styleBox = Path.fromRect(styleGeometry, {
                stroke: {
                    color: border.width ? border.color : '',
                    width: border.width,
                    dashType: border.dashType,
                    lineJoin: 'round',
                    lineCap: 'round'
                },
                fill: { color: background }
            });
            elements.append(wrapper);
            elements.append(styleBox);
            elements.append(text);
            return elements;
        }
        function getRange(range, min, max) {
            var from = defined(range.from) ? range.from : MIN_VALUE;
            var to = defined(range.to) ? range.to : MAX_VALUE;
            range.from = math.max(math.min(to, from), min);
            range.to = math.min(math.max(to, from), max);
            return range;
        }
        function _pad(bbox, value) {
            var origin = bbox.getOrigin();
            var size = bbox.getSize();
            var spacing = getSpacing(value);
            bbox.setOrigin([
                origin.x - spacing.left,
                origin.y - spacing.top
            ]);
            bbox.setSize([
                size.width + (spacing.left + spacing.right),
                size.height + (spacing.top + spacing.bottom)
            ]);
            return bbox;
        }
        function _unpad(bbox, value) {
            var spacing = getSpacing(value);
            spacing.left = -spacing.left;
            spacing.top = -spacing.top;
            spacing.right = -spacing.right;
            spacing.bottom = -spacing.bottom;
            return _pad(bbox, spacing);
        }
        dataviz.ui.plugin(RadialGauge);
        dataviz.ui.plugin(LinearGauge);
        dataviz.ExportMixin.extend(Gauge.fn);
        deepExtend(dataviz, {
            Gauge: Gauge,
            RadialPointer: RadialPointer,
            LinearPointer: LinearPointer,
            ArrowLinearPointer: ArrowLinearPointer,
            BarLinearPointer: BarLinearPointer,
            LinearScale: LinearScale,
            RadialScale: RadialScale,
            LinearGauge: LinearGauge,
            RadialGauge: RadialGauge
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.barcode', [
        'kendo.dataviz.core',
        'kendo.drawing'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.barcode',
        name: 'Barcode',
        category: 'dataviz',
        description: 'Barcode widget',
        depends: ['dataviz.core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, extend = $.extend, deepExtend = kendo.deepExtend, inArray = $.inArray, isPlainObject = $.isPlainObject, draw = kendo.drawing, geom = kendo.geometry, util = kendo.drawing.util, defined = util.defined, dataviz = kendo.dataviz, Box2D = dataviz.Box2D, TextBox = dataviz.TextBox, DEFAULT_WIDTH = 300, DEFAULT_HEIGHT = 100, DEFAULT_QUIETZONE_LENGTH = 10, numberRegex = /^\d+$/, alphanumericRegex = /^[a-z0-9]+$/i, InvalidCharacterErrorTemplate = 'Character \'{0}\' is not valid for symbology {1}';
        function getNext(value, index, count) {
            return value.substring(index, index + count);
        }
        var Encoding = kendo.Class.extend({
            init: function (options) {
                this.setOptions(options);
            },
            setOptions: function (options) {
                var that = this;
                that.options = extend({}, that.options, options);
                that.quietZoneLength = that.options.addQuietZone ? 2 * that.options.quietZoneLength : 0;
            },
            encode: function (value, width, height) {
                var that = this;
                if (defined(value)) {
                    value += '';
                }
                that.initValue(value, width, height);
                if (that.options.addQuietZone) {
                    that.addQuietZone();
                }
                that.addData();
                if (that.options.addQuietZone) {
                    that.addQuietZone();
                }
                return {
                    baseUnit: that.baseUnit,
                    pattern: that.pattern
                };
            },
            options: {
                quietZoneLength: DEFAULT_QUIETZONE_LENGTH,
                addQuietZone: true,
                addCheckSum: true
            },
            initValue: function () {
            },
            addQuietZone: function () {
                this.pattern.push(this.options.quietZoneLength || DEFAULT_QUIETZONE_LENGTH);
            },
            addData: function () {
            },
            invalidCharacterError: function (character) {
                throw new Error(kendo.format(InvalidCharacterErrorTemplate, character, this.name));
            }
        });
        var encodings = {};
        var code39Base = Encoding.extend({
            minBaseUnitLength: 0.7,
            addData: function () {
                var that = this, value = that.value;
                that.addStart();
                for (var idx = 0; idx < value.length; idx++) {
                    that.addCharacter(value.charAt(idx));
                }
                if (that.options.addCheckSum) {
                    that.pushCheckSum();
                }
                that.addStop();
                that.prepareValues();
            },
            addCharacter: function (character) {
                var that = this, charData = that.characterMap[character];
                if (!charData) {
                    that.invalidCharacterError(character);
                }
                that.addBase(charData);
            },
            addBase: function () {
            }
        });
        var code39ExtendedBase = {
            addCharacter: function (character) {
                var that = this;
                if (that.characterMap[character]) {
                    that.addBase(that.characterMap[character]);
                } else if (character.charCodeAt(0) > 127) {
                    that.invalidCharacterError(character);
                } else {
                    that.addExtended(character.charCodeAt(0));
                }
            },
            addExtended: function (code) {
                var that = this, patterns;
                for (var i = 0; i < that.extendedMappings.length; i++) {
                    if (patterns = that.extendedMappings[i].call(that, code)) {
                        for (var j = 0; j < patterns.length; j++) {
                            that.addBase(patterns[j]);
                        }
                        that.dataLength += patterns.length - 1;
                        return;
                    }
                }
            },
            extendedMappings: [
                function (code) {
                    if (97 <= code && code <= 122) {
                        var that = this;
                        return [
                            that.characterMap[that.shiftCharacters[0]],
                            that.characterMap[String.fromCharCode(code - 32)]
                        ];
                    }
                },
                function (code) {
                    if (33 <= code && code <= 58) {
                        var that = this;
                        return [
                            that.characterMap[that.shiftCharacters[1]],
                            that.characterMap[String.fromCharCode(code + 32)]
                        ];
                    }
                },
                function (code) {
                    if (1 <= code && code <= 26) {
                        var that = this;
                        return [
                            that.characterMap[that.shiftCharacters[2]],
                            that.characterMap[String.fromCharCode(code + 64)]
                        ];
                    }
                },
                function (code) {
                    var that = this, result, dataCharacter;
                    if (!that.specialAsciiCodes[code]) {
                        dataCharacter = Math.floor(code / 32) * 6 + (code - 27) % 32 + 64;
                        result = [
                            that.characterMap[that.shiftCharacters[3]],
                            that.characterMap[String.fromCharCode(dataCharacter)]
                        ];
                    } else {
                        result = [];
                        for (var i = 0; i < that.specialAsciiCodes[code].length; i++) {
                            result.push(that.characterMap[that.shiftCharacters[3]]);
                            result.push(that.characterMap[that.specialAsciiCodes[code][i]]);
                        }
                    }
                    return result;
                }
            ],
            specialAsciiCodes: {
                '0': ['U'],
                '64': ['V'],
                '96': ['W'],
                '127': [
                    'T',
                    'X',
                    'Y',
                    'Z'
                ]
            },
            shiftValuesAsciiCodes: {
                '39': 36,
                '40': 47,
                '41': 43,
                '42': 37
            },
            characterMap: {
                '+': false,
                '/': false,
                '$': false,
                '%': false
            },
            shiftCharacters: [
                'SHIFT0',
                'SHIFT1',
                'SHIFT2',
                'SHIFT3'
            ]
        };
        encodings.code39 = code39Base.extend({
            name: 'Code 39',
            checkSumMod: 43,
            minRatio: 2.5,
            maxRatio: 3,
            gapWidth: 1,
            splitCharacter: '|',
            initValue: function (value, width, height) {
                var that = this;
                that.width = width;
                that.height = height;
                that.value = value;
                that.dataLength = value.length;
                that.pattern = [];
                that.patternString = '';
            },
            prepareValues: function () {
                var that = this, baseUnit, minBaseUnit = that.minBaseUnitLength, ratio = that.maxRatio, minRatio = that.minRatio, minHeight = Math.max(0.15 * that.width, 24);
                if (that.height < minHeight) {
                    throw new Error('Insufficient Height. The minimum height for value: ' + that.value + ' is: ' + minHeight);
                }
                while ((baseUnit = that.getBaseUnit(ratio)) < minBaseUnit && ratio > minRatio) {
                    ratio = parseFloat((ratio - 0.1).toFixed(1));
                }
                if (baseUnit < minBaseUnit) {
                    var minWidth = Math.ceil(that.getBaseWidth(minRatio) * minBaseUnit);
                    throw new Error('Insufficient width. The minimum width for value: ' + that.value + ' is: ' + minWidth);
                }
                that.ratio = ratio;
                that.baseUnit = baseUnit;
                that.patternString = that.patternString.substring(0, that.patternString.length - 1);
                that.pattern = that.pattern.concat(that.patternString.replace(/ratio/g, ratio).split(that.splitCharacter));
            },
            getBaseUnit: function (ratio) {
                return this.width / this.getBaseWidth(ratio);
            },
            getBaseWidth: function (ratio) {
                var that = this, characterLength = 3 * (ratio + 2);
                return that.quietZoneLength + characterLength * (that.dataLength + 2) + that.gapWidth * (that.dataLength + 1);
            },
            addStart: function () {
                var that = this;
                that.addPattern(that.characterMap.START.pattern);
                that.addCharacterGap();
            },
            addBase: function (character) {
                this.addPattern(character.pattern);
                this.addCharacterGap();
            },
            addStop: function () {
                this.addPattern(this.characterMap.START.pattern);
            },
            addPattern: function (pattern) {
                for (var i = 0; i < pattern.length; i++) {
                    this.patternString += this.patternMappings[pattern.charAt(i)];
                }
            },
            addCharacterGap: function () {
                var that = this;
                that.patternString += that.gapWidth + that.splitCharacter;
            },
            patternMappings: {
                'b': '1|',
                'w': '1|',
                'B': 'ratio|',
                'W': 'ratio|'
            },
            characterMap: {
                '0': {
                    'pattern': 'bwbWBwBwb',
                    'value': 0
                },
                '1': {
                    'pattern': 'BwbWbwbwB',
                    'value': 1
                },
                '2': {
                    'pattern': 'bwBWbwbwB',
                    'value': 2
                },
                '3': {
                    'pattern': 'BwBWbwbwb',
                    'value': 3
                },
                '4': {
                    'pattern': 'bwbWBwbwB',
                    'value': 4
                },
                '5': {
                    'pattern': 'BwbWBwbwb',
                    'value': 5
                },
                '6': {
                    'pattern': 'bwBWBwbwb',
                    'value': 6
                },
                '7': {
                    'pattern': 'bwbWbwBwB',
                    'value': 7
                },
                '8': {
                    'pattern': 'BwbWbwBwb',
                    'value': 8
                },
                '9': {
                    'pattern': 'bwBWbwBwb',
                    'value': 9
                },
                'A': {
                    'pattern': 'BwbwbWbwB',
                    'value': 10
                },
                'B': {
                    'pattern': 'bwBwbWbwB',
                    'value': 11
                },
                'C': {
                    'pattern': 'BwBwbWbwb',
                    'value': 12
                },
                'D': {
                    'pattern': 'bwbwBWbwB',
                    'value': 13
                },
                'E': {
                    'pattern': 'BwbwBWbwb',
                    'value': 14
                },
                'F': {
                    'pattern': 'bwBwBWbwb',
                    'value': 15
                },
                'G': {
                    'pattern': 'bwbwbWBwB',
                    'value': 16
                },
                'H': {
                    'pattern': 'BwbwbWBwb',
                    'value': 17
                },
                'I': {
                    'pattern': 'bwBwbWBwb',
                    'value': 18
                },
                'J': {
                    'pattern': 'bwbwBWBwb',
                    'value': 19
                },
                'K': {
                    'pattern': 'BwbwbwbWB',
                    'value': 20
                },
                'L': {
                    'pattern': 'bwBwbwbWB',
                    'value': 21
                },
                'M': {
                    'pattern': 'BwBwbwbWb',
                    'value': 22
                },
                'N': {
                    'pattern': 'bwbwBwbWB',
                    'value': 23
                },
                'O': {
                    'pattern': 'BwbwBwbWb',
                    'value': 24
                },
                'P': {
                    'pattern': 'bwBwBwbWb',
                    'value': 25
                },
                'Q': {
                    'pattern': 'bwbwbwBWB',
                    'value': 26
                },
                'R': {
                    'pattern': 'BwbwbwBWb',
                    'value': 27
                },
                'S': {
                    'pattern': 'bwBwbwBWb',
                    'value': 28
                },
                'T': {
                    'pattern': 'bwbwBwBWb',
                    'value': 29
                },
                'U': {
                    'pattern': 'BWbwbwbwB',
                    'value': 30
                },
                'V': {
                    'pattern': 'bWBwbwbwB',
                    'value': 31
                },
                'W': {
                    'pattern': 'BWBwbwbwb',
                    'value': 32
                },
                'X': {
                    'pattern': 'bWbwBwbwB',
                    'value': 33
                },
                'Y': {
                    'pattern': 'BWbwBwbwb',
                    'value': 34
                },
                'Z': {
                    'pattern': 'bWBwBwbwb',
                    'value': 35
                },
                '-': {
                    'pattern': 'bWbwbwBwB',
                    'value': 36
                },
                '.': {
                    'pattern': 'BWbwbwBwb',
                    'value': 37
                },
                ' ': {
                    'pattern': 'bWBwbwBwb',
                    'value': 38
                },
                '$': {
                    'pattern': 'bWbWbWbwb',
                    'value': 39
                },
                '/': {
                    'pattern': 'bWbWbwbWb',
                    'value': 40
                },
                '+': {
                    'pattern': 'bWbwbWbWb',
                    'value': 41
                },
                '%': {
                    'pattern': 'bwbWbWbWb',
                    'value': 42
                },
                START: { pattern: 'bWbwBwBwb' }
            },
            options: { addCheckSum: false }
        });
        encodings.code39extended = encodings.code39.extend(deepExtend({}, code39ExtendedBase, {
            name: 'Code 39 extended',
            characterMap: {
                SHIFT0: {
                    'pattern': 'bWbwbWbWb',
                    'value': 41
                },
                SHIFT1: {
                    'pattern': 'bWbWbwbWb',
                    'value': 40
                },
                SHIFT2: {
                    'pattern': 'bWbWbWbwb',
                    'value': 39
                },
                SHIFT3: {
                    'pattern': 'bwbWbWbWb',
                    'value': 42
                }
            }
        }));
        encodings.code93 = code39Base.extend({
            name: 'Code 93',
            cCheckSumTotal: 20,
            kCheckSumTotal: 15,
            checkSumMod: 47,
            initValue: function (value, width, height) {
                var that = this;
                that.value = value;
                that.width = width;
                that.height = height;
                that.pattern = [];
                that.values = [];
                that.dataLength = value.length;
            },
            prepareValues: function () {
                var that = this, minHeight = Math.max(0.15 * that.width, 24);
                if (that.height < minHeight) {
                    throw new Error('Insufficient Height');
                }
                that.setBaseUnit();
                if (that.baseUnit < that.minBaseUnitLength) {
                    throw new Error('Insufficient Width');
                }
            },
            setBaseUnit: function () {
                var that = this, checkSumLength = 2;
                that.baseUnit = that.width / (9 * (that.dataLength + 2 + checkSumLength) + that.quietZoneLength + 1);
            },
            addStart: function () {
                var pattern = this.characterMap.START.pattern;
                this.addPattern(pattern);
            },
            addStop: function () {
                var that = this;
                that.addStart();
                that.pattern.push(that.characterMap.TERMINATION_BAR);
            },
            addBase: function (charData) {
                this.addPattern(charData.pattern);
                this.values.push(charData.value);
            },
            pushCheckSum: function () {
                var that = this, checkValues = that._getCheckValues(), charData;
                that.checksum = checkValues.join('');
                for (var i = 0; i < checkValues.length; i++) {
                    charData = that.characterMap[that._findCharacterByValue(checkValues[i])];
                    that.addPattern(charData.pattern);
                }
            },
            _getCheckValues: function () {
                var that = this, values = that.values, length = values.length, wightedSum = 0, cValue, kValue, idx;
                for (idx = length - 1; idx >= 0; idx--) {
                    wightedSum += that.weightedValue(values[idx], length - idx, that.cCheckSumTotal);
                }
                cValue = wightedSum % that.checkSumMod;
                wightedSum = that.weightedValue(cValue, 1, that.kCheckSumTotal);
                for (idx = length - 1; idx >= 0; idx--) {
                    wightedSum += that.weightedValue(values[idx], length - idx + 1, that.kCheckSumTotal);
                }
                kValue = wightedSum % that.checkSumMod;
                return [
                    cValue,
                    kValue
                ];
            },
            _findCharacterByValue: function (value) {
                for (var character in this.characterMap) {
                    if (this.characterMap[character].value === value) {
                        return character;
                    }
                }
            },
            weightedValue: function (value, index, total) {
                return (index % total || total) * value;
            },
            addPattern: function (pattern) {
                var value;
                for (var i = 0; i < pattern.length; i++) {
                    value = parseInt(pattern.charAt(i), 10);
                    this.pattern.push(value);
                }
            },
            characterMap: {
                '0': {
                    'pattern': '131112',
                    'value': 0
                },
                '1': {
                    'pattern': '111213',
                    'value': 1
                },
                '2': {
                    'pattern': '111312',
                    'value': 2
                },
                '3': {
                    'pattern': '111411',
                    'value': 3
                },
                '4': {
                    'pattern': '121113',
                    'value': 4
                },
                '5': {
                    'pattern': '121212',
                    'value': 5
                },
                '6': {
                    'pattern': '121311',
                    'value': 6
                },
                '7': {
                    'pattern': '111114',
                    'value': 7
                },
                '8': {
                    'pattern': '131211',
                    'value': 8
                },
                '9': {
                    'pattern': '141111',
                    'value': 9
                },
                'A': {
                    'pattern': '211113',
                    'value': 10
                },
                'B': {
                    'pattern': '211212',
                    'value': 11
                },
                'C': {
                    'pattern': '211311',
                    'value': 12
                },
                'D': {
                    'pattern': '221112',
                    'value': 13
                },
                'E': {
                    'pattern': '221211',
                    'value': 14
                },
                'F': {
                    'pattern': '231111',
                    'value': 15
                },
                'G': {
                    'pattern': '112113',
                    'value': 16
                },
                'H': {
                    'pattern': '112212',
                    'value': 17
                },
                'I': {
                    'pattern': '112311',
                    'value': 18
                },
                'J': {
                    'pattern': '122112',
                    'value': 19
                },
                'K': {
                    'pattern': '132111',
                    'value': 20
                },
                'L': {
                    'pattern': '111123',
                    'value': 21
                },
                'M': {
                    'pattern': '111222',
                    'value': 22
                },
                'N': {
                    'pattern': '111321',
                    'value': 23
                },
                'O': {
                    'pattern': '121122',
                    'value': 24
                },
                'P': {
                    'pattern': '131121',
                    'value': 25
                },
                'Q': {
                    'pattern': '212112',
                    'value': 26
                },
                'R': {
                    'pattern': '212211',
                    'value': 27
                },
                'S': {
                    'pattern': '211122',
                    'value': 28
                },
                'T': {
                    'pattern': '211221',
                    'value': 29
                },
                'U': {
                    'pattern': '221121',
                    'value': 30
                },
                'V': {
                    'pattern': '222111',
                    'value': 31
                },
                'W': {
                    'pattern': '112122',
                    'value': 32
                },
                'X': {
                    'pattern': '112221',
                    'value': 33
                },
                'Y': {
                    'pattern': '122121',
                    'value': 34
                },
                'Z': {
                    'pattern': '123111',
                    'value': 35
                },
                '-': {
                    'pattern': '121131',
                    'value': 36
                },
                '.': {
                    'pattern': '311112',
                    'value': 37
                },
                ' ': {
                    'pattern': '311211',
                    'value': 38
                },
                '$': {
                    'pattern': '321111',
                    'value': 39
                },
                '/': {
                    'pattern': '112131',
                    'value': 40
                },
                '+': {
                    'pattern': '113121',
                    'value': 41
                },
                '%': {
                    'pattern': '211131',
                    'value': 42
                },
                SHIFT0: {
                    'pattern': '122211',
                    'value': 46
                },
                SHIFT1: {
                    'pattern': '311121',
                    'value': 45
                },
                SHIFT2: {
                    'pattern': '121221',
                    'value': 43
                },
                SHIFT3: {
                    'pattern': '312111',
                    'value': 44
                },
                START: { 'pattern': '111141' },
                TERMINATION_BAR: '1'
            }
        });
        encodings.code93extended = encodings.code93.extend(deepExtend({}, code39ExtendedBase, {
            name: 'Code 93 extended',
            pushCheckSum: function () {
                var that = this, checkValues = that._getCheckValues(), value;
                that.checksum = checkValues.join('');
                for (var i = 0; i < checkValues.length; i++) {
                    value = checkValues[i];
                    if (that.shiftValuesAsciiCodes[value]) {
                        that.addExtended(that.shiftValuesAsciiCodes[value]);
                    } else {
                        that.addPattern(that.characterMap[that._findCharacterByValue(value)].pattern);
                    }
                }
            }
        }));
        var state128 = kendo.Class.extend({
            init: function (encoding) {
                this.encoding = encoding;
            },
            addStart: function () {
            },
            is: function () {
            },
            move: function () {
            },
            pushState: function () {
            }
        });
        var state128AB = state128.extend({
            FNC4: 'FNC4',
            init: function (encoding, states) {
                var that = this;
                that.encoding = encoding;
                that.states = states;
                that._initMoves(states);
            },
            addStart: function () {
                this.encoding.addPattern(this.START);
            },
            is: function (value, index) {
                var code = value.charCodeAt(index);
                return this.isCode(code);
            },
            move: function (encodingState) {
                var that = this, idx = 0;
                while (!that._moves[idx].call(that, encodingState) && idx < that._moves.length) {
                    idx++;
                }
            },
            pushState: function (encodingState) {
                var that = this, states = that.states, value = encodingState.value, maxLength = value.length, code;
                if (inArray('C', states) >= 0) {
                    var numberMatch = value.substr(encodingState.index).match(/\d{4,}/g);
                    if (numberMatch) {
                        maxLength = value.indexOf(numberMatch[0], encodingState.index);
                    }
                }
                while ((code = encodingState.value.charCodeAt(encodingState.index)) >= 0 && that.isCode(code) && encodingState.index < maxLength) {
                    that.encoding.addPattern(that.getValue(code));
                    encodingState.index++;
                }
            },
            _initMoves: function (states) {
                var that = this;
                that._moves = [];
                if (inArray(that.FNC4, states) >= 0) {
                    that._moves.push(that._moveFNC);
                }
                if (inArray(that.shiftKey, states) >= 0) {
                    that._moves.push(that._shiftState);
                }
                that._moves.push(that._moveState);
            },
            _moveFNC: function (encodingState) {
                if (encodingState.fnc) {
                    encodingState.fnc = false;
                    return encodingState.previousState == this.key;
                }
            },
            _shiftState: function (encodingState) {
                var that = this;
                if (encodingState.previousState == that.shiftKey && (encodingState.index + 1 >= encodingState.value.length || that.encoding[that.shiftKey].is(encodingState.value, encodingState.index + 1))) {
                    that.encoding.addPattern(that.SHIFT);
                    encodingState.shifted = true;
                    return true;
                }
            },
            _moveState: function () {
                this.encoding.addPattern(this.MOVE);
                return true;
            },
            SHIFT: 98
        });
        var states128 = {};
        states128.A = state128AB.extend({
            key: 'A',
            shiftKey: 'B',
            isCode: function (code) {
                return 0 <= code && code < 96;
            },
            getValue: function (code) {
                if (code < 32) {
                    return code + 64;
                }
                return code - 32;
            },
            MOVE: 101,
            START: 103
        });
        states128.B = state128AB.extend({
            key: 'B',
            shiftKey: 'A',
            isCode: function (code) {
                return 32 <= code && code < 128;
            },
            getValue: function (code) {
                return code - 32;
            },
            MOVE: 100,
            START: 104
        });
        states128.C = state128.extend({
            key: 'C',
            addStart: function () {
                this.encoding.addPattern(this.START);
            },
            is: function (value, index) {
                var next4 = getNext(value, index, 4);
                return (index + 4 <= value.length || value.length == 2) && numberRegex.test(next4);
            },
            move: function () {
                this.encoding.addPattern(this.MOVE);
            },
            pushState: function (encodingState) {
                var code;
                while ((code = getNext(encodingState.value, encodingState.index, 2)) && numberRegex.test(code) && code.length == 2) {
                    this.encoding.addPattern(parseInt(code, 10));
                    encodingState.index += 2;
                }
            },
            getValue: function (code) {
                return code;
            },
            MOVE: 99,
            START: 105
        });
        states128.FNC4 = state128.extend({
            key: 'FNC4',
            dependentStates: [
                'A',
                'B'
            ],
            init: function (encoding, states) {
                this.encoding = encoding;
                this._initSubStates(states);
            },
            addStart: function (encodingState) {
                var code = encodingState.value.charCodeAt(0) - 128, subState = this._getSubState(code);
                this.encoding[subState].addStart();
            },
            is: function (value, index) {
                var code = value.charCodeAt(index);
                return this.isCode(code);
            },
            isCode: function (code) {
                return 128 <= code && code < 256;
            },
            pushState: function (encodingState) {
                var that = this, subState = that._initSubState(encodingState), encoding = that.encoding, length = subState.value.length;
                encodingState.index += length;
                if (length < 3) {
                    var code;
                    for (; subState.index < length; subState.index++) {
                        code = subState.value.charCodeAt(subState.index);
                        subState.state = that._getSubState(code);
                        if (subState.previousState != subState.state) {
                            subState.previousState = subState.state;
                            encoding[subState.state].move(subState);
                        }
                        encoding.addPattern(encoding[subState.state].MOVE);
                        encoding.addPattern(encoding[subState.state].getValue(code));
                    }
                } else {
                    if (subState.state != subState.previousState) {
                        encoding[subState.state].move(subState);
                    }
                    that._pushStart(subState);
                    encoding.pushData(subState, that.subStates);
                    if (encodingState.index < encodingState.value.length) {
                        that._pushStart(subState);
                    }
                }
                encodingState.fnc = true;
                encodingState.state = subState.state;
            },
            _pushStart: function (subState) {
                var that = this;
                that.encoding.addPattern(that.encoding[subState.state].MOVE);
                that.encoding.addPattern(that.encoding[subState.state].MOVE);
            },
            _initSubState: function (encodingState) {
                var that = this, subState = {
                        value: that._getAll(encodingState.value, encodingState.index),
                        index: 0
                    };
                subState.state = that._getSubState(subState.value.charCodeAt(0));
                subState.previousState = encodingState.previousState == that.key ? subState.state : encodingState.previousState;
                return subState;
            },
            _initSubStates: function (states) {
                var that = this;
                that.subStates = [];
                for (var i = 0; i < states.length; i++) {
                    if (inArray(states[i], that.dependentStates) >= 0) {
                        that.subStates.push(states[i]);
                    }
                }
            },
            _getSubState: function (code) {
                var that = this;
                for (var i = 0; i < that.subStates.length; i++) {
                    if (that.encoding[that.subStates[i]].isCode(code)) {
                        return that.subStates[i];
                    }
                }
            },
            _getAll: function (value, index) {
                var code, result = '';
                while ((code = value.charCodeAt(index++)) && this.isCode(code)) {
                    result += String.fromCharCode(code - 128);
                }
                return result;
            }
        });
        states128.FNC1 = state128.extend({
            key: 'FNC1',
            startState: 'C',
            dependentStates: [
                'C',
                'B'
            ],
            startAI: '(',
            endAI: ')',
            init: function (encoding, states) {
                this.encoding = encoding;
                this.states = states;
            },
            addStart: function () {
                this.encoding[this.startState].addStart();
            },
            is: function () {
                return inArray(this.key, this.states) >= 0;
            },
            pushState: function (encodingState) {
                var that = this, encoding = that.encoding, value = encodingState.value.replace(/\s/g, ''), regexSeparators = new RegExp('[' + that.startAI + that.endAI + ']', 'g'), index = encodingState.index, subState = { state: that.startState }, current, nextStart, separatorLength;
                encoding.addPattern(that.START);
                while (true) {
                    subState.index = 0;
                    separatorLength = value.charAt(index) === that.startAI ? 2 : 0;
                    current = separatorLength > 0 ? that.getBySeparator(value, index) : that.getByLength(value, index);
                    if (current.ai.length) {
                        nextStart = index + separatorLength + current.id.length + current.ai.length;
                    } else {
                        nextStart = value.indexOf(that.startAI, index + 1);
                        if (nextStart < 0) {
                            if (index + current.ai.max + current.id.length + separatorLength < value.length) {
                                throw new Error('Separators are required after variable length identifiers');
                            }
                            nextStart = value.length;
                        }
                    }
                    subState.value = value.substring(index, nextStart).replace(regexSeparators, '');
                    that.validate(current, subState.value);
                    encoding.pushData(subState, that.dependentStates);
                    if (nextStart >= value.length) {
                        break;
                    }
                    index = nextStart;
                    if (subState.state != that.startState) {
                        encoding[that.startState].move(subState);
                        subState.state = that.startState;
                    }
                    if (!current.ai.length) {
                        encoding.addPattern(that.START);
                    }
                }
                encodingState.index = encodingState.value.length;
            },
            validate: function (current, value) {
                var code = value.substr(current.id.length), ai = current.ai;
                if (!ai.type && !numberRegex.test(code)) {
                    throw new Error('Application identifier ' + current.id + ' is numeric only but contains non numeric character(s).');
                }
                if (ai.type == 'alphanumeric' && !alphanumericRegex.test(code)) {
                    throw new Error('Application identifier ' + current.id + ' is alphanumeric only but contains non alphanumeric character(s).');
                }
                if (ai.length && ai.length !== code.length) {
                    throw new Error('Application identifier ' + current.id + ' must be ' + ai.length + ' characters long.');
                }
                if (ai.min && ai.min > code.length) {
                    throw new Error('Application identifier ' + current.id + ' must be at least ' + ai.min + ' characters long.');
                }
                if (ai.max && ai.max < code.length) {
                    throw new Error('Application identifier ' + current.id + ' must be at most ' + ai.max + ' characters long.');
                }
            },
            getByLength: function (value, index) {
                var that = this, id, ai;
                for (var i = 2; i <= 4; i++) {
                    id = getNext(value, index, i);
                    ai = that.getAI(id) || that.getAI(id.substring(0, id.length - 1));
                    if (ai) {
                        return {
                            id: id,
                            ai: ai
                        };
                    }
                }
                that.unsupportedAIError(id);
            },
            unsupportedAIError: function (id) {
                throw new Error(kendo.format('\'{0}\' is not a supported Application Identifier'), id);
            },
            getBySeparator: function (value, index) {
                var that = this, start = value.indexOf(that.startAI, index), end = value.indexOf(that.endAI, start), id = value.substring(start + 1, end), ai = that.getAI(id) || that.getAI(id.substr(id.length - 1));
                if (!ai) {
                    that.unsupportedAIError(id);
                }
                return {
                    ai: ai,
                    id: id
                };
            },
            getAI: function (id) {
                var ai = this.applicationIdentifiers, multiKey = ai.multiKey;
                if (ai[id]) {
                    return ai[id];
                }
                for (var i = 0; i < multiKey.length; i++) {
                    if (multiKey[i].ids && inArray(id, multiKey[i].ids) >= 0) {
                        return multiKey[i].type;
                    } else if (multiKey[i].ranges) {
                        var ranges = multiKey[i].ranges;
                        for (var j = 0; j < ranges.length; j++) {
                            if (ranges[j][0] <= id && id <= ranges[j][1]) {
                                return multiKey[i].type;
                            }
                        }
                    }
                }
            },
            applicationIdentifiers: {
                '22': {
                    max: 29,
                    type: 'alphanumeric'
                },
                '402': { length: 17 },
                '7004': {
                    max: 4,
                    type: 'alphanumeric'
                },
                '242': {
                    max: 6,
                    type: 'alphanumeric'
                },
                '8020': {
                    max: 25,
                    type: 'alphanumeric'
                },
                '703': {
                    min: 3,
                    max: 30,
                    type: 'alphanumeric'
                },
                '8008': {
                    min: 8,
                    max: 12,
                    type: 'alphanumeric'
                },
                '253': {
                    min: 13,
                    max: 17,
                    type: 'alphanumeric'
                },
                '8003': {
                    min: 14,
                    max: 30,
                    type: 'alphanumeric'
                },
                multiKey: [
                    {
                        ids: [
                            '15',
                            '17',
                            '8005',
                            '8100'
                        ],
                        ranges: [
                            [
                                11,
                                13
                            ],
                            [
                                310,
                                316
                            ],
                            [
                                320,
                                336
                            ],
                            [
                                340,
                                369
                            ]
                        ],
                        type: { length: 6 }
                    },
                    {
                        ids: [
                            '240',
                            '241',
                            '250',
                            '251',
                            '400',
                            '401',
                            '403',
                            '7002',
                            '8004',
                            '8007',
                            '8110'
                        ],
                        ranges: [[90 - 99]],
                        type: {
                            max: 30,
                            type: 'alphanumeric'
                        }
                    },
                    {
                        ids: ['7001'],
                        ranges: [[
                                410,
                                414
                            ]],
                        type: { length: 13 }
                    },
                    {
                        ids: [
                            '10',
                            '21',
                            '254',
                            '420',
                            '8002'
                        ],
                        type: {
                            max: 20,
                            type: 'alphanumeric'
                        }
                    },
                    {
                        ids: [
                            '00',
                            '8006',
                            '8017',
                            '8018'
                        ],
                        type: { length: 18 }
                    },
                    {
                        ids: [
                            '01',
                            '02',
                            '8001'
                        ],
                        type: { length: 14 }
                    },
                    {
                        ids: ['422'],
                        ranges: [[
                                424,
                                426
                            ]],
                        type: { length: 3 }
                    },
                    {
                        ids: [
                            '20',
                            '8102'
                        ],
                        type: { length: 2 }
                    },
                    {
                        ids: [
                            '30',
                            '37'
                        ],
                        type: {
                            max: 8,
                            type: 'alphanumeric'
                        }
                    },
                    {
                        ids: [
                            '390',
                            '392'
                        ],
                        type: {
                            max: 15,
                            type: 'alphanumeric'
                        }
                    },
                    {
                        ids: [
                            '421',
                            '423'
                        ],
                        type: {
                            min: 3,
                            max: 15,
                            type: 'alphanumeric'
                        }
                    },
                    {
                        ids: [
                            '391',
                            '393'
                        ],
                        type: {
                            min: 3,
                            max: 18,
                            type: 'alphanumeric'
                        }
                    },
                    {
                        ids: [
                            '7003',
                            '8101'
                        ],
                        type: { length: 10 }
                    }
                ]
            },
            START: 102
        });
        var code128Base = Encoding.extend({
            init: function (options) {
                Encoding.fn.init.call(this, options);
                this._initStates();
            },
            _initStates: function () {
                var that = this;
                for (var i = 0; i < that.states.length; i++) {
                    that[that.states[i]] = new states128[that.states[i]](that, that.states);
                }
            },
            initValue: function (value, width, height) {
                var that = this;
                that.pattern = [];
                that.value = value;
                that.width = width;
                that.height = height;
                that.checkSum = 0;
                that.totalUnits = 0;
                that.index = 0;
                that.position = 1;
            },
            addData: function () {
                var that = this, encodingState = {
                        value: that.value,
                        index: 0,
                        state: ''
                    };
                if (that.value.length === 0) {
                    return;
                }
                encodingState.state = encodingState.previousState = that.getNextState(encodingState, that.states);
                that.addStart(encodingState);
                that.pushData(encodingState, that.states);
                that.addCheckSum();
                that.addStop();
                that.setBaseUnit();
            },
            pushData: function (encodingState, states) {
                var that = this;
                while (true) {
                    that[encodingState.state].pushState(encodingState);
                    if (encodingState.index >= encodingState.value.length) {
                        break;
                    }
                    if (!encodingState.shifted) {
                        encodingState.previousState = encodingState.state;
                        encodingState.state = that.getNextState(encodingState, states);
                        that[encodingState.state].move(encodingState);
                    } else {
                        var temp = encodingState.state;
                        encodingState.state = encodingState.previousState;
                        encodingState.previousState = temp;
                        encodingState.shifted = false;
                    }
                }
            },
            addStart: function (encodingState) {
                this[encodingState.state].addStart(encodingState);
                this.position = 1;
            },
            addCheckSum: function () {
                var that = this;
                that.checksum = that.checkSum % 103;
                that.addPattern(that.checksum);
            },
            addStop: function () {
                this.addPattern(this.STOP);
            },
            setBaseUnit: function () {
                var that = this;
                that.baseUnit = that.width / (that.totalUnits + that.quietZoneLength);
            },
            addPattern: function (code) {
                var that = this, pattern = that.characterMap[code].toString(), value;
                for (var i = 0; i < pattern.length; i++) {
                    value = parseInt(pattern.charAt(i), 10);
                    that.pattern.push(value);
                    that.totalUnits += value;
                }
                that.checkSum += code * that.position++;
            },
            getNextState: function (encodingState, states) {
                for (var i = 0; i < states.length; i++) {
                    if (this[states[i]].is(encodingState.value, encodingState.index)) {
                        return states[i];
                    }
                }
                this.invalidCharacterError(encodingState.value.charAt(encodingState.index));
            },
            characterMap: [
                212222,
                222122,
                222221,
                121223,
                121322,
                131222,
                122213,
                122312,
                132212,
                221213,
                221312,
                231212,
                112232,
                122132,
                122231,
                113222,
                123122,
                123221,
                223211,
                221132,
                221231,
                213212,
                223112,
                312131,
                311222,
                321122,
                321221,
                312212,
                322112,
                322211,
                212123,
                212321,
                232121,
                111323,
                131123,
                131321,
                112313,
                132113,
                132311,
                211313,
                231113,
                231311,
                112133,
                112331,
                132131,
                113123,
                113321,
                133121,
                313121,
                211331,
                231131,
                213113,
                213311,
                213131,
                311123,
                311321,
                331121,
                312113,
                312311,
                332111,
                314111,
                221411,
                431111,
                111224,
                111422,
                121124,
                121421,
                141122,
                141221,
                112214,
                112412,
                122114,
                122411,
                142112,
                142211,
                241211,
                221114,
                413111,
                241112,
                134111,
                111242,
                121142,
                121241,
                114212,
                124112,
                124211,
                411212,
                421112,
                421211,
                212141,
                214121,
                412121,
                111143,
                111341,
                131141,
                114113,
                114311,
                411113,
                411311,
                113141,
                114131,
                311141,
                411131,
                211412,
                211214,
                211232,
                2331112
            ],
            STOP: 106
        });
        encodings.code128a = code128Base.extend({
            name: 'Code 128 A',
            states: ['A']
        });
        encodings.code128b = code128Base.extend({
            name: 'Code 128 B',
            states: ['B']
        });
        encodings.code128c = code128Base.extend({
            name: 'Code 128 C',
            states: ['C']
        });
        encodings.code128 = code128Base.extend({
            name: 'Code 128',
            states: [
                'C',
                'B',
                'A',
                'FNC4'
            ]
        });
        encodings['gs1-128'] = code128Base.extend({
            name: 'Code GS1-128',
            states: [
                'FNC1',
                'C',
                'B'
            ]
        });
        var msiBase = Encoding.extend({
            initValue: function (value, width) {
                var that = this;
                that.pattern = [];
                that.value = value;
                that.checkSumLength = 0;
                that.width = width;
            },
            setBaseUnit: function () {
                var that = this, startStopLength = 7;
                that.baseUnit = that.width / (12 * (that.value.length + that.checkSumLength) + that.quietZoneLength + startStopLength);
            },
            addData: function () {
                var that = this, value = that.value;
                that.addPattern(that.START);
                for (var i = 0; i < value.length; i++) {
                    that.addCharacter(value.charAt(i));
                }
                if (that.options.addCheckSum) {
                    that.addCheckSum();
                }
                that.addPattern(that.STOP);
                that.setBaseUnit();
            },
            addCharacter: function (character) {
                var that = this, pattern = that.characterMap[character];
                if (!pattern) {
                    that.invalidCharacterError(character);
                }
                that.addPattern(pattern);
            },
            addPattern: function (pattern) {
                for (var i = 0; i < pattern.length; i++) {
                    this.pattern.push(parseInt(pattern.charAt(i), 10));
                }
            },
            addCheckSum: function () {
                var that = this, checkSumFunction = that.checkSums[that.checkSumType], checkValues;
                checkValues = checkSumFunction.call(that.checkSums, that.value);
                that.checksum = checkValues.join('');
                for (var i = 0; i < checkValues.length; i++) {
                    that.checkSumLength++;
                    that.addPattern(that.characterMap[checkValues[i]]);
                }
            },
            checkSums: {
                Modulo10: function (value) {
                    var checkValues = [
                            0,
                            ''
                        ], odd = value.length % 2, idx, evenSum, oddSum;
                    for (idx = 0; idx < value.length; idx++) {
                        checkValues[(idx + odd) % 2] += parseInt(value.charAt(idx), 10);
                    }
                    oddSum = checkValues[0];
                    evenSum = (checkValues[1] * 2).toString();
                    for (idx = 0; idx < evenSum.length; idx++) {
                        oddSum += parseInt(evenSum.charAt(idx), 10);
                    }
                    return [(10 - oddSum % 10) % 10];
                },
                Modulo11: function (value) {
                    var weightedSum = 0, mod = 11, length = value.length, weight, checkValue;
                    for (var i = 0; i < length; i++) {
                        weight = ((length - i) % 6 || 6) + 1;
                        weightedSum += weight * value.charAt(i);
                    }
                    checkValue = (mod - weightedSum % mod) % mod;
                    if (checkValue != 10) {
                        return [checkValue];
                    }
                    return [
                        1,
                        0
                    ];
                },
                Modulo11Modulo10: function (value) {
                    var checkValues = this.Modulo11(value), mod11Value;
                    mod11Value = value + checkValues[0];
                    return checkValues.concat(this.Modulo10(mod11Value));
                },
                Modulo10Modulo10: function (value) {
                    var checkValues = this.Modulo10(value), mod10Value;
                    mod10Value = value + checkValues[0];
                    return checkValues.concat(this.Modulo10(mod10Value));
                }
            },
            characterMap: [
                '12121212',
                '12121221',
                '12122112',
                '12122121',
                '12211212',
                '12211221',
                '12212112',
                '12212121',
                '21121212',
                '21121221'
            ],
            START: '21',
            STOP: '121',
            checkSumType: ''
        });
        encodings.msimod10 = msiBase.extend({
            name: 'MSI Modulo10',
            checkSumType: 'Modulo10'
        });
        encodings.msimod11 = msiBase.extend({
            name: 'MSI Modulo11',
            checkSumType: 'Modulo11'
        });
        encodings.msimod1110 = msiBase.extend({
            name: 'MSI Modulo11 Modulo10',
            checkSumType: 'Modulo11Modulo10'
        });
        encodings.msimod1010 = msiBase.extend({
            name: 'MSI Modulo10 Modulo10',
            checkSumType: 'Modulo10Modulo10'
        });
        encodings.code11 = Encoding.extend({
            name: 'Code 11',
            cCheckSumTotal: 10,
            kCheckSumTotal: 9,
            kCheckSumMinLength: 10,
            checkSumMod: 11,
            DASH_VALUE: 10,
            DASH: '-',
            START: '112211',
            STOP: '11221',
            initValue: function (value, width) {
                var that = this;
                that.pattern = [];
                that.value = value;
                that.width = width;
                that.totalUnits = 0;
            },
            addData: function () {
                var that = this;
                var value = that.value;
                that.addPattern(that.START);
                for (var i = 0; i < value.length; i++) {
                    that.addCharacter(value.charAt(i));
                }
                if (that.options.addCheckSum) {
                    that.addCheckSum();
                }
                that.addPattern(that.STOP);
                that.setBaseUnit();
            },
            setBaseUnit: function () {
                var that = this;
                that.baseUnit = that.width / (that.totalUnits + that.quietZoneLength);
            },
            addCheckSum: function () {
                var that = this, value = that.value, length = value.length, cValue;
                cValue = that.getWeightedSum(value, length, that.cCheckSumTotal) % that.checkSumMod;
                that.checksum = cValue + '';
                that.addPattern(that.characterMap[cValue]);
                length++;
                if (length >= that.kCheckSumMinLength) {
                    var kValue = (cValue + that.getWeightedSum(value, length, that.kCheckSumTotal)) % that.checkSumMod;
                    that.checksum += kValue;
                    that.addPattern(that.characterMap[kValue]);
                }
            },
            getWeightedSum: function (value, length, total) {
                var weightedSum = 0;
                for (var i = 0; i < value.length; i++) {
                    weightedSum += this.weightedValue(this.getValue(value.charAt(i)), length, i, total);
                }
                return weightedSum;
            },
            weightedValue: function (value, length, index, total) {
                var weight = (length - index) % total || total;
                return weight * value;
            },
            getValue: function (character) {
                var that = this;
                if (!isNaN(character)) {
                    return parseInt(character, 10);
                } else if (character !== that.DASH) {
                    that.invalidCharacterError(character);
                }
                return that.DASH_VALUE;
            },
            addCharacter: function (character) {
                var that = this, value = that.getValue(character), pattern = that.characterMap[value];
                that.addPattern(pattern);
            },
            addPattern: function (pattern) {
                var value;
                for (var i = 0; i < pattern.length; i++) {
                    value = parseInt(pattern.charAt(i), 10);
                    this.pattern.push(value);
                    this.totalUnits += value;
                }
            },
            characterMap: [
                '111121',
                '211121',
                '121121',
                '221111',
                '112121',
                '212111',
                '122111',
                '111221',
                '211211',
                '211111',
                '112111'
            ],
            options: { addCheckSum: true }
        });
        encodings.postnet = Encoding.extend({
            name: 'Postnet',
            START: '2',
            VALID_CODE_LENGTHS: [
                5,
                9,
                11
            ],
            DIGIT_SEPARATOR: '-',
            initValue: function (value, width, height) {
                var that = this;
                that.height = height;
                that.width = width;
                that.baseHeight = height / 2;
                that.value = value.replace(new RegExp(that.DIGIT_SEPARATOR, 'g'), '');
                that.pattern = [];
                that.validate(that.value);
                that.checkSum = 0;
                that.setBaseUnit();
            },
            addData: function () {
                var that = this, value = that.value;
                that.addPattern(that.START);
                for (var i = 0; i < value.length; i++) {
                    that.addCharacter(value.charAt(i));
                }
                if (that.options.addCheckSum) {
                    that.addCheckSum();
                }
                that.addPattern(that.START);
                that.pattern.pop();
            },
            addCharacter: function (character) {
                var that = this, pattern = that.characterMap[character];
                that.checkSum += parseInt(character, 10);
                that.addPattern(pattern);
            },
            addCheckSum: function () {
                var that = this;
                that.checksum = (10 - that.checkSum % 10) % 10;
                that.addCharacter(that.checksum);
            },
            setBaseUnit: function () {
                var that = this, startStopLength = 3;
                that.baseUnit = that.width / ((that.value.length + 1) * 10 + startStopLength + that.quietZoneLength);
            },
            validate: function (value) {
                var that = this;
                if (!numberRegex.test(value)) {
                    that.invalidCharacterError(value.match(/[^0-9]/)[0]);
                }
                if (inArray(value.length, that.VALID_CODE_LENGTHS) < 0) {
                    throw new Error('Invalid value length. Valid lengths for the Postnet symbology are ' + that.VALID_CODE_LENGTHS.join(','));
                }
            },
            addPattern: function (pattern) {
                var that = this, y1;
                for (var i = 0; i < pattern.length; i++) {
                    y1 = that.height - that.baseHeight * pattern.charAt(i);
                    that.pattern.push({
                        width: 1,
                        y1: y1,
                        y2: that.height
                    });
                    that.pattern.push(1);
                }
            },
            characterMap: [
                '22111',
                '11122',
                '11212',
                '11221',
                '12112',
                '12121',
                '12211',
                '21112',
                '21121',
                '21211'
            ]
        });
        encodings.ean13 = Encoding.extend({
            initValue: function (value, width, height) {
                value += '';
                if (value.length != 12 || /\D/.test(value)) {
                    throw new Error('The value of the "EAN13" encoding should be 12 symbols');
                }
                var that = this;
                that.pattern = [];
                that.options.height = height;
                that.baseUnit = width / (95 + that.quietZoneLength);
                that.value = value;
                that.checksum = that.calculateChecksum();
                that.leftKey = value[0];
                that.leftPart = value.substr(1, 6);
                that.rightPart = value.substr(7) + that.checksum;
            },
            addData: function () {
                var that = this;
                that.addPieces(that.characterMap.start);
                that.addSide(that.leftPart, that.leftKey);
                that.addPieces(that.characterMap.middle);
                that.addSide(that.rightPart);
                that.addPieces(that.characterMap.start);
            },
            addSide: function (leftPart, key) {
                var that = this;
                for (var i = 0; i < leftPart.length; i++) {
                    if (key && parseInt(that.keyTable[key].charAt(i), 10)) {
                        that.addPieces(Array.prototype.slice.call(that.characterMap.digits[leftPart.charAt(i)]).reverse(), true);
                    } else {
                        that.addPieces(that.characterMap.digits[leftPart.charAt(i)], true);
                    }
                }
            },
            addPieces: function (arrToAdd, limitedHeight) {
                var that = this;
                for (var i = 0; i < arrToAdd.length; i++) {
                    if (limitedHeight) {
                        that.pattern.push({
                            y1: 0,
                            y2: that.options.height * 0.95,
                            width: arrToAdd[i]
                        });
                    } else {
                        that.pattern.push(arrToAdd[i]);
                    }
                }
            },
            calculateChecksum: function () {
                var odd = 0, even = 0, value = this.value.split('').reverse().join('');
                for (var i = 0; i < value.length; i++) {
                    if (i % 2) {
                        even += parseInt(value.charAt(i), 10);
                    } else {
                        odd += parseInt(value.charAt(i), 10);
                    }
                }
                var checksum = (10 - (3 * odd + even) % 10) % 10;
                return checksum;
            },
            keyTable: [
                '000000',
                '001011',
                '001101',
                '001110',
                '010011',
                '011001',
                '011100',
                '010101',
                '010110',
                '011010'
            ],
            characterMap: {
                digits: [
                    [
                        3,
                        2,
                        1,
                        1
                    ],
                    [
                        2,
                        2,
                        2,
                        1
                    ],
                    [
                        2,
                        1,
                        2,
                        2
                    ],
                    [
                        1,
                        4,
                        1,
                        1
                    ],
                    [
                        1,
                        1,
                        3,
                        2
                    ],
                    [
                        1,
                        2,
                        3,
                        1
                    ],
                    [
                        1,
                        1,
                        1,
                        4
                    ],
                    [
                        1,
                        3,
                        1,
                        2
                    ],
                    [
                        1,
                        2,
                        1,
                        3
                    ],
                    [
                        3,
                        1,
                        1,
                        2
                    ]
                ],
                start: [
                    1,
                    1,
                    1
                ],
                middle: [
                    1,
                    1,
                    1,
                    1,
                    1
                ]
            }
        });
        encodings.ean8 = encodings.ean13.extend({
            initValue: function (value, width, height) {
                var that = this;
                if (value.length != 7 || /\D/.test(value)) {
                    throw new Error('Invalid value provided');
                }
                that.value = value;
                that.options.height = height;
                that.checksum = that.calculateChecksum(that.value);
                that.leftPart = that.value.substr(0, 4);
                that.rightPart = that.value.substr(4) + that.checksum;
                that.pattern = [];
                that.baseUnit = width / (67 + that.quietZoneLength);
            }
        });
        var Barcode = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.element = $(element);
                that.wrapper = that.element;
                that.element.addClass('k-barcode').css('display', 'block');
                that.surfaceWrap = $('<div />').css('position', 'relative').appendTo(this.element);
                that.surface = draw.Surface.create(that.surfaceWrap, { type: that.options.renderAs });
                that.setOptions(options);
            },
            setOptions: function (options) {
                var that = this;
                that.type = (options.type || that.options.type).toLowerCase();
                if (that.type == 'upca') {
                    that.type = 'ean13';
                    options.value = '0' + options.value;
                }
                if (that.type == 'upce') {
                    that.type = 'ean8';
                    options.value = '0' + options.value;
                }
                if (!encodings[that.type]) {
                    throw new Error('Encoding ' + that.type + 'is not supported.');
                }
                that.encoding = new encodings[that.type]();
                that.options = extend(true, that.options, options);
                if (!defined(options.value)) {
                    return;
                }
                that.redraw();
            },
            redraw: function () {
                var size = this._getSize();
                this.surface.clear();
                this.surface.setSize({
                    width: size.width,
                    height: size.height
                });
                this.createVisual();
                this.surface.draw(this.visual);
            },
            getSize: function () {
                return kendo.dimensions(this.element);
            },
            _resize: function () {
                this.redraw();
            },
            createVisual: function () {
                this.visual = this._render();
            },
            _render: function () {
                var that = this, options = that.options, value = options.value, textOptions = options.text, textMargin = dataviz.getSpacing(textOptions.margin), size = that._getSize(), border = options.border || {}, encoding = that.encoding, contentBox = new Box2D(0, 0, size.width, size.height).unpad(border.width).unpad(options.padding), barHeight = contentBox.height(), result, textToDisplay, textHeight;
                var visual = new draw.Group();
                that.contentBox = contentBox;
                visual.append(that._getBackground(size));
                if (textOptions.visible) {
                    textHeight = draw.util.measureText(value, { font: textOptions.font }).height;
                    barHeight -= textHeight + textMargin.top + textMargin.bottom;
                }
                result = encoding.encode(value, contentBox.width(), barHeight);
                if (textOptions.visible) {
                    textToDisplay = value;
                    if (options.checksum && defined(encoding.checksum)) {
                        textToDisplay += ' ' + encoding.checksum;
                    }
                    visual.append(that._getText(textToDisplay));
                }
                that.barHeight = barHeight;
                this._bandsGroup = this._getBands(result.pattern, result.baseUnit);
                visual.append(this._bandsGroup);
                return visual;
            },
            exportVisual: function () {
                return this._render();
            },
            _getSize: function () {
                var that = this, element = that.element, size = new geom.Size(DEFAULT_WIDTH, DEFAULT_HEIGHT);
                if (element.width() > 0) {
                    size.width = element.width();
                }
                if (element.height() > 0) {
                    size.height = element.height();
                }
                if (that.options.width) {
                    size.width = that.options.width;
                }
                if (that.options.height) {
                    size.height = that.options.height;
                }
                return size;
            },
            value: function (value) {
                var that = this;
                if (!defined(value)) {
                    return that.options.value;
                }
                that.options.value = value + '';
                that.redraw();
            },
            _getBands: function (pattern, baseUnit) {
                var that = this, contentBox = that.contentBox, position = contentBox.x1, step, item;
                var group = new draw.Group();
                for (var i = 0; i < pattern.length; i++) {
                    item = isPlainObject(pattern[i]) ? pattern[i] : {
                        width: pattern[i],
                        y1: 0,
                        y2: that.barHeight
                    };
                    step = item.width * baseUnit;
                    if (i % 2) {
                        var rect = geom.Rect.fromPoints(new geom.Point(position, item.y1 + contentBox.y1), new geom.Point(position + step, item.y2 + contentBox.y1));
                        var path = draw.Path.fromRect(rect, {
                            fill: { color: that.options.color },
                            stroke: null
                        });
                        group.append(path);
                    }
                    position += step;
                }
                return group;
            },
            _getBackground: function (size) {
                var that = this, options = that.options, border = options.border || {};
                var box = new Box2D(0, 0, size.width, size.height).unpad(border.width / 2);
                var path = draw.Path.fromRect(box.toRect(), {
                    fill: { color: options.background },
                    stroke: {
                        color: border.width ? border.color : '',
                        width: border.width,
                        dashType: border.dashType
                    }
                });
                return path;
            },
            _getText: function (value) {
                var that = this, textOptions = that.options.text, text = that._textbox = new TextBox(value, {
                        font: textOptions.font,
                        color: textOptions.color,
                        align: 'center',
                        vAlign: 'bottom',
                        margin: textOptions.margin
                    });
                text.reflow(that.contentBox);
                text.renderVisual();
                return text.visual;
            },
            options: {
                name: 'Barcode',
                renderAs: 'svg',
                value: '',
                type: 'code39',
                checksum: false,
                width: 0,
                height: 0,
                color: 'black',
                background: 'white',
                text: {
                    visible: true,
                    font: '16px Consolas, Monaco, Sans Mono, monospace, sans-serif',
                    color: 'black',
                    margin: {
                        top: 0,
                        bottom: 0,
                        left: 0,
                        right: 0
                    }
                },
                border: {
                    width: 0,
                    dashType: 'solid',
                    color: 'black'
                },
                padding: {
                    top: 0,
                    bottom: 0,
                    left: 0,
                    right: 0
                }
            }
        });
        dataviz.ExportMixin.extend(Barcode.fn);
        dataviz.ui.plugin(Barcode);
        kendo.deepExtend(dataviz, {
            encodings: encodings,
            Encoding: Encoding
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.qrcode', [
        'kendo.dataviz.core',
        'kendo.drawing'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.qrcode',
        name: 'QRCode',
        category: 'dataviz',
        description: 'QRCode widget.',
        depends: [
            'dataviz.core',
            'drawing'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, draw = kendo.drawing, dataviz = kendo.dataviz, Widget = kendo.ui.Widget, Box2D = dataviz.Box2D, terminator = '0000', NUMERIC = 'numeric', ALPHA_NUMERIC = 'alphanumeric', BYTE = 'byte', powersOfTwo = { '1': 0 }, powersOfTwoResult = { '0': 1 }, generatorPolynomials = [
                [
                    1,
                    0
                ],
                [
                    1,
                    25,
                    0
                ]
            ], irregularAlignmentPatternsStartDistance = {
                15: 20,
                16: 20,
                18: 24,
                19: 24,
                22: 20,
                24: 22,
                26: 24,
                28: 20,
                30: 20,
                31: 24,
                32: 28,
                33: 24,
                36: 18,
                37: 22,
                39: 20,
                40: 24
            }, versionsCodewordsInformation = [
                {
                    L: {
                        groups: [[
                                1,
                                19
                            ]],
                        totalDataCodewords: 19,
                        errorCodewordsPerBlock: 7
                    },
                    M: {
                        groups: [[
                                1,
                                16
                            ]],
                        totalDataCodewords: 16,
                        errorCodewordsPerBlock: 10
                    },
                    Q: {
                        groups: [[
                                1,
                                13
                            ]],
                        totalDataCodewords: 13,
                        errorCodewordsPerBlock: 13
                    },
                    H: {
                        groups: [[
                                1,
                                9
                            ]],
                        totalDataCodewords: 9,
                        errorCodewordsPerBlock: 17
                    }
                },
                {
                    L: {
                        groups: [[
                                1,
                                34
                            ]],
                        totalDataCodewords: 34,
                        errorCodewordsPerBlock: 10
                    },
                    M: {
                        groups: [[
                                1,
                                28
                            ]],
                        totalDataCodewords: 28,
                        errorCodewordsPerBlock: 16
                    },
                    Q: {
                        groups: [[
                                1,
                                22
                            ]],
                        totalDataCodewords: 22,
                        errorCodewordsPerBlock: 22
                    },
                    H: {
                        groups: [[
                                1,
                                16
                            ]],
                        totalDataCodewords: 16,
                        errorCodewordsPerBlock: 28
                    }
                },
                {
                    L: {
                        groups: [[
                                1,
                                55
                            ]],
                        totalDataCodewords: 55,
                        errorCodewordsPerBlock: 15
                    },
                    M: {
                        groups: [[
                                1,
                                44
                            ]],
                        totalDataCodewords: 44,
                        errorCodewordsPerBlock: 26
                    },
                    Q: {
                        groups: [[
                                2,
                                17
                            ]],
                        totalDataCodewords: 34,
                        errorCodewordsPerBlock: 18
                    },
                    H: {
                        groups: [[
                                2,
                                13
                            ]],
                        totalDataCodewords: 26,
                        errorCodewordsPerBlock: 22
                    }
                },
                {
                    L: {
                        groups: [[
                                1,
                                80
                            ]],
                        totalDataCodewords: 80,
                        errorCodewordsPerBlock: 20
                    },
                    M: {
                        groups: [[
                                2,
                                32
                            ]],
                        totalDataCodewords: 64,
                        errorCodewordsPerBlock: 18
                    },
                    Q: {
                        groups: [[
                                2,
                                24
                            ]],
                        totalDataCodewords: 48,
                        errorCodewordsPerBlock: 26
                    },
                    H: {
                        groups: [[
                                4,
                                9
                            ]],
                        totalDataCodewords: 36,
                        errorCodewordsPerBlock: 16
                    }
                },
                {
                    L: {
                        groups: [[
                                1,
                                108
                            ]],
                        totalDataCodewords: 108,
                        errorCodewordsPerBlock: 26
                    },
                    M: {
                        groups: [[
                                2,
                                43
                            ]],
                        totalDataCodewords: 86,
                        errorCodewordsPerBlock: 24
                    },
                    Q: {
                        groups: [
                            [
                                2,
                                15
                            ],
                            [
                                2,
                                16
                            ]
                        ],
                        totalDataCodewords: 62,
                        errorCodewordsPerBlock: 18
                    },
                    H: {
                        groups: [
                            [
                                2,
                                11
                            ],
                            [
                                2,
                                12
                            ]
                        ],
                        totalDataCodewords: 46,
                        errorCodewordsPerBlock: 22
                    }
                },
                {
                    L: {
                        groups: [[
                                2,
                                68
                            ]],
                        totalDataCodewords: 136,
                        errorCodewordsPerBlock: 18
                    },
                    M: {
                        groups: [[
                                4,
                                27
                            ]],
                        totalDataCodewords: 108,
                        errorCodewordsPerBlock: 16
                    },
                    Q: {
                        groups: [[
                                4,
                                19
                            ]],
                        totalDataCodewords: 76,
                        errorCodewordsPerBlock: 24
                    },
                    H: {
                        groups: [[
                                4,
                                15
                            ]],
                        totalDataCodewords: 60,
                        errorCodewordsPerBlock: 28
                    }
                },
                {
                    L: {
                        groups: [[
                                2,
                                78
                            ]],
                        totalDataCodewords: 156,
                        errorCodewordsPerBlock: 20
                    },
                    M: {
                        groups: [[
                                4,
                                31
                            ]],
                        totalDataCodewords: 124,
                        errorCodewordsPerBlock: 18
                    },
                    Q: {
                        groups: [
                            [
                                2,
                                14
                            ],
                            [
                                4,
                                15
                            ]
                        ],
                        totalDataCodewords: 88,
                        errorCodewordsPerBlock: 18
                    },
                    H: {
                        groups: [
                            [
                                4,
                                13
                            ],
                            [
                                1,
                                14
                            ]
                        ],
                        totalDataCodewords: 66,
                        errorCodewordsPerBlock: 26
                    }
                },
                {
                    L: {
                        groups: [[
                                2,
                                97
                            ]],
                        totalDataCodewords: 194,
                        errorCodewordsPerBlock: 24
                    },
                    M: {
                        groups: [
                            [
                                2,
                                38
                            ],
                            [
                                2,
                                39
                            ]
                        ],
                        totalDataCodewords: 154,
                        errorCodewordsPerBlock: 22
                    },
                    Q: {
                        groups: [
                            [
                                4,
                                18
                            ],
                            [
                                2,
                                19
                            ]
                        ],
                        totalDataCodewords: 110,
                        errorCodewordsPerBlock: 22
                    },
                    H: {
                        groups: [
                            [
                                4,
                                14
                            ],
                            [
                                2,
                                15
                            ]
                        ],
                        totalDataCodewords: 86,
                        errorCodewordsPerBlock: 26
                    }
                },
                {
                    L: {
                        groups: [[
                                2,
                                116
                            ]],
                        totalDataCodewords: 232,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                3,
                                36
                            ],
                            [
                                2,
                                37
                            ]
                        ],
                        totalDataCodewords: 182,
                        errorCodewordsPerBlock: 22
                    },
                    Q: {
                        groups: [
                            [
                                4,
                                16
                            ],
                            [
                                4,
                                17
                            ]
                        ],
                        totalDataCodewords: 132,
                        errorCodewordsPerBlock: 20
                    },
                    H: {
                        groups: [
                            [
                                4,
                                12
                            ],
                            [
                                4,
                                13
                            ]
                        ],
                        totalDataCodewords: 100,
                        errorCodewordsPerBlock: 24
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                2,
                                68
                            ],
                            [
                                2,
                                69
                            ]
                        ],
                        totalDataCodewords: 274,
                        errorCodewordsPerBlock: 18
                    },
                    M: {
                        groups: [
                            [
                                4,
                                43
                            ],
                            [
                                1,
                                44
                            ]
                        ],
                        totalDataCodewords: 216,
                        errorCodewordsPerBlock: 26
                    },
                    Q: {
                        groups: [
                            [
                                6,
                                19
                            ],
                            [
                                2,
                                20
                            ]
                        ],
                        totalDataCodewords: 154,
                        errorCodewordsPerBlock: 24
                    },
                    H: {
                        groups: [
                            [
                                6,
                                15
                            ],
                            [
                                2,
                                16
                            ]
                        ],
                        totalDataCodewords: 122,
                        errorCodewordsPerBlock: 28
                    }
                },
                {
                    L: {
                        groups: [[
                                4,
                                81
                            ]],
                        totalDataCodewords: 324,
                        errorCodewordsPerBlock: 20
                    },
                    M: {
                        groups: [
                            [
                                1,
                                50
                            ],
                            [
                                4,
                                51
                            ]
                        ],
                        totalDataCodewords: 254,
                        errorCodewordsPerBlock: 30
                    },
                    Q: {
                        groups: [
                            [
                                4,
                                22
                            ],
                            [
                                4,
                                23
                            ]
                        ],
                        totalDataCodewords: 180,
                        errorCodewordsPerBlock: 28
                    },
                    H: {
                        groups: [
                            [
                                3,
                                12
                            ],
                            [
                                8,
                                13
                            ]
                        ],
                        totalDataCodewords: 140,
                        errorCodewordsPerBlock: 24
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                2,
                                92
                            ],
                            [
                                2,
                                93
                            ]
                        ],
                        totalDataCodewords: 370,
                        errorCodewordsPerBlock: 24
                    },
                    M: {
                        groups: [
                            [
                                6,
                                36
                            ],
                            [
                                2,
                                37
                            ]
                        ],
                        totalDataCodewords: 290,
                        errorCodewordsPerBlock: 22
                    },
                    Q: {
                        groups: [
                            [
                                4,
                                20
                            ],
                            [
                                6,
                                21
                            ]
                        ],
                        totalDataCodewords: 206,
                        errorCodewordsPerBlock: 26
                    },
                    H: {
                        groups: [
                            [
                                7,
                                14
                            ],
                            [
                                4,
                                15
                            ]
                        ],
                        totalDataCodewords: 158,
                        errorCodewordsPerBlock: 28
                    }
                },
                {
                    L: {
                        groups: [[
                                4,
                                107
                            ]],
                        totalDataCodewords: 428,
                        errorCodewordsPerBlock: 26
                    },
                    M: {
                        groups: [
                            [
                                8,
                                37
                            ],
                            [
                                1,
                                38
                            ]
                        ],
                        totalDataCodewords: 334,
                        errorCodewordsPerBlock: 22
                    },
                    Q: {
                        groups: [
                            [
                                8,
                                20
                            ],
                            [
                                4,
                                21
                            ]
                        ],
                        totalDataCodewords: 244,
                        errorCodewordsPerBlock: 24
                    },
                    H: {
                        groups: [
                            [
                                12,
                                11
                            ],
                            [
                                4,
                                12
                            ]
                        ],
                        totalDataCodewords: 180,
                        errorCodewordsPerBlock: 22
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                3,
                                115
                            ],
                            [
                                1,
                                116
                            ]
                        ],
                        totalDataCodewords: 461,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                4,
                                40
                            ],
                            [
                                5,
                                41
                            ]
                        ],
                        totalDataCodewords: 365,
                        errorCodewordsPerBlock: 24
                    },
                    Q: {
                        groups: [
                            [
                                11,
                                16
                            ],
                            [
                                5,
                                17
                            ]
                        ],
                        totalDataCodewords: 261,
                        errorCodewordsPerBlock: 20
                    },
                    H: {
                        groups: [
                            [
                                11,
                                12
                            ],
                            [
                                5,
                                13
                            ]
                        ],
                        totalDataCodewords: 197,
                        errorCodewordsPerBlock: 24
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                5,
                                87
                            ],
                            [
                                1,
                                88
                            ]
                        ],
                        totalDataCodewords: 523,
                        errorCodewordsPerBlock: 22
                    },
                    M: {
                        groups: [
                            [
                                5,
                                41
                            ],
                            [
                                5,
                                42
                            ]
                        ],
                        totalDataCodewords: 415,
                        errorCodewordsPerBlock: 24
                    },
                    Q: {
                        groups: [
                            [
                                5,
                                24
                            ],
                            [
                                7,
                                25
                            ]
                        ],
                        totalDataCodewords: 295,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                11,
                                12
                            ],
                            [
                                7,
                                13
                            ]
                        ],
                        totalDataCodewords: 223,
                        errorCodewordsPerBlock: 24
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                5,
                                98
                            ],
                            [
                                1,
                                99
                            ]
                        ],
                        totalDataCodewords: 589,
                        errorCodewordsPerBlock: 24
                    },
                    M: {
                        groups: [
                            [
                                7,
                                45
                            ],
                            [
                                3,
                                46
                            ]
                        ],
                        totalDataCodewords: 453,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                15,
                                19
                            ],
                            [
                                2,
                                20
                            ]
                        ],
                        totalDataCodewords: 325,
                        errorCodewordsPerBlock: 24
                    },
                    H: {
                        groups: [
                            [
                                3,
                                15
                            ],
                            [
                                13,
                                16
                            ]
                        ],
                        totalDataCodewords: 253,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                1,
                                107
                            ],
                            [
                                5,
                                108
                            ]
                        ],
                        totalDataCodewords: 647,
                        errorCodewordsPerBlock: 28
                    },
                    M: {
                        groups: [
                            [
                                10,
                                46
                            ],
                            [
                                1,
                                47
                            ]
                        ],
                        totalDataCodewords: 507,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                1,
                                22
                            ],
                            [
                                15,
                                23
                            ]
                        ],
                        totalDataCodewords: 367,
                        errorCodewordsPerBlock: 28
                    },
                    H: {
                        groups: [
                            [
                                2,
                                14
                            ],
                            [
                                17,
                                15
                            ]
                        ],
                        totalDataCodewords: 283,
                        errorCodewordsPerBlock: 28
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                5,
                                120
                            ],
                            [
                                1,
                                121
                            ]
                        ],
                        totalDataCodewords: 721,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                9,
                                43
                            ],
                            [
                                4,
                                44
                            ]
                        ],
                        totalDataCodewords: 563,
                        errorCodewordsPerBlock: 26
                    },
                    Q: {
                        groups: [
                            [
                                17,
                                22
                            ],
                            [
                                1,
                                23
                            ]
                        ],
                        totalDataCodewords: 397,
                        errorCodewordsPerBlock: 28
                    },
                    H: {
                        groups: [
                            [
                                2,
                                14
                            ],
                            [
                                19,
                                15
                            ]
                        ],
                        totalDataCodewords: 313,
                        errorCodewordsPerBlock: 28
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                3,
                                113
                            ],
                            [
                                4,
                                114
                            ]
                        ],
                        totalDataCodewords: 795,
                        errorCodewordsPerBlock: 28
                    },
                    M: {
                        groups: [
                            [
                                3,
                                44
                            ],
                            [
                                11,
                                45
                            ]
                        ],
                        totalDataCodewords: 627,
                        errorCodewordsPerBlock: 26
                    },
                    Q: {
                        groups: [
                            [
                                17,
                                21
                            ],
                            [
                                4,
                                22
                            ]
                        ],
                        totalDataCodewords: 445,
                        errorCodewordsPerBlock: 26
                    },
                    H: {
                        groups: [
                            [
                                9,
                                13
                            ],
                            [
                                16,
                                14
                            ]
                        ],
                        totalDataCodewords: 341,
                        errorCodewordsPerBlock: 26
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                3,
                                107
                            ],
                            [
                                5,
                                108
                            ]
                        ],
                        totalDataCodewords: 861,
                        errorCodewordsPerBlock: 28
                    },
                    M: {
                        groups: [
                            [
                                3,
                                41
                            ],
                            [
                                13,
                                42
                            ]
                        ],
                        totalDataCodewords: 669,
                        errorCodewordsPerBlock: 26
                    },
                    Q: {
                        groups: [
                            [
                                15,
                                24
                            ],
                            [
                                5,
                                25
                            ]
                        ],
                        totalDataCodewords: 485,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                15,
                                15
                            ],
                            [
                                10,
                                16
                            ]
                        ],
                        totalDataCodewords: 385,
                        errorCodewordsPerBlock: 28
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                4,
                                116
                            ],
                            [
                                4,
                                117
                            ]
                        ],
                        totalDataCodewords: 932,
                        errorCodewordsPerBlock: 28
                    },
                    M: {
                        groups: [[
                                17,
                                42
                            ]],
                        totalDataCodewords: 714,
                        errorCodewordsPerBlock: 26
                    },
                    Q: {
                        groups: [
                            [
                                17,
                                22
                            ],
                            [
                                6,
                                23
                            ]
                        ],
                        totalDataCodewords: 512,
                        errorCodewordsPerBlock: 28
                    },
                    H: {
                        groups: [
                            [
                                19,
                                16
                            ],
                            [
                                6,
                                17
                            ]
                        ],
                        totalDataCodewords: 406,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                2,
                                111
                            ],
                            [
                                7,
                                112
                            ]
                        ],
                        totalDataCodewords: 1006,
                        errorCodewordsPerBlock: 28
                    },
                    M: {
                        groups: [[
                                17,
                                46
                            ]],
                        totalDataCodewords: 782,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                7,
                                24
                            ],
                            [
                                16,
                                25
                            ]
                        ],
                        totalDataCodewords: 568,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [[
                                34,
                                13
                            ]],
                        totalDataCodewords: 442,
                        errorCodewordsPerBlock: 24
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                4,
                                121
                            ],
                            [
                                5,
                                122
                            ]
                        ],
                        totalDataCodewords: 1094,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                4,
                                47
                            ],
                            [
                                14,
                                48
                            ]
                        ],
                        totalDataCodewords: 860,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                11,
                                24
                            ],
                            [
                                14,
                                25
                            ]
                        ],
                        totalDataCodewords: 614,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                16,
                                15
                            ],
                            [
                                14,
                                16
                            ]
                        ],
                        totalDataCodewords: 464,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                6,
                                117
                            ],
                            [
                                4,
                                118
                            ]
                        ],
                        totalDataCodewords: 1174,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                6,
                                45
                            ],
                            [
                                14,
                                46
                            ]
                        ],
                        totalDataCodewords: 914,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                11,
                                24
                            ],
                            [
                                16,
                                25
                            ]
                        ],
                        totalDataCodewords: 664,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                30,
                                16
                            ],
                            [
                                2,
                                17
                            ]
                        ],
                        totalDataCodewords: 514,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                8,
                                106
                            ],
                            [
                                4,
                                107
                            ]
                        ],
                        totalDataCodewords: 1276,
                        errorCodewordsPerBlock: 26
                    },
                    M: {
                        groups: [
                            [
                                8,
                                47
                            ],
                            [
                                13,
                                48
                            ]
                        ],
                        totalDataCodewords: 1000,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                7,
                                24
                            ],
                            [
                                22,
                                25
                            ]
                        ],
                        totalDataCodewords: 718,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                22,
                                15
                            ],
                            [
                                13,
                                16
                            ]
                        ],
                        totalDataCodewords: 538,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                10,
                                114
                            ],
                            [
                                2,
                                115
                            ]
                        ],
                        totalDataCodewords: 1370,
                        errorCodewordsPerBlock: 28
                    },
                    M: {
                        groups: [
                            [
                                19,
                                46
                            ],
                            [
                                4,
                                47
                            ]
                        ],
                        totalDataCodewords: 1062,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                28,
                                22
                            ],
                            [
                                6,
                                23
                            ]
                        ],
                        totalDataCodewords: 754,
                        errorCodewordsPerBlock: 28
                    },
                    H: {
                        groups: [
                            [
                                33,
                                16
                            ],
                            [
                                4,
                                17
                            ]
                        ],
                        totalDataCodewords: 596,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                8,
                                122
                            ],
                            [
                                4,
                                123
                            ]
                        ],
                        totalDataCodewords: 1468,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                22,
                                45
                            ],
                            [
                                3,
                                46
                            ]
                        ],
                        totalDataCodewords: 1128,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                8,
                                23
                            ],
                            [
                                26,
                                24
                            ]
                        ],
                        totalDataCodewords: 808,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                12,
                                15
                            ],
                            [
                                28,
                                16
                            ]
                        ],
                        totalDataCodewords: 628,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                3,
                                117
                            ],
                            [
                                10,
                                118
                            ]
                        ],
                        totalDataCodewords: 1531,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                3,
                                45
                            ],
                            [
                                23,
                                46
                            ]
                        ],
                        totalDataCodewords: 1193,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                4,
                                24
                            ],
                            [
                                31,
                                25
                            ]
                        ],
                        totalDataCodewords: 871,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                11,
                                15
                            ],
                            [
                                31,
                                16
                            ]
                        ],
                        totalDataCodewords: 661,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                7,
                                116
                            ],
                            [
                                7,
                                117
                            ]
                        ],
                        totalDataCodewords: 1631,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                21,
                                45
                            ],
                            [
                                7,
                                46
                            ]
                        ],
                        totalDataCodewords: 1267,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                1,
                                23
                            ],
                            [
                                37,
                                24
                            ]
                        ],
                        totalDataCodewords: 911,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                19,
                                15
                            ],
                            [
                                26,
                                16
                            ]
                        ],
                        totalDataCodewords: 701,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                5,
                                115
                            ],
                            [
                                10,
                                116
                            ]
                        ],
                        totalDataCodewords: 1735,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                19,
                                47
                            ],
                            [
                                10,
                                48
                            ]
                        ],
                        totalDataCodewords: 1373,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                15,
                                24
                            ],
                            [
                                25,
                                25
                            ]
                        ],
                        totalDataCodewords: 985,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                23,
                                15
                            ],
                            [
                                25,
                                16
                            ]
                        ],
                        totalDataCodewords: 745,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                13,
                                115
                            ],
                            [
                                3,
                                116
                            ]
                        ],
                        totalDataCodewords: 1843,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                2,
                                46
                            ],
                            [
                                29,
                                47
                            ]
                        ],
                        totalDataCodewords: 1455,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                42,
                                24
                            ],
                            [
                                1,
                                25
                            ]
                        ],
                        totalDataCodewords: 1033,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                23,
                                15
                            ],
                            [
                                28,
                                16
                            ]
                        ],
                        totalDataCodewords: 793,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [[
                                17,
                                115
                            ]],
                        totalDataCodewords: 1955,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                10,
                                46
                            ],
                            [
                                23,
                                47
                            ]
                        ],
                        totalDataCodewords: 1541,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                10,
                                24
                            ],
                            [
                                35,
                                25
                            ]
                        ],
                        totalDataCodewords: 1115,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                19,
                                15
                            ],
                            [
                                35,
                                16
                            ]
                        ],
                        totalDataCodewords: 845,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                17,
                                115
                            ],
                            [
                                1,
                                116
                            ]
                        ],
                        totalDataCodewords: 2071,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                14,
                                46
                            ],
                            [
                                21,
                                47
                            ]
                        ],
                        totalDataCodewords: 1631,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                29,
                                24
                            ],
                            [
                                19,
                                25
                            ]
                        ],
                        totalDataCodewords: 1171,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                11,
                                15
                            ],
                            [
                                46,
                                16
                            ]
                        ],
                        totalDataCodewords: 901,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                13,
                                115
                            ],
                            [
                                6,
                                116
                            ]
                        ],
                        totalDataCodewords: 2191,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                14,
                                46
                            ],
                            [
                                23,
                                47
                            ]
                        ],
                        totalDataCodewords: 1725,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                44,
                                24
                            ],
                            [
                                7,
                                25
                            ]
                        ],
                        totalDataCodewords: 1231,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                59,
                                16
                            ],
                            [
                                1,
                                17
                            ]
                        ],
                        totalDataCodewords: 961,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                12,
                                121
                            ],
                            [
                                7,
                                122
                            ]
                        ],
                        totalDataCodewords: 2306,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                12,
                                47
                            ],
                            [
                                26,
                                48
                            ]
                        ],
                        totalDataCodewords: 1812,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                39,
                                24
                            ],
                            [
                                14,
                                25
                            ]
                        ],
                        totalDataCodewords: 1286,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                22,
                                15
                            ],
                            [
                                41,
                                16
                            ]
                        ],
                        totalDataCodewords: 986,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                6,
                                121
                            ],
                            [
                                14,
                                122
                            ]
                        ],
                        totalDataCodewords: 2434,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                6,
                                47
                            ],
                            [
                                34,
                                48
                            ]
                        ],
                        totalDataCodewords: 1914,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                46,
                                24
                            ],
                            [
                                10,
                                25
                            ]
                        ],
                        totalDataCodewords: 1354,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                2,
                                15
                            ],
                            [
                                64,
                                16
                            ]
                        ],
                        totalDataCodewords: 1054,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                17,
                                122
                            ],
                            [
                                4,
                                123
                            ]
                        ],
                        totalDataCodewords: 2566,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                29,
                                46
                            ],
                            [
                                14,
                                47
                            ]
                        ],
                        totalDataCodewords: 1992,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                49,
                                24
                            ],
                            [
                                10,
                                25
                            ]
                        ],
                        totalDataCodewords: 1426,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                24,
                                15
                            ],
                            [
                                46,
                                16
                            ]
                        ],
                        totalDataCodewords: 1096,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                4,
                                122
                            ],
                            [
                                18,
                                123
                            ]
                        ],
                        totalDataCodewords: 2702,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                13,
                                46
                            ],
                            [
                                32,
                                47
                            ]
                        ],
                        totalDataCodewords: 2102,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                48,
                                24
                            ],
                            [
                                14,
                                25
                            ]
                        ],
                        totalDataCodewords: 1502,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                42,
                                15
                            ],
                            [
                                32,
                                16
                            ]
                        ],
                        totalDataCodewords: 1142,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                20,
                                117
                            ],
                            [
                                4,
                                118
                            ]
                        ],
                        totalDataCodewords: 2812,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                40,
                                47
                            ],
                            [
                                7,
                                48
                            ]
                        ],
                        totalDataCodewords: 2216,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                43,
                                24
                            ],
                            [
                                22,
                                25
                            ]
                        ],
                        totalDataCodewords: 1582,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                10,
                                15
                            ],
                            [
                                67,
                                16
                            ]
                        ],
                        totalDataCodewords: 1222,
                        errorCodewordsPerBlock: 30
                    }
                },
                {
                    L: {
                        groups: [
                            [
                                19,
                                118
                            ],
                            [
                                6,
                                119
                            ]
                        ],
                        totalDataCodewords: 2956,
                        errorCodewordsPerBlock: 30
                    },
                    M: {
                        groups: [
                            [
                                18,
                                47
                            ],
                            [
                                31,
                                48
                            ]
                        ],
                        totalDataCodewords: 2334,
                        errorCodewordsPerBlock: 28
                    },
                    Q: {
                        groups: [
                            [
                                34,
                                24
                            ],
                            [
                                34,
                                25
                            ]
                        ],
                        totalDataCodewords: 1666,
                        errorCodewordsPerBlock: 30
                    },
                    H: {
                        groups: [
                            [
                                20,
                                15
                            ],
                            [
                                61,
                                16
                            ]
                        ],
                        totalDataCodewords: 1276,
                        errorCodewordsPerBlock: 30
                    }
                }
            ], finderPattern = [
                1,
                0,
                1,
                1,
                1
            ], alignmentPattern = [
                1,
                0,
                1
            ], errorCorrectionPatterns = {
                L: '01',
                M: '00',
                Q: '11',
                H: '10'
            }, formatMaskPattern = '101010000010010', formatGeneratorPolynomial = '10100110111', versionGeneratorPolynomial = '1111100100101', paddingCodewords = [
                '11101100',
                '00010001'
            ], finderPatternValue = 93, maskPatternConditions = [
                function (row, column) {
                    return (row + column) % 2 === 0;
                },
                function (row) {
                    return row % 2 === 0;
                },
                function (row, column) {
                    return column % 3 === 0;
                },
                function (row, column) {
                    return (row + column) % 3 === 0;
                },
                function (row, column) {
                    return (Math.floor(row / 2) + Math.floor(column / 3)) % 2 === 0;
                },
                function (row, column) {
                    return row * column % 2 + row * column % 3 === 0;
                },
                function (row, column) {
                    return (row * column % 2 + row * column % 3) % 2 === 0;
                },
                function (row, column) {
                    return ((row + column) % 2 + row * column % 3) % 2 === 0;
                }
            ], numberRegex = /^\d+/, alphaPattern = 'A-Z0-9 $%*+./:-', alphaExclusiveSet = 'A-Z $%*+./:-', alphaRegex = new RegExp('^[' + alphaExclusiveSet + ']+'), alphaNumericRegex = new RegExp('^[' + alphaPattern + ']+'), byteRegex = new RegExp('^[^' + alphaPattern + ']+'), initMinNumericBeforeAlpha = 8, initMinNumericBeforeByte = 5, initMinAlphaBeforeByte = 8, minNumericBeforeAlpha = 17, minNumericBeforeByte = 9, minAlphaBeforeByte = 16, round = Math.round;
        function toDecimal(value) {
            return parseInt(value, 2);
        }
        function toBitsString(value, length) {
            var result = Number(value).toString(2);
            if (result.length < length) {
                result = new Array(length - result.length + 1).join(0) + result;
            }
            return result;
        }
        function splitInto(str, n) {
            var result = [], idx = 0;
            while (idx < str.length) {
                result.push(str.substring(idx, idx + n));
                idx += n;
            }
            return result;
        }
        var QRDataMode = kendo.Class.extend({
            getVersionIndex: function (version) {
                if (version < 10) {
                    return 0;
                } else if (version > 26) {
                    return 2;
                }
                return 1;
            },
            getBitsCharacterCount: function (version) {
                var mode = this;
                return mode.bitsInCharacterCount[mode.getVersionIndex(version || 40)];
            },
            getModeCountString: function (length, version) {
                var mode = this;
                return mode.modeIndicator + toBitsString(length, mode.getBitsCharacterCount(version));
            },
            encode: function () {
            },
            getStringBitsLength: function () {
            },
            getValue: function () {
            },
            modeIndicator: '',
            bitsInCharacterCount: []
        });
        var modes = {};
        modes[NUMERIC] = QRDataMode.extend({
            bitsInCharacterCount: [
                10,
                12,
                14
            ],
            modeIndicator: '0001',
            getValue: function (character) {
                return parseInt(character, 10);
            },
            encode: function (str, version) {
                var mode = this, parts = splitInto(str, 3), result = mode.getModeCountString(str.length, version);
                for (var i = 0; i < parts.length - 1; i++) {
                    result += toBitsString(parts[i], 10);
                }
                return result + toBitsString(parts[i], 1 + 3 * parts[i].length);
            },
            getStringBitsLength: function (inputLength, version) {
                var mod3 = inputLength % 3;
                return 4 + this.getBitsCharacterCount(version) + 10 * Math.floor(inputLength / 3) + 3 * mod3 + (mod3 === 0 ? 0 : 1);
            }
        });
        modes[ALPHA_NUMERIC] = QRDataMode.extend({
            characters: {
                '0': 0,
                '1': 1,
                '2': 2,
                '3': 3,
                '4': 4,
                '5': 5,
                '6': 6,
                '7': 7,
                '8': 8,
                '9': 9,
                'A': 10,
                'B': 11,
                'C': 12,
                'D': 13,
                'E': 14,
                'F': 15,
                'G': 16,
                'H': 17,
                'I': 18,
                'J': 19,
                'K': 20,
                'L': 21,
                'M': 22,
                'N': 23,
                'O': 24,
                'P': 25,
                'Q': 26,
                'R': 27,
                'S': 28,
                'T': 29,
                'U': 30,
                'V': 31,
                'W': 32,
                'X': 33,
                'Y': 34,
                'Z': 35,
                ' ': 36,
                '$': 37,
                '%': 38,
                '*': 39,
                '+': 40,
                '-': 41,
                '.': 42,
                '/': 43,
                ':': 44
            },
            bitsInCharacterCount: [
                9,
                11,
                13
            ],
            modeIndicator: '0010',
            getValue: function (character) {
                return this.characters[character];
            },
            encode: function (str, version) {
                var mode = this, parts = splitInto(str, 2), result = mode.getModeCountString(str.length, version), value;
                for (var i = 0; i < parts.length - 1; i++) {
                    value = 45 * mode.getValue(parts[i].charAt(0)) + mode.getValue(parts[i].charAt(1));
                    result += toBitsString(value, 11);
                }
                value = parts[i].length == 2 ? 45 * mode.getValue(parts[i].charAt(0)) + mode.getValue(parts[i].charAt(1)) : mode.getValue(parts[i].charAt(0));
                return result + toBitsString(value, 1 + 5 * parts[i].length);
            },
            getStringBitsLength: function (inputLength, version) {
                return 4 + this.getBitsCharacterCount(version) + 11 * Math.floor(inputLength / 2) + 6 * (inputLength % 2);
            }
        });
        modes[BYTE] = QRDataMode.extend({
            bitsInCharacterCount: [
                8,
                16,
                16
            ],
            modeIndicator: '0100',
            getValue: function (character) {
                var code = character.charCodeAt(0);
                if (code <= 127 || 160 <= code && code <= 255) {
                    return code;
                } else {
                    throw new Error('Unsupported character: ' + character);
                }
            },
            encode: function (str, version) {
                var mode = this, result = mode.getModeCountString(str.length, version);
                for (var i = 0; i < str.length; i++) {
                    result += toBitsString(mode.getValue(str.charAt(i)), 8);
                }
                return result;
            },
            getStringBitsLength: function (inputLength, version) {
                return 4 + this.getBitsCharacterCount(version) + 8 * inputLength;
            }
        });
        var modeInstances = {};
        for (var mode in modes) {
            modeInstances[mode] = new modes[mode]();
        }
        var FreeCellVisitor = function (matrix) {
            var that = this, row = matrix.length - 1, column = matrix.length - 1, startColumn = column, dir = -1, c = 0;
            that.move = function () {
                row += dir * c;
                c ^= 1;
                column = startColumn - c;
            };
            that.getNextCell = function () {
                while (matrix[row][column] !== undefined) {
                    that.move();
                    if (row < 0 || row >= matrix.length) {
                        dir = -dir;
                        startColumn -= startColumn != 8 ? 2 : 3;
                        column = startColumn;
                        row = dir < 0 ? matrix.length - 1 : 0;
                    }
                }
                return {
                    row: row,
                    column: column
                };
            };
            that.getNextRemainderCell = function () {
                that.move();
                if (matrix[row][column] === undefined) {
                    return {
                        row: row,
                        column: column
                    };
                }
            };
        };
        function fillFunctionCell(matrices, bit, x, y) {
            for (var i = 0; i < matrices.length; i++) {
                matrices[i][x][y] = bit;
            }
        }
        function fillDataCell(matrices, bit, x, y) {
            for (var i = 0; i < maskPatternConditions.length; i++) {
                matrices[i][x][y] = maskPatternConditions[i](x, y) ? bit ^ 1 : parseInt(bit, 10);
            }
        }
        var fillData = function (matrices, blocks) {
            var cellVisitor = new FreeCellVisitor(matrices[0]), block, codewordIdx, cell;
            for (var blockIdx = 0; blockIdx < blocks.length; blockIdx++) {
                block = blocks[blockIdx];
                codewordIdx = 0;
                while (block.length > 0) {
                    for (var i = 0; i < block.length; i++) {
                        for (var j = 0; j < 8; j++) {
                            cell = cellVisitor.getNextCell();
                            fillDataCell(matrices, block[i][codewordIdx].charAt(j), cell.row, cell.column);
                        }
                    }
                    codewordIdx++;
                    while (block[0] && codewordIdx == block[0].length) {
                        block.splice(0, 1);
                    }
                }
            }
            while (cell = cellVisitor.getNextRemainderCell()) {
                fillDataCell(matrices, 0, cell.row, cell.column);
            }
        };
        var padDataString = function (dataString, totalDataCodewords) {
            var dataBitsCount = totalDataCodewords * 8, terminatorIndex = 0, paddingCodewordIndex = 0;
            while (dataString.length < dataBitsCount && terminatorIndex < terminator.length) {
                dataString += terminator.charAt(terminatorIndex++);
            }
            if (dataString.length % 8 !== 0) {
                dataString += new Array(9 - dataString.length % 8).join('0');
            }
            while (dataString.length < dataBitsCount) {
                dataString += paddingCodewords[paddingCodewordIndex];
                paddingCodewordIndex ^= 1;
            }
            return dataString;
        };
        function generatePowersOfTwo() {
            var result;
            for (var power = 1; power < 255; power++) {
                result = powersOfTwoResult[power - 1] * 2;
                if (result > 255) {
                    result = result ^ 285;
                }
                powersOfTwoResult[power] = result;
                powersOfTwo[result] = power;
            }
            result = powersOfTwoResult[power - 1] * 2 ^ 285;
            powersOfTwoResult[power] = result;
            powersOfTwoResult[-1] = 0;
        }
        var xorPolynomials = function (x, y) {
            var result = [], idx = x.length - 2;
            for (var i = idx; i >= 0; i--) {
                result[i] = x[i] ^ y[i];
            }
            return result;
        };
        var multiplyPolynomials = function (x, y) {
            var result = [];
            for (var i = 0; i < x.length; i++) {
                for (var j = 0; j < y.length; j++) {
                    if (result[i + j] === undefined) {
                        result[i + j] = (x[i] + (y[j] >= 0 ? y[j] : 0)) % 255;
                    } else {
                        result[i + j] = powersOfTwo[powersOfTwoResult[result[i + j]] ^ powersOfTwoResult[(x[i] + y[j]) % 255]];
                    }
                }
            }
            return result;
        };
        function generateGeneratorPolynomials() {
            var maxErrorCorrectionCodeWordsCount = 68;
            for (var idx = 2; idx <= maxErrorCorrectionCodeWordsCount; idx++) {
                var firstPolynomial = generatorPolynomials[idx - 1], secondPolynomial = [
                        idx,
                        0
                    ];
                generatorPolynomials[idx] = multiplyPolynomials(firstPolynomial, secondPolynomial);
            }
        }
        generatePowersOfTwo();
        generateGeneratorPolynomials();
        function multiplyByConstant(polynomial, power) {
            var result = [], idx = polynomial.length - 1;
            do {
                result[idx] = powersOfTwoResult[(polynomial[idx] + power) % 255];
                idx--;
            } while (polynomial[idx] !== undefined);
            return result;
        }
        var generateErrorCodewords = function (data, errorCodewordsCount) {
            var generator = generatorPolynomials[errorCodewordsCount - 1], result = new Array(errorCodewordsCount).concat(data), generatorPolynomial = new Array(result.length - generator.length).concat(generator), steps = data.length, errorCodewords = [], divisor, idx;
            for (idx = 0; idx < steps; idx++) {
                divisor = multiplyByConstant(generatorPolynomial, powersOfTwo[result[result.length - 1]]);
                generatorPolynomial.splice(0, 1);
                result = xorPolynomials(divisor, result);
            }
            for (idx = result.length - 1; idx >= 0; idx--) {
                errorCodewords[errorCodewordsCount - 1 - idx] = toBitsString(result[idx], 8);
            }
            return errorCodewords;
        };
        var getBlocks = function (dataStream, versionCodewordsInformation) {
            var codewordStart = 0, dataBlocks = [], errorBlocks = [], dataBlock, versionGroups = versionCodewordsInformation.groups, blockCodewordsCount, groupBlocksCount, messagePolynomial, codeword;
            for (var groupIdx = 0; groupIdx < versionGroups.length; groupIdx++) {
                groupBlocksCount = versionGroups[groupIdx][0];
                for (var blockIdx = 0; blockIdx < groupBlocksCount; blockIdx++) {
                    blockCodewordsCount = versionGroups[groupIdx][1];
                    dataBlock = [];
                    messagePolynomial = [];
                    for (var codewordIdx = 1; codewordIdx <= blockCodewordsCount; codewordIdx++) {
                        codeword = dataStream.substring(codewordStart, codewordStart + 8);
                        dataBlock.push(codeword);
                        messagePolynomial[blockCodewordsCount - codewordIdx] = toDecimal(codeword);
                        codewordStart += 8;
                    }
                    dataBlocks.push(dataBlock);
                    errorBlocks.push(generateErrorCodewords(messagePolynomial, versionCodewordsInformation.errorCodewordsPerBlock));
                }
            }
            return [
                dataBlocks,
                errorBlocks
            ];
        };
        var chooseMode = function (str, minNumericBeforeAlpha, minNumericBeforeByte, minAlphaBeforeByte, previousMode) {
            var numeric = numberRegex.exec(str), numericMatch = numeric ? numeric[0] : '', alpha = alphaRegex.exec(str), alphaMatch = alpha ? alpha[0] : '', alphaNumeric = alphaNumericRegex.exec(str), alphaNumericMatch = alphaNumeric ? alphaNumeric[0] : '', mode, modeString;
            if (numericMatch && (numericMatch.length >= minNumericBeforeAlpha || str.length == numericMatch.length || numericMatch.length >= minNumericBeforeByte && !alphaNumericRegex.test(str.charAt(numericMatch.length)))) {
                mode = NUMERIC;
                modeString = numericMatch;
            } else if (alphaNumericMatch && (str.length == alphaNumericMatch.length || alphaNumericMatch.length >= minAlphaBeforeByte || previousMode == ALPHA_NUMERIC)) {
                mode = ALPHA_NUMERIC;
                modeString = numericMatch || alphaMatch;
            } else {
                mode = BYTE;
                if (alphaNumericMatch) {
                    modeString = alphaNumericMatch + byteRegex.exec(str.substring(alphaNumericMatch.length))[0];
                } else {
                    modeString = byteRegex.exec(str)[0];
                }
            }
            return {
                mode: mode,
                modeString: modeString
            };
        };
        var getModes = function (str) {
            var modes = [], previousMode, idx = 0;
            modes.push(chooseMode(str, initMinNumericBeforeAlpha, initMinNumericBeforeByte, initMinAlphaBeforeByte, previousMode));
            previousMode = modes[0].mode;
            str = str.substr(modes[0].modeString.length);
            while (str.length > 0) {
                var nextMode = chooseMode(str, minNumericBeforeAlpha, minNumericBeforeByte, minAlphaBeforeByte, previousMode);
                if (nextMode.mode != previousMode) {
                    previousMode = nextMode.mode;
                    modes.push(nextMode);
                    idx++;
                } else {
                    modes[idx].modeString += nextMode.modeString;
                }
                str = str.substr(nextMode.modeString.length);
            }
            return modes;
        };
        var getDataCodewordsCount = function (modes) {
            var length = 0, mode;
            for (var i = 0; i < modes.length; i++) {
                mode = modeInstances[modes[i].mode];
                length += mode.getStringBitsLength(modes[i].modeString.length);
            }
            return Math.ceil(length / 8);
        };
        var getVersion = function (dataCodewordsCount, errorCorrectionLevel) {
            var x = 0, y = versionsCodewordsInformation.length - 1, version = Math.floor(versionsCodewordsInformation.length / 2);
            do {
                if (dataCodewordsCount < versionsCodewordsInformation[version][errorCorrectionLevel].totalDataCodewords) {
                    y = version;
                } else {
                    x = version;
                }
                version = x + Math.floor((y - x) / 2);
            } while (y - x > 1);
            if (dataCodewordsCount <= versionsCodewordsInformation[x][errorCorrectionLevel].totalDataCodewords) {
                return version + 1;
            }
            return y + 1;
        };
        var getDataString = function (modes, version) {
            var dataString = '', mode;
            for (var i = 0; i < modes.length; i++) {
                mode = modeInstances[modes[i].mode];
                dataString += mode.encode(modes[i].modeString, version);
            }
            return dataString;
        };
        var encodeFormatInformation = function (format) {
            var formatNumber = toDecimal(format), encodedString, result = '';
            if (formatNumber === 0) {
                return '101010000010010';
            } else {
                encodedString = encodeBCH(toDecimal(format), formatGeneratorPolynomial, 15);
            }
            for (var i = 0; i < encodedString.length; i++) {
                result += encodedString.charAt(i) ^ formatMaskPattern.charAt(i);
            }
            return result;
        };
        var encodeBCH = function (value, generatorPolynomial, codeLength) {
            var generatorNumber = toDecimal(generatorPolynomial), polynomialLength = generatorPolynomial.length - 1, valueNumber = value << polynomialLength, length = codeLength - polynomialLength, valueString = toBitsString(value, length), result = dividePolynomials(valueNumber, generatorNumber);
            result = valueString + toBitsString(result, polynomialLength);
            return result;
        };
        var dividePolynomials = function (numberX, numberY) {
            var yLength = numberY.toString(2).length, xLength = numberX.toString(2).length;
            do {
                numberX ^= numberY << xLength - yLength;
                xLength = numberX.toString(2).length;
            } while (xLength >= yLength);
            return numberX;
        };
        function getNumberAt(str, idx) {
            return parseInt(str.charAt(idx), 10);
        }
        var initMatrices = function (version) {
            var matrices = [], modules = 17 + 4 * version;
            for (var i = 0; i < maskPatternConditions.length; i++) {
                matrices[i] = new Array(modules);
                for (var j = 0; j < modules; j++) {
                    matrices[i][j] = new Array(modules);
                }
            }
            return matrices;
        };
        var addFormatInformation = function (matrices, formatString) {
            var matrix = matrices[0], x, y, idx = 0, length = formatString.length;
            for (x = 0, y = 8; x <= 8; x++) {
                if (x !== 6) {
                    fillFunctionCell(matrices, getNumberAt(formatString, length - 1 - idx++), x, y);
                }
            }
            for (x = 8, y = 7; y >= 0; y--) {
                if (y !== 6) {
                    fillFunctionCell(matrices, getNumberAt(formatString, length - 1 - idx++), x, y);
                }
            }
            idx = 0;
            for (y = matrix.length - 1, x = 8; y >= matrix.length - 8; y--) {
                fillFunctionCell(matrices, getNumberAt(formatString, length - 1 - idx++), x, y);
            }
            fillFunctionCell(matrices, 1, matrix.length - 8, 8);
            for (x = matrix.length - 7, y = 8; x < matrix.length; x++) {
                fillFunctionCell(matrices, getNumberAt(formatString, length - 1 - idx++), x, y);
            }
        };
        var encodeVersionInformation = function (version) {
            return encodeBCH(version, versionGeneratorPolynomial, 18);
        };
        var addVersionInformation = function (matrices, dataString) {
            var matrix = matrices[0], modules = matrix.length, x1 = 0, y1 = modules - 11, x2 = modules - 11, y2 = 0, quotient, mod, value;
            for (var idx = 0; idx < dataString.length; idx++) {
                quotient = Math.floor(idx / 3);
                mod = idx % 3;
                value = getNumberAt(dataString, dataString.length - idx - 1);
                fillFunctionCell(matrices, value, x1 + quotient, y1 + mod);
                fillFunctionCell(matrices, value, x2 + mod, y2 + quotient);
            }
        };
        var addCentricPattern = function (matrices, pattern, x, y) {
            var size = pattern.length + 2, length = pattern.length + 1, value;
            for (var i = 0; i < pattern.length; i++) {
                for (var j = i; j < size - i; j++) {
                    value = pattern[i];
                    fillFunctionCell(matrices, value, x + j, y + i);
                    fillFunctionCell(matrices, value, x + i, y + j);
                    fillFunctionCell(matrices, value, x + length - j, y + length - i);
                    fillFunctionCell(matrices, value, x + length - i, y + length - j);
                }
            }
        };
        var addFinderSeparator = function (matrices, direction, x, y) {
            var nextX = x, nextY = y, matrix = matrices[0];
            do {
                fillFunctionCell(matrices, 0, nextX, y);
                fillFunctionCell(matrices, 0, x, nextY);
                nextX += direction[0];
                nextY += direction[1];
            } while (nextX >= 0 && nextX < matrix.length);
        };
        var addFinderPatterns = function (matrices) {
            var modules = matrices[0].length;
            addCentricPattern(matrices, finderPattern, 0, 0);
            addFinderSeparator(matrices, [
                -1,
                -1
            ], 7, 7);
            addCentricPattern(matrices, finderPattern, modules - 7, 0);
            addFinderSeparator(matrices, [
                1,
                -1
            ], modules - 8, 7);
            addCentricPattern(matrices, finderPattern, 0, modules - 7);
            addFinderSeparator(matrices, [
                -1,
                1
            ], 7, modules - 8);
        };
        var addAlignmentPatterns = function (matrices, version) {
            if (version < 2) {
                return;
            }
            var matrix = matrices[0], modules = matrix.length, pointsCount = Math.floor(version / 7), points = [6], startDistance, distance, idx = 0;
            if (startDistance = irregularAlignmentPatternsStartDistance[version]) {
                distance = (modules - 13 - startDistance) / pointsCount;
            } else {
                startDistance = distance = (modules - 13) / (pointsCount + 1);
            }
            points.push(points[idx++] + startDistance);
            while (points[idx] + distance < modules) {
                points.push(points[idx++] + distance);
            }
            for (var i = 0; i < points.length; i++) {
                for (var j = 0; j < points.length; j++) {
                    if (matrix[points[i]][points[j]] === undefined) {
                        addCentricPattern(matrices, alignmentPattern, points[i] - 2, points[j] - 2);
                    }
                }
            }
        };
        var addTimingFunctions = function (matrices) {
            var row = 6, column = 6, value = 1, modules = matrices[0].length;
            for (var i = 8; i < modules - 8; i++) {
                fillFunctionCell(matrices, value, row, i);
                fillFunctionCell(matrices, value, i, column);
                value ^= 1;
            }
        };
        var scoreMaskMatrixes = function (matrices) {
            var scores = [], previousBits = [], darkModules = [], patterns = [], adjacentSameBits = [], matrix, i, row = 0, column = 1, modules = matrices[0].length;
            for (i = 0; i < matrices.length; i++) {
                scores[i] = 0;
                darkModules[i] = 0;
                adjacentSameBits[i] = [
                    0,
                    0
                ];
                patterns[i] = [
                    0,
                    0
                ];
                previousBits[i] = [];
            }
            for (i = 0; i < modules; i++) {
                for (var j = 0; j < modules; j++) {
                    for (var k = 0; k < matrices.length; k++) {
                        matrix = matrices[k];
                        darkModules[k] += parseInt(matrix[i][j], 10);
                        if (previousBits[k][row] === matrix[i][j] && i + 1 < modules && j - 1 >= 0 && matrix[i + 1][j] == previousBits[k][row] && matrix[i + 1][j - 1] == previousBits[k][row]) {
                            scores[k] += 3;
                        }
                        scoreFinderPatternOccurance(k, patterns, scores, row, matrix[i][j]);
                        scoreFinderPatternOccurance(k, patterns, scores, column, matrix[j][i]);
                        scoreAdjacentSameBits(k, scores, previousBits, matrix[i][j], adjacentSameBits, row);
                        scoreAdjacentSameBits(k, scores, previousBits, matrix[j][i], adjacentSameBits, column);
                    }
                }
            }
            var total = modules * modules, minIdx, min = Number.MAX_VALUE;
            for (i = 0; i < scores.length; i++) {
                scores[i] += calculateDarkModulesRatioScore(darkModules[i], total);
                if (scores[i] < min) {
                    min = scores[i];
                    minIdx = i;
                }
            }
            return minIdx;
        };
        function scoreFinderPatternOccurance(idx, patterns, scores, rowColumn, bit) {
            patterns[idx][rowColumn] = (patterns[idx][rowColumn] << 1 ^ bit) % 128;
            if (patterns[idx][rowColumn] == finderPatternValue) {
                scores[idx] += 40;
            }
        }
        function scoreAdjacentSameBits(idx, scores, previousBits, bit, adjacentBits, rowColumn) {
            if (previousBits[idx][rowColumn] == bit) {
                adjacentBits[idx][rowColumn]++;
            } else {
                previousBits[idx][rowColumn] = bit;
                if (adjacentBits[idx][rowColumn] >= 5) {
                    scores[idx] += 3 + adjacentBits[idx][rowColumn] - 5;
                }
                adjacentBits[idx][rowColumn] = 1;
            }
        }
        function calculateDarkModulesRatioScore(darkModules, total) {
            var percent = Math.floor(darkModules / total * 100), mod5 = percent % 5, previous = Math.abs(percent - mod5 - 50), next = Math.abs(percent + 5 - mod5 - 50), score = 10 * Math.min(previous / 5, next / 5);
            return score;
        }
        var EncodingResult = function (dataString, version) {
            this.dataString = dataString;
            this.version = version;
        };
        var IsoEncoder = function () {
            this.getEncodingResult = function (inputString, errorCorrectionLevel) {
                var modes = getModes(inputString), dataCodewordsCount = getDataCodewordsCount(modes), version = getVersion(dataCodewordsCount, errorCorrectionLevel), dataString = getDataString(modes, version);
                return new EncodingResult(dataString, version);
            };
        };
        var UTF8Encoder = function () {
            this.mode = modeInstances[this.encodingMode];
        };
        UTF8Encoder.fn = UTF8Encoder.prototype = {
            encodingMode: BYTE,
            utfBOM: '111011111011101110111111',
            initialModeCountStringLength: 20,
            getEncodingResult: function (inputString, errorCorrectionLevel) {
                var that = this, data = that.encode(inputString), dataCodewordsCount = that.getDataCodewordsCount(data), version = getVersion(dataCodewordsCount, errorCorrectionLevel), dataString = that.mode.getModeCountString(data.length / 8, version) + data;
                return new EncodingResult(dataString, version);
            },
            getDataCodewordsCount: function (data) {
                var that = this, dataLength = data.length, dataCodewordsCount = Math.ceil((that.initialModeCountStringLength + dataLength) / 8);
                return dataCodewordsCount;
            },
            encode: function (str) {
                var that = this, result = that.utfBOM;
                for (var i = 0; i < str.length; i++) {
                    result += that.encodeCharacter(str.charCodeAt(i));
                }
                return result;
            },
            encodeCharacter: function (code) {
                var bytesCount = this.getBytesCount(code), bc = bytesCount - 1, result = '';
                if (bytesCount == 1) {
                    result = toBitsString(code, 8);
                } else {
                    var significantOnes = 8 - bytesCount;
                    for (var i = 0; i < bc; i++) {
                        result = toBitsString(code >> i * 6 & 63 | 128, 8) + result;
                    }
                    result = (code >> bc * 6 | 255 >> significantOnes << significantOnes).toString(2) + result;
                }
                return result;
            },
            getBytesCount: function (code) {
                var ranges = this.ranges;
                for (var i = 0; i < ranges.length; i++) {
                    if (code < ranges[i]) {
                        return i + 1;
                    }
                }
            },
            ranges: [
                128,
                2048,
                65536,
                2097152,
                67108864
            ]
        };
        var QRCodeDataEncoder = function (encoding) {
            if (encoding && encoding.toLowerCase().indexOf('utf_8') >= 0) {
                return new UTF8Encoder();
            } else {
                return new IsoEncoder();
            }
        };
        var encodeData = function (inputString, errorCorrectionLevel, encoding) {
            var encoder = new QRCodeDataEncoder(encoding), encodingResult = encoder.getEncodingResult(inputString, errorCorrectionLevel), version = encodingResult.version, versionInformation = versionsCodewordsInformation[version - 1][errorCorrectionLevel], dataString = padDataString(encodingResult.dataString, versionInformation.totalDataCodewords), blocks = getBlocks(dataString, versionInformation), matrices = initMatrices(version);
            addFinderPatterns(matrices);
            addAlignmentPatterns(matrices, version);
            addTimingFunctions(matrices);
            if (version >= 7) {
                addVersionInformation(matrices, toBitsString(0, 18));
            }
            addFormatInformation(matrices, toBitsString(0, 15));
            fillData(matrices, blocks);
            var minIdx = scoreMaskMatrixes(matrices), optimalMatrix = matrices[minIdx];
            if (version >= 7) {
                addVersionInformation([optimalMatrix], encodeVersionInformation(version));
            }
            var formatString = errorCorrectionPatterns[errorCorrectionLevel] + toBitsString(minIdx, 3);
            addFormatInformation([optimalMatrix], encodeFormatInformation(formatString));
            return optimalMatrix;
        };
        var QRCodeDefaults = {
            DEFAULT_SIZE: 200,
            QUIET_ZONE_LENGTH: 4,
            DEFAULT_ERROR_CORRECTION_LEVEL: 'L',
            DEFAULT_BACKGROUND: '#fff',
            DEFAULT_DARK_MODULE_COLOR: '#000',
            MIN_BASE_UNIT_SIZE: 1
        };
        var QRCode = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.element = $(element);
                that.wrapper = that.element;
                that.element.addClass('k-qrcode');
                that.surfaceWrap = $('<div />').css('position', 'relative').appendTo(this.element);
                that.surface = draw.Surface.create(that.surfaceWrap, { type: that.options.renderAs });
                that.setOptions(options);
            },
            redraw: function () {
                var size = this._getSize();
                this.surfaceWrap.css({
                    width: size,
                    height: size
                });
                this.surface.clear();
                this.createVisual();
                this.surface.draw(this.visual);
            },
            getSize: function () {
                return kendo.dimensions(this.element);
            },
            _resize: function () {
                this.redraw();
            },
            createVisual: function () {
                this.visual = this._render();
            },
            exportVisual: function () {
                return this._render();
            },
            _render: function () {
                var that = this, value = that._value, baseUnit, border = that.options.border || {}, padding = that.options.padding || 0, borderWidth = border.width || 0, quietZoneSize, matrix, size, dataSize, contentSize;
                border.width = borderWidth;
                var visual = new draw.Group();
                if (value) {
                    matrix = encodeData(value, that.options.errorCorrection, that.options.encoding);
                    size = that._getSize();
                    contentSize = size - 2 * (borderWidth + padding);
                    baseUnit = that._calculateBaseUnit(contentSize, matrix.length);
                    dataSize = matrix.length * baseUnit;
                    quietZoneSize = borderWidth + padding + (contentSize - dataSize) / 2;
                    visual.append(that._renderBackground(size, border));
                    visual.append(that._renderMatrix(matrix, baseUnit, quietZoneSize));
                }
                return visual;
            },
            _getSize: function () {
                var that = this, size;
                if (that.options.size) {
                    size = parseInt(that.options.size, 10);
                } else {
                    var element = that.element, min = Math.min(element.width(), element.height());
                    if (min > 0) {
                        size = min;
                    } else {
                        size = QRCodeDefaults.DEFAULT_SIZE;
                    }
                }
                return size;
            },
            _calculateBaseUnit: function (size, matrixSize) {
                var baseUnit = Math.floor(size / matrixSize);
                if (baseUnit < QRCodeDefaults.MIN_BASE_UNIT_SIZE) {
                    throw new Error('Insufficient size.');
                }
                if (baseUnit * matrixSize >= size && baseUnit - 1 >= QRCodeDefaults.MIN_BASE_UNIT_SIZE) {
                    baseUnit--;
                }
                return baseUnit;
            },
            _renderMatrix: function (matrix, baseUnit, quietZoneSize) {
                var path = new draw.MultiPath({
                    fill: { color: this.options.color },
                    stroke: null
                });
                for (var row = 0; row < matrix.length; row++) {
                    var y = quietZoneSize + row * baseUnit;
                    var column = 0;
                    while (column < matrix.length) {
                        while (matrix[row][column] === 0 && column < matrix.length) {
                            column++;
                        }
                        if (column < matrix.length) {
                            var x = column;
                            while (matrix[row][column] == 1) {
                                column++;
                            }
                            var x1 = round(quietZoneSize + x * baseUnit);
                            var y1 = round(y);
                            var x2 = round(quietZoneSize + column * baseUnit);
                            var y2 = round(y + baseUnit);
                            path.moveTo(x1, y1).lineTo(x1, y2).lineTo(x2, y2).lineTo(x2, y1).close();
                        }
                    }
                }
                return path;
            },
            _renderBackground: function (size, border) {
                var box = new Box2D(0, 0, size, size).unpad(border.width / 2);
                return draw.Path.fromRect(box.toRect(), {
                    fill: { color: this.options.background },
                    stroke: {
                        color: border.color,
                        width: border.width
                    }
                });
            },
            setOptions: function (options) {
                var that = this;
                options = options || {};
                that.options = extend(that.options, options);
                if (options.value !== undefined) {
                    that._value = that.options.value + '';
                }
                that.redraw();
            },
            value: function (value) {
                var that = this;
                if (value === undefined) {
                    return that._value;
                }
                that._value = value + '';
                that.redraw();
            },
            options: {
                name: 'QRCode',
                renderAs: 'svg',
                encoding: 'ISO_8859_1',
                value: '',
                errorCorrection: QRCodeDefaults.DEFAULT_ERROR_CORRECTION_LEVEL,
                background: QRCodeDefaults.DEFAULT_BACKGROUND,
                color: QRCodeDefaults.DEFAULT_DARK_MODULE_COLOR,
                size: '',
                padding: 0,
                border: {
                    color: '',
                    width: 0
                }
            }
        });
        dataviz.ExportMixin.extend(QRCode.fn);
        dataviz.ui.plugin(QRCode);
        kendo.deepExtend(dataviz, {
            QRCode: QRCode,
            QRCodeDefaults: QRCodeDefaults,
            QRCodeFunctions: {
                FreeCellVisitor: FreeCellVisitor,
                fillData: fillData,
                padDataString: padDataString,
                generateErrorCodewords: generateErrorCodewords,
                xorPolynomials: xorPolynomials,
                getBlocks: getBlocks,
                multiplyPolynomials: multiplyPolynomials,
                chooseMode: chooseMode,
                getModes: getModes,
                getDataCodewordsCount: getDataCodewordsCount,
                getVersion: getVersion,
                getDataString: getDataString,
                encodeFormatInformation: encodeFormatInformation,
                encodeBCH: encodeBCH,
                dividePolynomials: dividePolynomials,
                initMatrices: initMatrices,
                addFormatInformation: addFormatInformation,
                encodeVersionInformation: encodeVersionInformation,
                addVersionInformation: addVersionInformation,
                addCentricPattern: addCentricPattern,
                addFinderSeparator: addFinderSeparator,
                addFinderPatterns: addFinderPatterns,
                addAlignmentPatterns: addAlignmentPatterns,
                addTimingFunctions: addTimingFunctions,
                scoreMaskMatrixes: scoreMaskMatrixes,
                encodeData: encodeData,
                UTF8Encoder: UTF8Encoder
            },
            QRCodeFields: {
                modes: modeInstances,
                powersOfTwo: powersOfTwo,
                powersOfTwoResult: powersOfTwoResult,
                generatorPolynomials: generatorPolynomials
            }
        });
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/stock/kendo-stock-chart', ['kendo.dataviz.chart'], f);
}(function () {
    (function () {
        window.kendo.dataviz = window.kendo.dataviz || {};
        var dataviz = kendo.dataviz;
        var elementStyles = dataviz.elementStyles;
        var deepExtend = dataviz.deepExtend;
        var toTime = dataviz.toTime;
        var services = dataviz.services;
        var datavizConstants = dataviz.constants;
        var Chart = dataviz.Chart;
        var drawing = kendo.drawing;
        var FadeOutAnimation = drawing.Animation.extend({
            setup: function () {
                this._initialOpacity = parseFloat(elementStyles(this.element, 'opacity').opacity);
            },
            step: function (pos) {
                elementStyles(this.element, { opacity: String(dataviz.interpolateValue(this._initialOpacity, 0, pos)) });
            },
            abort: function () {
                drawing.Animation.fn.abort.call(this);
                elementStyles(this.element, {
                    display: 'none',
                    opacity: String(this._initialOpacity)
                });
            },
            cancel: function () {
                drawing.Animation.fn.abort.call(this);
                elementStyles(this.element, { opacity: String(this._initialOpacity) });
            }
        });
        function createDiv(className, style) {
            var div = document.createElement('div');
            div.className = className;
            if (style) {
                div.style.cssText = style;
            }
            return div;
        }
        var NavigatorHint = dataviz.Class.extend({
            init: function (container, chartService, options) {
                this.options = deepExtend({}, this.options, options);
                this.container = container;
                this.chartService = chartService;
                var padding = elementStyles(container, [
                    'paddingLeft',
                    'paddingTop'
                ]);
                this.chartPadding = {
                    top: padding.paddingTop,
                    left: padding.paddingLeft
                };
                this.createElements();
                container.appendChild(this.element);
            },
            createElements: function () {
                var element = this.element = createDiv('k-navigator-hint', 'display: none; position: absolute; top: 1px; left: 1px;');
                var tooltip = this.tooltip = createDiv('k-tooltip k-chart-tooltip');
                var scroll = this.scroll = createDiv('k-scroll');
                tooltip.innerHTML = '&nbsp;';
                element.appendChild(tooltip);
                element.appendChild(scroll);
            },
            show: function (from, to, bbox) {
                var ref = this;
                var element = ref.element;
                var options = ref.options;
                var scroll = ref.scroll;
                var tooltip = ref.tooltip;
                var middle = dataviz.toDate(toTime(from) + toTime(to - from) / 2);
                var scrollWidth = bbox.width() * 0.4;
                var minPos = bbox.center().x - scrollWidth;
                var maxPos = bbox.center().x;
                var posRange = maxPos - minPos;
                var range = options.max - options.min;
                var scale = posRange / range;
                var offset = middle - options.min;
                var text = this.chartService.intl.format(options.format, from, to);
                this.clearHideTimeout();
                if (!this._visible) {
                    elementStyles(element, {
                        visibility: 'hidden',
                        display: 'block'
                    });
                    this._visible = true;
                }
                if (options.template) {
                    text = services.TemplateService.compile(options.template)({
                        from: from,
                        to: to
                    });
                }
                tooltip.innerHTML = text;
                elementStyles(tooltip, {
                    left: bbox.center().x - tooltip.offsetWidth / 2,
                    top: bbox.y1
                });
                var tooltipStyle = elementStyles(tooltip, [
                    'marginTop',
                    'borderTopWidth',
                    'height'
                ]);
                elementStyles(scroll, {
                    width: scrollWidth,
                    left: minPos + offset * scale,
                    top: bbox.y1 + tooltipStyle.marginTop + tooltipStyle.borderTopWidth + tooltipStyle.height / 2
                });
                elementStyles(element, { visibility: 'visible' });
            },
            clearHideTimeout: function () {
                if (this._hideTimeout) {
                    clearTimeout(this._hideTimeout);
                }
                if (this._hideAnimation) {
                    this._hideAnimation.cancel();
                }
            },
            hide: function () {
                var this$1 = this;
                this.clearHideTimeout();
                this._hideTimeout = setTimeout(function () {
                    this$1._visible = false;
                    this$1._hideAnimation = new FadeOutAnimation(this$1.element);
                    this$1._hideAnimation.setup();
                    this$1._hideAnimation.play();
                }, this.options.hideDelay);
            },
            destroy: function () {
                this.clearHideTimeout();
                if (this.container) {
                    this.container.removeChild(this.element);
                }
                delete this.container;
                delete this.chartService;
                delete this.element;
                delete this.tooltip;
                delete this.scroll;
            }
        });
        dataviz.setDefaultOptions(NavigatorHint, {
            format: '{0:d} - {1:d}',
            hideDelay: 500
        });
        var NAVIGATOR_PANE = '_navigator';
        var NAVIGATOR_AXIS = NAVIGATOR_PANE;
        var constants = {
            NAVIGATOR_AXIS: NAVIGATOR_AXIS,
            NAVIGATOR_PANE: NAVIGATOR_PANE
        };
        var ZOOM_ACCELERATION = 3;
        var Navigator = dataviz.Class.extend({
            init: function (chart) {
                this.chart = chart;
                var options = this.options = deepExtend({}, this.options, chart.options.navigator);
                var select = options.select;
                if (select) {
                    select.from = this.parseDate(select.from);
                    select.to = this.parseDate(select.to);
                }
                if (!dataviz.defined(options.hint.visible)) {
                    options.hint.visible = options.visible;
                }
                var obj;
                this.chartObserver = new dataviz.InstanceObserver(this, (obj = {}, obj[datavizConstants.DRAG] = '_drag', obj[datavizConstants.DRAG_END] = '_dragEnd', obj[datavizConstants.ZOOM] = '_zoom', obj[datavizConstants.ZOOM_END] = '_zoomEnd', obj));
                chart.addObserver(this.chartObserver);
            },
            parseDate: function (value) {
                return dataviz.parseDate(this.chart.chartService.intl, value);
            },
            destroy: function () {
                if (this.chart) {
                    this.chart.removeObserver(this.chartObserver);
                    delete this.chart;
                }
                if (this.selection) {
                    this.selection.destroy();
                    delete this.selection;
                }
                if (this.hint) {
                    this.hint.destroy();
                    delete this.hint;
                }
            },
            redraw: function () {
                this._redrawSelf();
                this.initSelection();
            },
            initSelection: function () {
                var ref = this;
                var chart = ref.chart;
                var options = ref.options;
                var axis = this.mainAxis();
                var ref$1 = axis.range();
                var min = ref$1.min;
                var max = ref$1.max;
                var ref$2 = options.select;
                var from = ref$2.from;
                var to = ref$2.to;
                var mousewheel = ref$2.mousewheel;
                var axisClone = clone(axis);
                var groups = axis.options.categories;
                var selection = this.selection;
                if (groups.length === 0) {
                    return;
                }
                if (selection) {
                    selection.destroy();
                }
                axisClone.box = axis.box;
                selection = this.selection = new dataviz.Selection(chart, axisClone, {
                    min: min,
                    max: max,
                    from: from || min,
                    to: to || max,
                    mousewheel: dataviz.valueOrDefault(mousewheel, { zoom: 'left' }),
                    visible: options.visible
                }, new dataviz.InstanceObserver(this, {
                    selectStart: '_selectStart',
                    select: '_select',
                    selectEnd: '_selectEnd'
                }));
                if (this.hint) {
                    this.hint.destroy();
                }
                if (options.hint.visible) {
                    this.hint = new NavigatorHint(chart.element, chart.chartService, {
                        min: min,
                        max: max,
                        template: options.hint.template,
                        format: options.hint.format
                    });
                }
            },
            setRange: function () {
                var plotArea = this.chart._createPlotArea(true);
                var axis = plotArea.namedCategoryAxes[NAVIGATOR_AXIS];
                var ref = axis.range();
                var min = ref.min;
                var max = ref.max;
                var select = this.options.select || {};
                var from = select.from || min;
                if (from < min) {
                    from = min;
                }
                var to = select.to || max;
                if (to > max) {
                    to = max;
                }
                this.options.select = deepExtend({}, select, {
                    from: from,
                    to: to
                });
                this.filterAxes();
            },
            _redrawSelf: function (silent) {
                var plotArea = this.chart._plotArea;
                if (plotArea) {
                    plotArea.redraw(dataviz.last(plotArea.panes), silent);
                }
            },
            redrawSlaves: function () {
                var chart = this.chart;
                var plotArea = chart._plotArea;
                var slavePanes = plotArea.panes.slice(0, -1);
                plotArea.srcSeries = chart.options.series;
                plotArea.options.categoryAxis = chart.options.categoryAxis;
                plotArea.redraw(slavePanes);
            },
            _drag: function (e) {
                var ref = this;
                var chart = ref.chart;
                var selection = ref.selection;
                var coords = chart._eventCoordinates(e.originalEvent);
                var navigatorAxis = this.mainAxis();
                var naviRange = navigatorAxis.datesRange();
                var inNavigator = navigatorAxis.pane.box.containsPoint(coords);
                var axis = chart._plotArea.categoryAxis;
                var range = e.axisRanges[axis.options.name];
                var select = this.options.select;
                var duration;
                if (!range || inNavigator || !selection) {
                    return;
                }
                if (select.from && select.to) {
                    duration = toTime(select.to) - toTime(select.from);
                } else {
                    duration = toTime(selection.options.to) - toTime(selection.options.from);
                }
                var from = dataviz.toDate(dataviz.limitValue(toTime(range.min), naviRange.min, toTime(naviRange.max) - duration));
                var to = dataviz.toDate(dataviz.limitValue(toTime(from) + duration, toTime(naviRange.min) + duration, naviRange.max));
                this.options.select = {
                    from: from,
                    to: to
                };
                if (this.options.liveDrag) {
                    this.filterAxes();
                    this.redrawSlaves();
                }
                selection.set(from, to);
                this.showHint(from, to);
            },
            _dragEnd: function () {
                this.filterAxes();
                this.filter();
                this.redrawSlaves();
                if (this.hint) {
                    this.hint.hide();
                }
            },
            readSelection: function () {
                var ref = this;
                var ref_selection_options = ref.selection.options;
                var from = ref_selection_options.from;
                var to = ref_selection_options.to;
                var select = ref.options.select;
                select.from = from;
                select.to = to;
            },
            filterAxes: function () {
                var ref = this;
                var select = ref.options.select;
                if (select === void 0) {
                    select = {};
                }
                var chart = ref.chart;
                var allAxes = chart.options.categoryAxis;
                var from = select.from;
                var to = select.to;
                for (var idx = 0; idx < allAxes.length; idx++) {
                    var axis = allAxes[idx];
                    if (axis.pane !== NAVIGATOR_PANE) {
                        axis.min = from;
                        axis.max = to;
                    }
                }
            },
            filter: function () {
                var ref = this;
                var chart = ref.chart;
                var select = ref.options.select;
                if (chart.requiresHandlers(['navigatorFilter'])) {
                    var axisOptions = new dataviz.DateCategoryAxis(deepExtend({ baseUnit: 'fit' }, chart.options.categoryAxis[0], {
                        categories: [
                            select.from,
                            select.to
                        ]
                    }), chart.chartService).options;
                    this.chart.trigger('navigatorFilter', {
                        from: dataviz.addDuration(axisOptions.min, -axisOptions.baseUnitStep, axisOptions.baseUnit),
                        to: dataviz.addDuration(axisOptions.max, axisOptions.baseUnitStep, axisOptions.baseUnit)
                    });
                }
            },
            _zoom: function (e) {
                var ref = this;
                var axis = ref.chart._plotArea.categoryAxis;
                var selection = ref.selection;
                var ref_options = ref.options;
                var select = ref_options.select;
                var liveDrag = ref_options.liveDrag;
                var categories = this.mainAxis().options.categories;
                var delta = e.delta;
                if (!selection) {
                    return;
                }
                var fromIx = dataviz.lteDateIndex(selection.options.from, categories);
                var toIx = dataviz.lteDateIndex(selection.options.to, categories);
                e.originalEvent.preventDefault();
                if (Math.abs(delta) > 1) {
                    delta *= ZOOM_ACCELERATION;
                }
                if (toIx - fromIx > 1) {
                    selection.expand(delta);
                    this.readSelection();
                } else {
                    axis.options.min = select.from;
                    select.from = axis.scaleRange(-e.delta).min;
                }
                if (liveDrag) {
                    this.filterAxes();
                    this.redrawSlaves();
                }
                selection.set(select.from, select.to);
                this.showHint(this.options.select.from, this.options.select.to);
            },
            _zoomEnd: function (e) {
                this._dragEnd(e);
            },
            showHint: function (from, to) {
                var plotArea = this.chart._plotArea;
                if (this.hint) {
                    this.hint.show(from, to, plotArea.backgroundBox());
                }
            },
            _selectStart: function (e) {
                return this.chart._selectStart(e);
            },
            _select: function (e) {
                this.showHint(e.from, e.to);
                return this.chart._select(e);
            },
            _selectEnd: function (e) {
                if (this.hint) {
                    this.hint.hide();
                }
                this.readSelection();
                this.filterAxes();
                this.filter();
                this.redrawSlaves();
                return this.chart._selectEnd(e);
            },
            mainAxis: function () {
                var plotArea = this.chart._plotArea;
                if (plotArea) {
                    return plotArea.namedCategoryAxes[NAVIGATOR_AXIS];
                }
            },
            select: function (from, to) {
                var select = this.options.select;
                if (from && to) {
                    select.from = this.parseDate(from);
                    select.to = this.parseDate(to);
                    this.filterAxes();
                    this.filter();
                    this.redrawSlaves();
                    this.selection.set(from, to);
                }
                return {
                    from: select.from,
                    to: select.to
                };
            }
        });
        Navigator.setup = function (options, themeOptions) {
            if (options === void 0) {
                options = {};
            }
            if (themeOptions === void 0) {
                themeOptions = {};
            }
            if (options.__navi) {
                return;
            }
            options.__navi = true;
            var naviOptions = deepExtend({}, themeOptions.navigator, options.navigator);
            var panes = options.panes = [].concat(options.panes);
            var paneOptions = deepExtend({}, naviOptions.pane, { name: NAVIGATOR_PANE });
            if (!naviOptions.visible) {
                paneOptions.visible = false;
                paneOptions.height = 0.1;
            }
            panes.push(paneOptions);
            Navigator.attachAxes(options, naviOptions);
            Navigator.attachSeries(options, naviOptions, themeOptions);
        };
        Navigator.attachAxes = function (options, naviOptions) {
            var series = naviOptions.series || [];
            var categoryAxes = options.categoryAxis = [].concat(options.categoryAxis);
            var valueAxes = options.valueAxis = [].concat(options.valueAxis);
            var equallySpacedSeries = dataviz.filterSeriesByType(series, datavizConstants.EQUALLY_SPACED_SERIES);
            var justifyAxis = equallySpacedSeries.length === 0;
            var base = deepExtend({
                type: 'date',
                pane: NAVIGATOR_PANE,
                roundToBaseUnit: !justifyAxis,
                justified: justifyAxis,
                _collapse: false,
                majorTicks: { visible: true },
                tooltip: { visible: false },
                labels: { step: 1 },
                autoBind: naviOptions.autoBindElements,
                autoBaseUnitSteps: {
                    minutes: [1],
                    hours: [
                        1,
                        2
                    ],
                    days: [
                        1,
                        2
                    ],
                    weeks: [],
                    months: [1],
                    years: [1]
                }
            });
            var user = naviOptions.categoryAxis;
            categoryAxes.push(deepExtend({}, base, { maxDateGroups: 200 }, user, {
                name: NAVIGATOR_AXIS,
                title: null,
                baseUnit: 'fit',
                baseUnitStep: 'auto',
                labels: { visible: false },
                majorTicks: { visible: false }
            }), deepExtend({}, base, user, {
                name: NAVIGATOR_AXIS + '_labels',
                maxDateGroups: 20,
                baseUnitStep: 'auto',
                plotBands: [],
                autoBaseUnitSteps: { minutes: [] },
                _overlap: true
            }), deepExtend({}, base, user, {
                name: NAVIGATOR_AXIS + '_ticks',
                maxDateGroups: 200,
                majorTicks: { width: 0.5 },
                plotBands: [],
                title: null,
                labels: {
                    visible: false,
                    mirror: true
                },
                _overlap: true
            }));
            valueAxes.push(deepExtend({
                name: NAVIGATOR_AXIS,
                pane: NAVIGATOR_PANE,
                majorGridLines: { visible: false },
                visible: false
            }, naviOptions.valueAxis));
        };
        Navigator.attachSeries = function (options, naviOptions, themeOptions) {
            var series = options.series = options.series || [];
            var navigatorSeries = [].concat(naviOptions.series || []);
            var seriesColors = themeOptions.seriesColors;
            var defaults = naviOptions.seriesDefaults;
            for (var idx = 0; idx < navigatorSeries.length; idx++) {
                series.push(deepExtend({
                    color: seriesColors[idx % seriesColors.length],
                    categoryField: naviOptions.dateField,
                    visibleInLegend: false,
                    tooltip: { visible: false }
                }, defaults, navigatorSeries[idx], {
                    axis: NAVIGATOR_AXIS,
                    categoryAxis: NAVIGATOR_AXIS,
                    autoBind: naviOptions.autoBindElements
                }));
            }
        };
        function ClonedObject() {
        }
        function clone(obj) {
            ClonedObject.prototype = obj;
            return new ClonedObject();
        }
        var AUTO_CATEGORY_WIDTH = 28;
        var StockChart = Chart.extend({
            applyDefaults: function (options, themeOptions) {
                var width = dataviz.elementSize(this.element).width || datavizConstants.DEFAULT_WIDTH;
                var theme = themeOptions;
                var stockDefaults = {
                    seriesDefaults: { categoryField: options.dateField },
                    axisDefaults: {
                        categoryAxis: {
                            name: 'default',
                            majorGridLines: { visible: false },
                            labels: { step: 2 },
                            majorTicks: { visible: false },
                            maxDateGroups: Math.floor(width / AUTO_CATEGORY_WIDTH)
                        }
                    }
                };
                if (theme) {
                    theme = deepExtend({}, theme, stockDefaults);
                }
                Navigator.setup(options, theme);
                Chart.fn.applyDefaults.call(this, options, theme);
            },
            _setElementClass: function (element) {
                dataviz.addClass(element, 'k-chart k-stockchart');
            },
            setOptions: function (options) {
                this.destroyNavigator();
                Chart.fn.setOptions.call(this, options);
            },
            _resize: function () {
                var transitions = this.options.transitions;
                this.options.transitions = false;
                this._fullRedraw();
                this.options.transitions = transitions;
            },
            _redraw: function () {
                var navigator = this.navigator;
                if (!this._dirty() && navigator && navigator.options.partialRedraw) {
                    navigator.redrawSlaves();
                } else {
                    this._fullRedraw();
                }
            },
            _dirty: function () {
                var options = this.options;
                var series = [].concat(options.series, options.navigator.series);
                var seriesCount = dataviz.grep(series, function (s) {
                    return s && s.visible;
                }).length;
                var dirty = this._seriesCount !== seriesCount;
                this._seriesCount = seriesCount;
                return dirty;
            },
            _fullRedraw: function () {
                var navigator = this.navigator;
                if (!navigator) {
                    navigator = this.navigator = new Navigator(this);
                    this.trigger('navigatorCreated', { navigator: navigator });
                }
                navigator.setRange();
                Chart.fn._redraw.call(this);
                navigator.initSelection();
            },
            _trackSharedTooltip: function (coords) {
                var plotArea = this._plotArea;
                var pane = plotArea.paneByPoint(coords);
                if (pane && pane.options.name === NAVIGATOR_PANE) {
                    this._unsetActivePoint();
                } else {
                    Chart.fn._trackSharedTooltip.call(this, coords);
                }
            },
            bindCategories: function () {
                Chart.fn.bindCategories.call(this);
                this.copyNavigatorCategories();
            },
            copyNavigatorCategories: function () {
                var definitions = [].concat(this.options.categoryAxis);
                var categories;
                for (var axisIx = 0; axisIx < definitions.length; axisIx++) {
                    var axis = definitions[axisIx];
                    if (axis.name === NAVIGATOR_AXIS) {
                        categories = axis.categories;
                    } else if (categories && axis.pane === NAVIGATOR_PANE) {
                        axis.categories = categories;
                    }
                }
            },
            destroyNavigator: function () {
                if (this.navigator) {
                    this.navigator.destroy();
                    this.navigator = null;
                }
            },
            destroy: function () {
                this.destroyNavigator();
                Chart.fn.destroy.call(this);
            },
            _stopDragEvent: function (e) {
                var coords = this._eventCoordinates(e);
                var pane = this._plotArea.paneByPoint(coords);
                return Chart.fn._stopDragEvent.call(this, e) || pane && pane.options.name === NAVIGATOR_PANE;
            }
        });
        dataviz.setDefaultOptions(StockChart, {
            dateField: 'date',
            axisDefaults: {
                categoryAxis: {
                    type: 'date',
                    baseUnit: 'fit',
                    justified: true
                },
                valueAxis: {
                    narrowRange: true,
                    labels: { format: 'C' }
                }
            },
            navigator: {
                select: {},
                seriesDefaults: {
                    markers: { visible: false },
                    tooltip: { visible: true },
                    line: { width: 2 }
                },
                hint: {},
                visible: true
            },
            tooltip: { visible: true },
            legend: { visible: false }
        });
        kendo.deepExtend(kendo.dataviz, {
            constants: constants,
            Navigator: Navigator,
            NavigatorHint: NavigatorHint,
            StockChart: StockChart
        });
    }());
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/stock/stock-chart', ['dataviz/stock/kendo-stock-chart'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo;
        var dataviz = kendo.dataviz;
        var ChartInstanceObserver = dataviz.ChartInstanceObserver;
        var Chart = dataviz.ui.Chart;
        var KendoStockChart = dataviz.StockChart;
        var constants = dataviz.constants;
        var NAVIGATOR_AXIS = constants.NAVIGATOR_AXIS;
        var NAVIGATOR_PANE = constants.NAVIGATOR_PANE;
        var deepExtend = kendo.deepExtend;
        var defined = dataviz.defined;
        var proxy = $.proxy;
        var CHANGE = 'change';
        var StockInstanceObserver = ChartInstanceObserver.extend({
            handlerMap: {
                navigatorFilter: '_onNavigatorFilter',
                navigatorCreated: '_onNavigatorCreated'
            }
        });
        var StockChart = Chart.extend({
            options: {
                name: 'StockChart',
                dateField: 'date',
                axisDefaults: {
                    categoryAxis: {
                        type: 'date',
                        baseUnit: 'fit',
                        justified: true
                    },
                    valueAxis: {
                        narrowRange: true,
                        labels: { format: 'C' }
                    }
                },
                navigator: {
                    select: {},
                    seriesDefaults: {
                        markers: { visible: false },
                        tooltip: {
                            visible: true,
                            template: '#= kendo.toString(category, \'d\') #'
                        },
                        line: { width: 2 }
                    },
                    hint: {},
                    visible: true
                },
                tooltip: { visible: true },
                legend: { visible: false }
            },
            _createChart: function (options, themeOptions) {
                this._initNavigatorOptions(options);
                this._instance = new KendoStockChart(this.element[0], options, themeOptions, {
                    observer: new StockInstanceObserver(this),
                    sender: this
                });
            },
            _initNavigatorOptions: function (options) {
                var navigatorOptions = options.navigator || {};
                var support = kendo.support;
                var isTouch = support.touch;
                var isFirefox = support.browser.mozilla;
                deepExtend(navigatorOptions, {
                    autoBindElements: !navigatorOptions.dataSource,
                    partialRedraw: navigatorOptions.dataSource,
                    liveDrag: !isTouch && !isFirefox
                });
            },
            _initDataSource: function (userOptions) {
                var options = userOptions || {}, dataSource = options.dataSource, hasServerFiltering = dataSource && dataSource.serverFiltering, mainAxis = [].concat(options.categoryAxis)[0], naviOptions = options.navigator || {}, select = naviOptions.select, hasSelect = select && select.from && select.to;
                if (hasServerFiltering && hasSelect) {
                    var filter = [].concat(dataSource.filter || []);
                    var from = kendo.parseDate(select.from);
                    var to = kendo.parseDate(select.to);
                    var dummyAxis = new dataviz.DateCategoryAxis(deepExtend({ baseUnit: 'fit' }, mainAxis, {
                        categories: [
                            from,
                            to
                        ]
                    }), kendo);
                    dataSource.filter = buildFilter(dummyAxis.range().min, to).concat(filter);
                }
                Chart.fn._initDataSource.call(this, userOptions);
            },
            _onNavigatorCreated: function (e) {
                this._instance = e.sender;
                this.options = e.sender.options;
                this._navigator = this.navigator = e.navigator;
                this._initNavigatorDataSource();
            },
            _initNavigatorDataSource: function () {
                var navigatorOptions = this.options.navigator;
                var autoBind = navigatorOptions.autoBind;
                var dsOptions = navigatorOptions.dataSource;
                if (dsOptions) {
                    this._navigatorDataChangedHandler = this._navigatorDataChangedHandler || proxy(this._onNavigatorDataChanged, this);
                    this._navigatorDataSource = kendo.data.DataSource.create(dsOptions).bind(CHANGE, this._navigatorDataChangedHandler);
                    if (!defined(autoBind)) {
                        autoBind = this.options.autoBind;
                    }
                    if (autoBind) {
                        this._navigatorDataSource.fetch();
                    }
                }
            },
            _onNavigatorDataChanged: function () {
                var chart = this, instance = chart._instance, series = chart.options.series, seriesIx, seriesLength = series.length, categoryAxes = chart.options.categoryAxis, axisIx, axesLength = categoryAxes.length, data = chart._navigatorDataSource.view(), currentSeries, currentAxis, naviCategories;
                for (seriesIx = 0; seriesIx < seriesLength; seriesIx++) {
                    currentSeries = series[seriesIx];
                    if (currentSeries.axis == NAVIGATOR_AXIS && chart._isBindable(currentSeries)) {
                        currentSeries.data = data;
                    }
                }
                for (axisIx = 0; axisIx < axesLength; axisIx++) {
                    currentAxis = categoryAxes[axisIx];
                    if (currentAxis.pane == NAVIGATOR_PANE) {
                        if (currentAxis.name == NAVIGATOR_AXIS) {
                            chart._bindCategoryAxis(currentAxis, data, axisIx);
                            naviCategories = currentAxis.categories;
                        } else {
                            currentAxis.categories = naviCategories;
                        }
                    }
                }
                if (instance._model) {
                    var navigator = this.navigator;
                    navigator.redraw();
                    navigator.setRange();
                    if (!chart.options.dataSource || chart.options.dataSource && chart._dataBound) {
                        navigator.redrawSlaves();
                    }
                }
            },
            _bindCategories: function () {
                Chart.fn._bindCategories.call(this);
                if (this._instance) {
                    this._instance.copyNavigatorCategories();
                }
            },
            _onDataChanged: function () {
                Chart.fn._onDataChanged.call(this);
                this._dataBound = true;
            },
            setOptions: function (options) {
                this._removeNavigatorDataSource();
                this._initNavigatorOptions(options);
                this._instance.destroyNavigator();
                Chart.fn.setOptions.call(this, options);
            },
            _onNavigatorFilter: function (e) {
                this.dataSource.filter(buildFilter(e.from, e.to));
            },
            requiresHandlers: function (names) {
                if (dataviz.inArray('navigatorFilter', names)) {
                    var dataSource = this.dataSource;
                    var hasServerFiltering = dataSource && dataSource.options.serverFiltering;
                    return hasServerFiltering && this.options.navigator.dataSource;
                }
                return Chart.fn.requiresHandlers.call(this, names);
            },
            _removeNavigatorDataSource: function () {
                var navigatorDataSource = this._navigatorDataSource;
                if (navigatorDataSource) {
                    navigatorDataSource.unbind(CHANGE, this._navigatorDataChangedHandler);
                    delete this._navigatorDataSource;
                }
            },
            destroy: function () {
                Chart.fn.destroy.call(this);
                this._removeNavigatorDataSource();
            }
        });
        dataviz.ui.plugin(StockChart);
        function buildFilter(from, to) {
            return [
                {
                    field: 'Date',
                    operator: 'gte',
                    value: from
                },
                {
                    field: 'Date',
                    operator: 'lt',
                    value: to
                }
            ];
        }
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.stock', [
        'dataviz/stock/kendo-stock-chart',
        'dataviz/stock/stock-chart'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.stockchart',
        name: 'StockChart',
        category: 'dataviz',
        description: 'StockChart widget and associated financial series.',
        depends: ['dataviz.chart']
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/sparkline/kendo-sparkline', ['kendo.dataviz.chart'], f);
}(function () {
    (function () {
        window.kendo.dataviz = window.kendo.dataviz || {};
        var dataviz = kendo.dataviz;
        var constants = dataviz.constants;
        var Chart = dataviz.Chart;
        var elementSize = dataviz.elementSize;
        var deepExtend = dataviz.deepExtend;
        var TOP_OFFSET = -2;
        var SharedTooltip$1 = dataviz.SharedTooltip.extend({
            _slotAnchor: function (coords, slot) {
                var axis = this.plotArea.categoryAxis;
                var vertical = axis.options.vertical;
                var align = vertical ? {
                    horizontal: 'left',
                    vertical: 'center'
                } : {
                    horizontal: 'center',
                    vertical: 'bottom'
                };
                var point;
                if (vertical) {
                    point = new dataviz.Point(this.plotArea.box.x2, slot.center().y);
                } else {
                    point = new dataviz.Point(slot.center().x, TOP_OFFSET);
                }
                return {
                    point: point,
                    align: align
                };
            },
            _defaultAnchor: function (point, slot) {
                return this._slotAnchor({}, slot);
            }
        });
        var DEAULT_BAR_WIDTH = 150;
        var DEAULT_BULLET_WIDTH = 150;
        var NO_CROSSHAIR = [
            constants.BAR,
            constants.BULLET
        ];
        function hide(children) {
            var state = [];
            for (var idx = 0; idx < children.length; idx++) {
                var child = children[idx];
                state[idx] = child.style.display;
                child.style.display = 'none';
            }
            return state;
        }
        function show(children, state) {
            for (var idx = 0; idx < children.length; idx++) {
                children[idx].style.display = state[idx];
            }
        }
        function wrapNumber(value) {
            return dataviz.isNumber(value) ? [value] : value;
        }
        var Sparkline = Chart.extend({
            _setElementClass: function (element) {
                dataviz.addClass(element, 'k-sparkline');
            },
            _initElement: function (element) {
                Chart.fn._initElement.call(this, element);
                this._initialWidth = Math.floor(elementSize(element).width);
            },
            _resize: function () {
                var element = this.element;
                var state = hide(element.childNodes);
                this._initialWidth = Math.floor(elementSize(element).width);
                show(element.childNodes, state);
                Chart.fn._resize.call(this);
            },
            _modelOptions: function () {
                var chartOptions = this.options;
                var stage = this._surfaceWrap();
                var displayState = hide(stage.childNodes);
                var space = document.createElement('span');
                space.innerHTML = '&nbsp;';
                stage.appendChild(space);
                var options = deepExtend({
                    width: this._autoWidth,
                    height: elementSize(stage).height,
                    transitions: chartOptions.transitions
                }, chartOptions.chartArea, {
                    inline: true,
                    align: false
                });
                elementSize(stage, {
                    width: options.width,
                    height: options.height
                });
                stage.removeChild(space);
                show(stage.childNodes, displayState);
                this.surface.resize();
                return options;
            },
            _surfaceWrap: function () {
                if (!this.stage) {
                    var stage = this.stage = document.createElement('span');
                    this.element.appendChild(stage);
                }
                return this.stage;
            },
            _createPlotArea: function (skipSeries) {
                var plotArea = Chart.fn._createPlotArea.call(this, skipSeries);
                this._autoWidth = this._initialWidth || this._calculateWidth(plotArea);
                return plotArea;
            },
            _calculateWidth: function (plotArea) {
                var options = this.options;
                var margin = dataviz.getSpacing(options.chartArea.margin);
                var charts = plotArea.charts;
                var stage = this._surfaceWrap();
                var total = 0;
                for (var i = 0; i < charts.length; i++) {
                    var currentChart = charts[i];
                    var firstSeries = (currentChart.options.series || [])[0];
                    if (!firstSeries) {
                        continue;
                    }
                    if (firstSeries.type === constants.BAR) {
                        return DEAULT_BAR_WIDTH;
                    }
                    if (firstSeries.type === constants.BULLET) {
                        return DEAULT_BULLET_WIDTH;
                    }
                    if (firstSeries.type === constants.PIE) {
                        return elementSize(stage).height;
                    }
                    var categoryAxis = currentChart.categoryAxis;
                    if (categoryAxis) {
                        var pointsCount = categoryAxis.options.categories.length * (!currentChart.options.isStacked && dataviz.inArray(firstSeries.type, [
                            constants.COLUMN,
                            constants.VERTICAL_BULLET
                        ]) ? currentChart.seriesOptions.length : 1);
                        total = Math.max(total, pointsCount);
                    }
                }
                var size = total * options.pointWidth;
                if (size > 0) {
                    size += margin.left + margin.right;
                }
                return size;
            },
            _createSharedTooltip: function (options) {
                return new SharedTooltip$1(this._plotArea, options);
            }
        });
        Sparkline.normalizeOptions = function (userOptions) {
            var options = wrapNumber(userOptions);
            if (dataviz.isArray(options)) {
                options = { seriesDefaults: { data: options } };
            } else {
                options = deepExtend({}, options);
            }
            if (!options.series) {
                options.series = [{ data: wrapNumber(options.data) }];
            }
            deepExtend(options, { seriesDefaults: { type: options.type } });
            if (dataviz.inArray(options.series[0].type, NO_CROSSHAIR) || dataviz.inArray(options.seriesDefaults.type, NO_CROSSHAIR)) {
                options = deepExtend({}, { categoryAxis: { crosshair: { visible: false } } }, options);
            }
            return options;
        };
        dataviz.setDefaultOptions(Sparkline, {
            chartArea: { margin: 2 },
            axisDefaults: {
                visible: false,
                majorGridLines: { visible: false },
                valueAxis: { narrowRange: true }
            },
            seriesDefaults: {
                type: 'line',
                area: { line: { width: 0.5 } },
                bar: { stack: true },
                padding: 2,
                width: 0.5,
                overlay: { gradient: null },
                highlight: { visible: false },
                border: { width: 0 },
                markers: {
                    size: 2,
                    visible: false
                }
            },
            tooltip: {
                visible: true,
                shared: true
            },
            categoryAxis: {
                crosshair: {
                    visible: true,
                    tooltip: { visible: false }
                }
            },
            legend: { visible: false },
            transitions: false,
            pointWidth: 5,
            panes: [{ clip: false }]
        });
        kendo.deepExtend(kendo.dataviz, { Sparkline: Sparkline });
    }());
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/sparkline/sparkline', ['dataviz/sparkline/kendo-sparkline'], f);
}(function () {
    (function () {
        var dataviz = kendo.dataviz;
        var Chart = dataviz.ui.Chart;
        var KendoSparkline = dataviz.Sparkline;
        var ChartInstanceObserver = dataviz.ChartInstanceObserver;
        var Sparkline = Chart.extend({
            init: function (element, userOptions) {
                var options = userOptions;
                if (options instanceof kendo.data.ObservableArray) {
                    options = { seriesDefaults: { data: options } };
                }
                Chart.fn.init.call(this, element, KendoSparkline.normalizeOptions(options));
            },
            _createChart: function (options, themeOptions) {
                this._instance = new KendoSparkline(this.element[0], options, themeOptions, {
                    observer: new ChartInstanceObserver(this),
                    sender: this
                });
            },
            _createTooltip: function () {
                return new SparklineTooltip(this.element, this.options.tooltip);
            },
            options: {
                name: 'Sparkline',
                chartArea: { margin: 2 },
                axisDefaults: {
                    visible: false,
                    majorGridLines: { visible: false },
                    valueAxis: { narrowRange: true }
                },
                seriesDefaults: {
                    type: 'line',
                    area: { line: { width: 0.5 } },
                    bar: { stack: true },
                    padding: 2,
                    width: 0.5,
                    overlay: { gradient: null },
                    highlight: { visible: false },
                    border: { width: 0 },
                    markers: {
                        size: 2,
                        visible: false
                    }
                },
                tooltip: {
                    visible: true,
                    shared: true
                },
                categoryAxis: {
                    crosshair: {
                        visible: true,
                        tooltip: { visible: false }
                    }
                },
                legend: { visible: false },
                transitions: false,
                pointWidth: 5,
                panes: [{ clip: false }]
            }
        });
        dataviz.ui.plugin(Sparkline);
        var SparklineTooltip = dataviz.Tooltip.extend({
            options: { animation: { duration: 0 } },
            _hideElement: function () {
                if (this.element) {
                    this.element.hide().remove();
                }
            }
        });
        dataviz.SparklineTooltip = SparklineTooltip;
    }());
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.sparkline', [
        'dataviz/sparkline/kendo-sparkline',
        'dataviz/sparkline/sparkline'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.sparkline',
        name: 'Sparkline',
        category: 'dataviz',
        description: 'Sparkline widgets.',
        depends: ['dataviz.chart']
    };
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/location', [
        'kendo.drawing',
        'util/main'
    ], f);
}(function () {
    (function ($, undefined) {
        var math = Math, abs = math.abs, atan = math.atan, atan2 = math.atan2, cos = math.cos, max = math.max, min = math.min, sin = math.sin, tan = math.tan, kendo = window.kendo, Class = kendo.Class, dataviz = kendo.dataviz, deepExtend = kendo.deepExtend, util = kendo.drawing.util, defined = util.defined, deg = util.deg, rad = util.rad, round = util.round, valueOrDefault = util.valueOrDefault, sqr = kendo.util.sqr;
        var Location = Class.extend({
            init: function (lat, lng) {
                if (arguments.length === 1) {
                    this.lat = lat[0];
                    this.lng = lat[1];
                } else {
                    this.lat = lat;
                    this.lng = lng;
                }
            },
            DISTANCE_ITERATIONS: 100,
            DISTANCE_CONVERGENCE: 1e-12,
            DISTANCE_PRECISION: 2,
            FORMAT: '{0:N6},{1:N6}',
            toArray: function () {
                return [
                    this.lat,
                    this.lng
                ];
            },
            equals: function (loc) {
                return loc && loc.lat === this.lat && loc.lng === this.lng;
            },
            clone: function () {
                return new Location(this.lat, this.lng);
            },
            round: function (precision) {
                this.lng = round(this.lng, precision);
                this.lat = round(this.lat, precision);
                return this;
            },
            wrap: function () {
                this.lng = this.lng % 180;
                this.lat = this.lat % 90;
                return this;
            },
            distanceTo: function (dest, datum) {
                return this.greatCircleTo(dest, datum).distance;
            },
            destination: function (distance, bearing, datum) {
                bearing = rad(bearing);
                datum = datum || dataviz.map.datums.WGS84;
                var fromLat = rad(this.lat);
                var fromLng = rad(this.lng);
                var dToR = distance / kendo.dataviz.map.datums.WGS84.a;
                var lat = math.asin(sin(fromLat) * cos(dToR) + cos(fromLat) * sin(dToR) * cos(bearing));
                var lng = fromLng + atan2(sin(bearing) * sin(dToR) * cos(fromLat), cos(dToR) - sin(fromLat) * sin(lat));
                return new Location(deg(lat), deg(lng));
            },
            greatCircleTo: function (dest, datum) {
                dest = Location.create(dest);
                datum = datum || dataviz.map.datums.WGS84;
                if (!dest || this.clone().round(8).equals(dest.clone().round(8))) {
                    return {
                        distance: 0,
                        azimuthFrom: 0,
                        azimuthTo: 0
                    };
                }
                var a = datum.a;
                var b = datum.b;
                var f = datum.f;
                var L = rad(dest.lng - this.lng);
                var U1 = atan((1 - f) * tan(rad(this.lat)));
                var sinU1 = sin(U1);
                var cosU1 = cos(U1);
                var U2 = atan((1 - f) * tan(rad(dest.lat)));
                var sinU2 = sin(U2);
                var cosU2 = cos(U2);
                var lambda = L;
                var prevLambda;
                var i = this.DISTANCE_ITERATIONS;
                var converged = false;
                var sinLambda;
                var cosLambda;
                var sino;
                var cosA2;
                var coso;
                var cos2om;
                var sigma;
                while (!converged && i-- > 0) {
                    sinLambda = sin(lambda);
                    cosLambda = cos(lambda);
                    sino = math.sqrt(sqr(cosU2 * sinLambda) + sqr(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
                    coso = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
                    sigma = atan2(sino, coso);
                    var sinA = cosU1 * cosU2 * sinLambda / sino;
                    cosA2 = 1 - sqr(sinA);
                    cos2om = 0;
                    if (cosA2 !== 0) {
                        cos2om = coso - 2 * sinU1 * sinU2 / cosA2;
                    }
                    prevLambda = lambda;
                    var C = f / 16 * cosA2 * (4 + f * (4 - 3 * cosA2));
                    lambda = L + (1 - C) * f * sinA * (sigma + C * sino * (cos2om + C * coso * (-1 + 2 * sqr(cos2om))));
                    converged = abs(lambda - prevLambda) <= this.DISTANCE_CONVERGENCE;
                }
                var u2 = cosA2 * (sqr(a) - sqr(b)) / sqr(b);
                var A = 1 + u2 / 16384 * (4096 + u2 * (-768 + u2 * (320 - 175 * u2)));
                var B = u2 / 1024 * (256 + u2 * (-128 + u2 * (74 - 47 * u2)));
                var deltao = B * sino * (cos2om + B / 4 * (coso * (-1 + 2 * sqr(cos2om)) - B / 6 * cos2om * (-3 + 4 * sqr(sino)) * (-3 + 4 * sqr(cos2om))));
                var azimuthFrom = atan2(cosU2 * sinLambda, cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
                var azimuthTo = atan2(cosU1 * sinLambda, -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
                return {
                    distance: round(b * A * (sigma - deltao), this.DISTANCE_PRECISION),
                    azimuthFrom: deg(azimuthFrom),
                    azimuthTo: deg(azimuthTo)
                };
            }
        });
        Location.fn.toString = function () {
            return kendo.format(this.FORMAT, this.lat, this.lng);
        };
        Location.fromLngLat = function (ll) {
            return new Location(ll[1], ll[0]);
        };
        Location.fromLatLng = function (ll) {
            return new Location(ll[0], ll[1]);
        };
        Location.create = function (a, b) {
            if (defined(a)) {
                if (a instanceof Location) {
                    return a.clone();
                } else if (arguments.length === 1 && a.length === 2) {
                    return Location.fromLatLng(a);
                } else {
                    return new Location(a, b);
                }
            }
        };
        var Extent = Class.extend({
            init: function (nw, se) {
                nw = Location.create(nw);
                se = Location.create(se);
                if (nw.lng + 180 > se.lng + 180 && nw.lat + 90 < se.lat + 90) {
                    this.se = nw;
                    this.nw = se;
                } else {
                    this.se = se;
                    this.nw = nw;
                }
            },
            contains: function (loc) {
                var nw = this.nw, se = this.se, lng = valueOrDefault(loc.lng, loc[1]), lat = valueOrDefault(loc.lat, loc[0]);
                return loc && lng + 180 >= nw.lng + 180 && lng + 180 <= se.lng + 180 && lat + 90 >= se.lat + 90 && lat + 90 <= nw.lat + 90;
            },
            center: function () {
                var nw = this.nw;
                var se = this.se;
                var lng = nw.lng + (se.lng - nw.lng) / 2;
                var lat = nw.lat + (se.lat - nw.lat) / 2;
                return new Location(lat, lng);
            },
            containsAny: function (locs) {
                var result = false;
                for (var i = 0; i < locs.length; i++) {
                    result = result || this.contains(locs[i]);
                }
                return result;
            },
            include: function (loc) {
                var nw = this.nw, se = this.se, lng = valueOrDefault(loc.lng, loc[1]), lat = valueOrDefault(loc.lat, loc[0]);
                nw.lng = min(nw.lng, lng);
                nw.lat = max(nw.lat, lat);
                se.lng = max(se.lng, lng);
                se.lat = min(se.lat, lat);
            },
            includeAll: function (locs) {
                for (var i = 0; i < locs.length; i++) {
                    this.include(locs[i]);
                }
            },
            edges: function () {
                var nw = this.nw, se = this.se;
                return {
                    nw: this.nw,
                    ne: new Location(nw.lat, se.lng),
                    se: this.se,
                    sw: new Location(se.lat, nw.lng)
                };
            },
            toArray: function () {
                var nw = this.nw, se = this.se;
                return [
                    nw,
                    new Location(nw.lat, se.lng),
                    se,
                    new Location(se.lat, nw.lng)
                ];
            },
            overlaps: function (extent) {
                return this.containsAny(extent.toArray()) || extent.containsAny(this.toArray());
            }
        });
        Extent.World = new Extent([
            90,
            -180
        ], [
            -90,
            180
        ]);
        Extent.create = function (a, b) {
            if (a instanceof Extent) {
                return a;
            } else if (a && b) {
                return new Extent(a, b);
            } else if (a && a.length === 4 && !b) {
                return new Extent([
                    a[0],
                    a[1]
                ], [
                    a[2],
                    a[3]
                ]);
            }
        };
        deepExtend(dataviz, {
            map: {
                Extent: Extent,
                Location: Location
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/attribution', ['kendo.drawing'], f);
}(function () {
    (function () {
        var kendo = window.kendo, Widget = kendo.ui.Widget, template = kendo.template, util = kendo.drawing.util, valueOrDefault = util.valueOrDefault, defined = util.defined;
        var Attribution = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._initOptions(options);
                this.items = [];
                this.element.addClass('k-widget k-attribution');
            },
            options: {
                name: 'Attribution',
                separator: '&nbsp;|&nbsp;',
                itemTemplate: '#= text #'
            },
            filter: function (extent, zoom) {
                this._extent = extent;
                this._zoom = zoom;
                this._render();
            },
            add: function (item) {
                if (defined(item)) {
                    if (typeof item === 'string') {
                        item = { text: item };
                    }
                    this.items.push(item);
                    this._render();
                }
            },
            remove: function (text) {
                var result = [];
                for (var i = 0; i < this.items.length; i++) {
                    var item = this.items[i];
                    if (item.text !== text) {
                        result.push(item);
                    }
                }
                this.items = result;
                this._render();
            },
            clear: function () {
                this.items = [];
                this.element.empty();
            },
            _render: function () {
                var result = [];
                var itemTemplate = template(this.options.itemTemplate);
                for (var i = 0; i < this.items.length; i++) {
                    var item = this.items[i];
                    var text = this._itemText(item);
                    if (text !== '') {
                        result.push(itemTemplate({ text: text }));
                    }
                }
                if (result.length > 0) {
                    this.element.empty().append(result.join(this.options.separator)).show();
                } else {
                    this.element.hide();
                }
            },
            _itemText: function (item) {
                var text = '';
                var inZoomLevel = this._inZoomLevel(item.minZoom, item.maxZoom);
                var inArea = this._inArea(item.extent);
                if (inZoomLevel && inArea) {
                    text += item.text;
                }
                return text;
            },
            _inZoomLevel: function (min, max) {
                var result = true;
                min = valueOrDefault(min, -Number.MAX_VALUE);
                max = valueOrDefault(max, Number.MAX_VALUE);
                result = this._zoom > min && this._zoom < max;
                return result;
            },
            _inArea: function (area) {
                var result = true;
                if (area) {
                    result = area.contains(this._extent);
                }
                return result;
            }
        });
        kendo.dataviz.ui.plugin(Attribution);
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/navigator', ['kendo.core'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo;
        var Widget = kendo.ui.Widget;
        var keys = kendo.keys;
        var proxy = $.proxy;
        var NS = '.kendoNavigator';
        function button(dir) {
            return kendo.format('<button class="k-button k-navigator-{0}" aria-label="move {0}">' + '<span class="k-icon k-i-arrow-60-{0}"/>' + '</button>', dir);
        }
        var BUTTONS = button('up') + button('right') + button('down') + button('left');
        var Navigator = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._initOptions(options);
                this.element.addClass('k-widget k-header k-shadow k-navigator').append(BUTTONS).on('click' + NS, '.k-button', proxy(this, '_click'));
                var parentElement = this.element.parent().closest('[' + kendo.attr('role') + ']');
                this._keyroot = parentElement.length > 0 ? parentElement : this.element;
                this._tabindex(this._keyroot);
                this._keydown = proxy(this._keydown, this);
                this._keyroot.on('keydown', this._keydown);
            },
            options: {
                name: 'Navigator',
                panStep: 1
            },
            events: ['pan'],
            dispose: function () {
                this._keyroot.off('keydown', this._keydown);
            },
            _pan: function (x, y) {
                var panStep = this.options.panStep;
                this.trigger('pan', {
                    x: x * panStep,
                    y: y * panStep
                });
            },
            _click: function (e) {
                var x = 0;
                var y = 0;
                var button = $(e.currentTarget);
                if (button.is('.k-navigator-up')) {
                    y = 1;
                } else if (button.is('.k-navigator-down')) {
                    y = -1;
                } else if (button.is('.k-navigator-right')) {
                    x = 1;
                } else if (button.is('.k-navigator-left')) {
                    x = -1;
                }
                this._pan(x, y);
                e.preventDefault();
            },
            _keydown: function (e) {
                switch (e.which) {
                case keys.UP:
                    this._pan(0, 1);
                    e.preventDefault();
                    break;
                case keys.DOWN:
                    this._pan(0, -1);
                    e.preventDefault();
                    break;
                case keys.RIGHT:
                    this._pan(1, 0);
                    e.preventDefault();
                    break;
                case keys.LEFT:
                    this._pan(-1, 0);
                    e.preventDefault();
                    break;
                }
            }
        });
        kendo.dataviz.ui.plugin(Navigator);
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/zoom', ['kendo.core'], f);
}(function () {
    (function ($) {
        var kendo = window.kendo;
        var Widget = kendo.ui.Widget;
        var keys = kendo.keys;
        var proxy = $.proxy;
        function button(dir, iconClass) {
            return kendo.format('<button class="k-button k-zoom-{0}" title="zoom-{0}" aria-label="zoom-{0}"><span class="k-icon {1}"></span></button>', dir, iconClass);
        }
        var NS = '.kendoZoomControl';
        var BUTTONS = button('in', 'k-i-plus') + button('out', 'k-i-minus');
        var PLUS = 187;
        var MINUS = 189;
        var FF_PLUS = 61;
        var FF_MINUS = 173;
        var ZoomControl = Widget.extend({
            init: function (element, options) {
                Widget.fn.init.call(this, element, options);
                this._initOptions(options);
                this.element.addClass('k-widget k-zoom-control k-button-wrap k-buttons-horizontal k-button-group k-group-horizontal').append(BUTTONS).on('click' + NS, '.k-button', proxy(this, '_click'));
                var parentElement = this.element.parent().closest('[' + kendo.attr('role') + ']');
                this._keyroot = parentElement.length > 0 ? parentElement : this.element;
                this._tabindex(this._keyroot);
                this._keydown = proxy(this._keydown, this);
                this._keyroot.on('keydown', this._keydown);
            },
            options: {
                name: 'ZoomControl',
                zoomStep: 1
            },
            events: ['change'],
            _change: function (dir) {
                var zoomStep = this.options.zoomStep;
                this.trigger('change', { delta: dir * zoomStep });
            },
            _click: function (e) {
                var button = $(e.currentTarget);
                var dir = 1;
                if (button.is('.k-zoom-out')) {
                    dir = -1;
                }
                this._change(dir);
                e.preventDefault();
            },
            _keydown: function (e) {
                switch (e.which) {
                case keys.NUMPAD_PLUS:
                case PLUS:
                case FF_PLUS:
                    this._change(1);
                    break;
                case keys.NUMPAD_MINUS:
                case MINUS:
                case FF_MINUS:
                    this._change(-1);
                    break;
                }
            }
        });
        kendo.dataviz.ui.plugin(ZoomControl);
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/crs', [
        'dataviz/map/location',
        'kendo.drawing'
    ], f);
}(function () {
    (function ($, undefined) {
        var math = Math, atan = math.atan, exp = math.exp, pow = math.pow, sin = math.sin, log = math.log, tan = math.tan, kendo = window.kendo, Class = kendo.Class, dataviz = kendo.dataviz, deepExtend = kendo.deepExtend, g = kendo.geometry, Point = g.Point, map = dataviz.map, Location = map.Location, util = kendo.drawing.util, rad = util.rad, deg = util.deg, limit = util.limitValue;
        var PI = math.PI, PI_DIV_2 = PI / 2, PI_DIV_4 = PI / 4, DEG_TO_RAD = PI / 180;
        var WGS84 = {
            a: 6378137,
            b: 6356752.314245179,
            f: 0.0033528106647474805,
            e: 0.08181919084262149
        };
        var Mercator = Class.extend({
            init: function (options) {
                this._initOptions(options);
            },
            MAX_LNG: 180,
            MAX_LAT: 85.0840590501,
            INVERSE_ITERATIONS: 15,
            INVERSE_CONVERGENCE: 1e-12,
            options: {
                centralMeridian: 0,
                datum: WGS84
            },
            forward: function (loc, clamp) {
                var proj = this, options = proj.options, datum = options.datum, r = datum.a, lng0 = options.centralMeridian, lat = limit(loc.lat, -proj.MAX_LAT, proj.MAX_LAT), lng = clamp ? limit(loc.lng, -proj.MAX_LNG, proj.MAX_LNG) : loc.lng, x = rad(lng - lng0) * r, y = proj._projectLat(lat);
                return new Point(x, y);
            },
            _projectLat: function (lat) {
                var datum = this.options.datum, ecc = datum.e, r = datum.a, y = rad(lat), ts = tan(PI_DIV_4 + y / 2), con = ecc * sin(y), p = pow((1 - con) / (1 + con), ecc / 2);
                return r * log(ts * p);
            },
            inverse: function (point, clamp) {
                var proj = this, options = proj.options, datum = options.datum, r = datum.a, lng0 = options.centralMeridian, lng = point.x / (DEG_TO_RAD * r) + lng0, lat = limit(proj._inverseY(point.y), -proj.MAX_LAT, proj.MAX_LAT);
                if (clamp) {
                    lng = limit(lng, -proj.MAX_LNG, proj.MAX_LNG);
                }
                return new Location(lat, lng);
            },
            _inverseY: function (y) {
                var proj = this, datum = proj.options.datum, r = datum.a, ecc = datum.e, ecch = ecc / 2, ts = exp(-y / r), phi = PI_DIV_2 - 2 * atan(ts), i;
                for (i = 0; i <= proj.INVERSE_ITERATIONS; i++) {
                    var con = ecc * sin(phi), p = pow((1 - con) / (1 + con), ecch), dphi = PI_DIV_2 - 2 * atan(ts * p) - phi;
                    phi += dphi;
                    if (math.abs(dphi) <= proj.INVERSE_CONVERGENCE) {
                        break;
                    }
                }
                return deg(phi);
            }
        });
        var SphericalMercator = Mercator.extend({
            MAX_LAT: 85.0511287798,
            _projectLat: function (lat) {
                var r = this.options.datum.a, y = rad(lat), ts = tan(PI_DIV_4 + y / 2);
                return r * log(ts);
            },
            _inverseY: function (y) {
                var r = this.options.datum.a, ts = exp(-y / r);
                return deg(PI_DIV_2 - 2 * atan(ts));
            }
        });
        var Equirectangular = Class.extend({
            forward: function (loc) {
                return new Point(loc.lng, loc.lat);
            },
            inverse: function (point) {
                return new Location(point.y, point.x);
            }
        });
        var EPSG3857 = Class.extend({
            init: function () {
                var crs = this, proj = crs._proj = new SphericalMercator();
                var c = this.c = 2 * PI * proj.options.datum.a;
                this._tm = g.transform().translate(0.5, 0.5).scale(1 / c, -1 / c);
                this._itm = g.transform().scale(c, -c).translate(-0.5, -0.5);
            },
            toPoint: function (loc, scale, clamp) {
                var point = this._proj.forward(loc, clamp);
                return point.transform(this._tm).scale(scale || 1);
            },
            toLocation: function (point, scale, clamp) {
                point = point.clone().scale(1 / (scale || 1)).transform(this._itm);
                return this._proj.inverse(point, clamp);
            }
        });
        var EPSG3395 = Class.extend({
            init: function () {
                this._proj = new Mercator();
            },
            toPoint: function (loc) {
                return this._proj.forward(loc);
            },
            toLocation: function (point) {
                return this._proj.inverse(point);
            }
        });
        var EPSG4326 = Class.extend({
            init: function () {
                this._proj = new Equirectangular();
            },
            toPoint: function (loc) {
                return this._proj.forward(loc);
            },
            toLocation: function (point) {
                return this._proj.inverse(point);
            }
        });
        deepExtend(dataviz, {
            map: {
                crs: {
                    EPSG3395: EPSG3395,
                    EPSG3857: EPSG3857,
                    EPSG4326: EPSG4326
                },
                datums: { WGS84: WGS84 },
                projections: {
                    Equirectangular: Equirectangular,
                    Mercator: Mercator,
                    SphericalMercator: SphericalMercator
                }
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/layers/base', [
        'kendo.core',
        'dataviz/map/location'
    ], f);
}(function () {
    (function ($, undefined) {
        var proxy = $.proxy, kendo = window.kendo, Class = kendo.Class, dataviz = kendo.dataviz, deepExtend = kendo.deepExtend, Extent = dataviz.map.Extent, util = kendo.drawing.util, defined = util.defined;
        var Layer = Class.extend({
            init: function (map, options) {
                this._initOptions(options);
                this.map = map;
                this.element = $('<div class=\'k-layer\'></div>').css({
                    'zIndex': this.options.zIndex,
                    'opacity': this.options.opacity
                }).appendTo(map.scrollElement);
                this._beforeReset = proxy(this._beforeReset, this);
                this._reset = proxy(this._reset, this);
                this._resize = proxy(this._resize, this);
                this._panEnd = proxy(this._panEnd, this);
                this._activate();
                this._updateAttribution();
            },
            destroy: function () {
                this._deactivate();
            },
            show: function () {
                this.reset();
                this._activate();
                this._applyExtent(true);
            },
            hide: function () {
                this._deactivate();
                this._setVisibility(false);
            },
            reset: function () {
                this._beforeReset();
                this._reset();
            },
            _reset: function () {
                this._applyExtent();
            },
            _beforeReset: $.noop,
            _resize: $.noop,
            _panEnd: function () {
                this._applyExtent();
            },
            _applyExtent: function () {
                var options = this.options;
                var zoom = this.map.zoom();
                var matchMinZoom = !defined(options.minZoom) || zoom >= options.minZoom;
                var matchMaxZoom = !defined(options.maxZoom) || zoom <= options.maxZoom;
                var extent = Extent.create(options.extent);
                var inside = !extent || extent.overlaps(this.map.extent());
                this._setVisibility(matchMinZoom && matchMaxZoom && inside);
            },
            _setVisibility: function (visible) {
                this.element.css('display', visible ? '' : 'none');
            },
            _activate: function () {
                var map = this.map;
                map.bind('beforeReset', this._beforeReset);
                map.bind('reset', this._reset);
                map.bind('resize', this._resize);
                map.bind('panEnd', this._panEnd);
            },
            _deactivate: function () {
                var map = this.map;
                map.unbind('beforeReset', this._beforeReset);
                map.unbind('reset', this._reset);
                map.unbind('resize', this._resize);
                map.unbind('panEnd', this._panEnd);
            },
            _updateAttribution: function () {
                var attr = this.map.attribution;
                if (attr) {
                    attr.add(this.options.attribution);
                }
            }
        });
        deepExtend(dataviz, { map: { layers: { Layer: Layer } } });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/layers/shape', [
        'dataviz/map/layers/base',
        'dataviz/map/location'
    ], f);
}(function () {
    (function ($, undefined) {
        var proxy = $.proxy, kendo = window.kendo, Class = kendo.Class, DataSource = kendo.data.DataSource, dataviz = kendo.dataviz, deepExtend = kendo.deepExtend, g = kendo.geometry, d = kendo.drawing, Group = d.Group, last = d.util.last, defined = d.util.defined, map = dataviz.map, Location = map.Location, Layer = map.layers.Layer;
        var ShapeLayer = Layer.extend({
            init: function (map, options) {
                this._pan = proxy(this._pan, this);
                Layer.fn.init.call(this, map, options);
                this.surface = d.Surface.create(this.element, {
                    width: map.scrollElement.width(),
                    height: map.scrollElement.height()
                });
                this._initRoot();
                this.movable = new kendo.ui.Movable(this.surface.element);
                this._markers = [];
                this._click = this._handler('shapeClick');
                this.surface.bind('click', this._click);
                this._mouseenter = this._handler('shapeMouseEnter');
                this.surface.bind('mouseenter', this._mouseenter);
                this._mouseleave = this._handler('shapeMouseLeave');
                this.surface.bind('mouseleave', this._mouseleave);
                this._initDataSource();
            },
            options: { autoBind: true },
            destroy: function () {
                Layer.fn.destroy.call(this);
                this.surface.destroy();
                this.dataSource.unbind('change', this._dataChange);
            },
            setDataSource: function (dataSource) {
                if (this.dataSource) {
                    this.dataSource.unbind('change', this._dataChange);
                }
                this.dataSource = kendo.data.DataSource.create(dataSource);
                this.dataSource.bind('change', this._dataChange);
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            _reset: function () {
                Layer.fn._reset.call(this);
                this._translateSurface();
                if (this._data) {
                    this._load(this._data);
                }
            },
            _initRoot: function () {
                this._root = new Group();
                this.surface.draw(this._root);
            },
            _beforeReset: function () {
                this.surface.clear();
                this._initRoot();
            },
            _resize: function () {
                this.surface.size(this.map.size());
            },
            _initDataSource: function () {
                var dsOptions = this.options.dataSource;
                this._dataChange = proxy(this._dataChange, this);
                this.dataSource = DataSource.create(dsOptions).bind('change', this._dataChange);
                if (dsOptions && this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            _dataChange: function (e) {
                this._data = e.sender.view();
                this._load(this._data);
            },
            _load: function (data) {
                this._clearMarkers();
                if (!this._loader) {
                    this._loader = new GeoJSONLoader(this.map, this.options.style, this);
                }
                var container = new Group();
                for (var i = 0; i < data.length; i++) {
                    var shape = this._loader.parse(data[i]);
                    if (shape) {
                        container.append(shape);
                    }
                }
                this._root.clear();
                this._root.append(container);
            },
            shapeCreated: function (shape) {
                var cancelled = false;
                if (shape instanceof d.Circle) {
                    cancelled = defined(this._createMarker(shape));
                }
                if (!cancelled) {
                    var args = {
                        layer: this,
                        shape: shape
                    };
                    cancelled = this.map.trigger('shapeCreated', args);
                }
                return cancelled;
            },
            featureCreated: function (e) {
                e.layer = this;
                this.map.trigger('shapeFeatureCreated', e);
            },
            _createMarker: function (shape) {
                var marker = this.map.markers.bind({ location: shape.location }, shape.dataItem);
                if (marker) {
                    this._markers.push(marker);
                }
                return marker;
            },
            _clearMarkers: function () {
                for (var i = 0; i < this._markers.length; i++) {
                    this.map.markers.remove(this._markers[i]);
                }
                this._markers = [];
            },
            _pan: function () {
                if (!this._panning) {
                    this._panning = true;
                    this.surface.suspendTracking();
                }
            },
            _panEnd: function (e) {
                Layer.fn._panEnd.call(this, e);
                this._translateSurface();
                this.surface.resumeTracking();
                this._panning = false;
            },
            _translateSurface: function () {
                var map = this.map;
                var nw = map.locationToView(map.extent().nw);
                if (this.surface.translate) {
                    this.surface.translate(nw);
                    this.movable.moveTo({
                        x: nw.x,
                        y: nw.y
                    });
                }
            },
            _handler: function (event) {
                var layer = this;
                return function (e) {
                    if (e.element) {
                        var args = {
                            layer: layer,
                            shape: e.element,
                            originalEvent: e.originalEvent
                        };
                        layer.map.trigger(event, args);
                    }
                };
            },
            _activate: function () {
                Layer.fn._activate.call(this);
                this.map.bind('pan', this._pan);
            },
            _deactivate: function () {
                Layer.fn._deactivate.call(this);
                this.map.unbind('pan', this._pan);
            }
        });
        var GeoJSONLoader = Class.extend({
            init: function (locator, defaultStyle, observer) {
                this.observer = observer;
                this.locator = locator;
                this.style = defaultStyle;
            },
            parse: function (item) {
                var root = new Group();
                var unwrap = true;
                if (item.type === 'Feature') {
                    unwrap = false;
                    this._loadGeometryTo(root, item.geometry, item);
                    this._featureCreated(root, item);
                } else {
                    this._loadGeometryTo(root, item, item);
                }
                if (unwrap && root.children.length < 2) {
                    root = root.children[0];
                }
                return root;
            },
            _shapeCreated: function (shape) {
                var cancelled = false;
                if (this.observer && this.observer.shapeCreated) {
                    cancelled = this.observer.shapeCreated(shape);
                }
                return cancelled;
            },
            _featureCreated: function (group, dataItem) {
                if (this.observer && this.observer.featureCreated) {
                    this.observer.featureCreated({
                        group: group,
                        dataItem: dataItem,
                        properties: dataItem.properties
                    });
                }
            },
            _loadGeometryTo: function (container, geometry, dataItem) {
                var coords = geometry.coordinates;
                var i;
                var path;
                switch (geometry.type) {
                case 'LineString':
                    path = this._loadPolygon(container, [coords], dataItem);
                    this._setLineFill(path);
                    break;
                case 'MultiLineString':
                    for (i = 0; i < coords.length; i++) {
                        path = this._loadPolygon(container, [coords[i]], dataItem);
                        this._setLineFill(path);
                    }
                    break;
                case 'Polygon':
                    this._loadPolygon(container, coords, dataItem);
                    break;
                case 'MultiPolygon':
                    for (i = 0; i < coords.length; i++) {
                        this._loadPolygon(container, coords[i], dataItem);
                    }
                    break;
                case 'Point':
                    this._loadPoint(container, coords, dataItem);
                    break;
                case 'MultiPoint':
                    for (i = 0; i < coords.length; i++) {
                        this._loadPoint(container, coords[i], dataItem);
                    }
                    break;
                }
            },
            _setLineFill: function (path) {
                var segments = path.segments;
                if (segments.length < 4 || !segments[0].anchor().equals(last(segments).anchor())) {
                    path.options.fill = null;
                }
            },
            _loadShape: function (container, shape) {
                if (!this._shapeCreated(shape)) {
                    container.append(shape);
                }
                return shape;
            },
            _loadPolygon: function (container, rings, dataItem) {
                var shape = this._buildPolygon(rings);
                shape.dataItem = dataItem;
                return this._loadShape(container, shape);
            },
            _buildPolygon: function (rings) {
                var type = rings.length > 1 ? d.MultiPath : d.Path;
                var path = new type(this.style);
                for (var i = 0; i < rings.length; i++) {
                    for (var j = 0; j < rings[i].length; j++) {
                        var point = this.locator.locationToView(Location.fromLngLat(rings[i][j]));
                        if (j === 0) {
                            path.moveTo(point.x, point.y);
                        } else {
                            path.lineTo(point.x, point.y);
                        }
                    }
                }
                return path;
            },
            _loadPoint: function (container, coords, dataItem) {
                var location = Location.fromLngLat(coords);
                var point = this.locator.locationToView(location);
                var circle = new g.Circle(point, 10);
                var shape = new d.Circle(circle, this.style);
                shape.dataItem = dataItem;
                shape.location = location;
                return this._loadShape(container, shape);
            }
        });
        deepExtend(kendo.data, {
            schemas: {
                geojson: {
                    type: 'json',
                    data: function (data) {
                        if (data.type === 'FeatureCollection') {
                            return data.features;
                        }
                        if (data.type === 'GeometryCollection') {
                            return data.geometries;
                        }
                        return data;
                    }
                }
            },
            transports: { geojson: { read: { dataType: 'json' } } }
        });
        deepExtend(dataviz, {
            map: {
                layers: {
                    shape: ShapeLayer,
                    ShapeLayer: ShapeLayer
                },
                GeoJSONLoader: GeoJSONLoader
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/layers/bubble', ['dataviz/map/layers/shape'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, getter = kendo.getter, dataviz = kendo.dataviz, deepExtend = kendo.deepExtend, g = kendo.geometry, d = kendo.drawing, util = d.util, defined = util.defined, map = dataviz.map, Location = map.Location, ShapeLayer = map.layers.ShapeLayer;
        var BubbleLayer = ShapeLayer.extend({
            options: {
                autoBind: true,
                locationField: 'location',
                valueField: 'value',
                minSize: 0,
                maxSize: 100,
                scale: 'sqrt',
                symbol: 'circle'
            },
            _load: function (data) {
                this.surface.clear();
                if (data.length === 0) {
                    return;
                }
                var opt = this.options;
                var getValue = getter(opt.valueField);
                data = data.slice(0);
                data.sort(function (a, b) {
                    return getValue(b) - getValue(a);
                });
                var scaleType = this._scaleType();
                var scale;
                for (var i = 0; i < data.length; i++) {
                    var dataItem = data[i];
                    var location = getter(opt.locationField)(dataItem);
                    var value = getter(opt.valueField)(dataItem);
                    if (defined(location) && defined(value)) {
                        if (!scale) {
                            scale = new scaleType([
                                0,
                                value
                            ], [
                                opt.minSize,
                                opt.maxSize
                            ]);
                        }
                        location = Location.create(location);
                        var center = this.map.locationToView(location);
                        var size = scale.map(value);
                        var symbol = this._createSymbol({
                            center: center,
                            size: size,
                            style: opt.style,
                            dataItem: dataItem,
                            location: location
                        });
                        symbol.dataItem = dataItem;
                        symbol.location = location;
                        symbol.value = value;
                        this._drawSymbol(symbol);
                    }
                }
            },
            _scaleType: function () {
                var scale = this.options.scale;
                if (kendo.isFunction(scale)) {
                    return scale;
                }
                return dataviz.map.scales[scale];
            },
            _createSymbol: function (args) {
                var symbol = this.options.symbol;
                if (!kendo.isFunction(symbol)) {
                    symbol = dataviz.map.symbols[symbol];
                }
                return symbol(args);
            },
            _drawSymbol: function (shape) {
                var args = {
                    layer: this,
                    shape: shape
                };
                var cancelled = this.map.trigger('shapeCreated', args);
                if (!cancelled) {
                    this.surface.draw(shape);
                }
            }
        });
        var SqrtScale = kendo.Class.extend({
            init: function (domain, range) {
                this._domain = domain;
                this._range = range;
                var domainRange = Math.sqrt(domain[1]) - Math.sqrt(domain[0]);
                var outputRange = range[1] - range[0];
                this._ratio = outputRange / domainRange;
            },
            map: function (value) {
                var rel = (Math.sqrt(value) - Math.sqrt(this._domain[0])) * this._ratio;
                return this._range[0] + rel;
            }
        });
        var Symbols = {
            circle: function (args) {
                var geo = new g.Circle(args.center, args.size / 2);
                return new d.Circle(geo, args.style);
            },
            square: function (args) {
                var path = new d.Path(args.style);
                var halfSize = args.size / 2;
                var center = args.center;
                path.moveTo(center.x - halfSize, center.y - halfSize).lineTo(center.x + halfSize, center.y - halfSize).lineTo(center.x + halfSize, center.y + halfSize).lineTo(center.x - halfSize, center.y + halfSize).close();
                return path;
            }
        };
        deepExtend(dataviz, {
            map: {
                layers: {
                    bubble: BubbleLayer,
                    BubbleLayer: BubbleLayer
                },
                scales: { sqrt: SqrtScale },
                symbols: Symbols
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/layers/tile', [
        'dataviz/map/layers/base',
        'dataviz/map/location'
    ], f);
}(function () {
    (function ($, undefined) {
        var math = Math, proxy = $.proxy, kendo = window.kendo, Class = kendo.Class, template = kendo.template, dataviz = kendo.dataviz, deepExtend = kendo.deepExtend, g = kendo.geometry, Point = g.Point, Layer = dataviz.map.layers.Layer, util = kendo.util, renderSize = util.renderSize, drawingUtil = kendo.drawing.util, round = drawingUtil.round, limit = drawingUtil.limitValue;
        var TileLayer = Layer.extend({
            init: function (map, options) {
                Layer.fn.init.call(this, map, options);
                if (typeof this.options.subdomains === 'string') {
                    this.options.subdomains = this.options.subdomains.split('');
                }
                var viewType = this._viewType();
                this._view = new viewType(this.element, this.options);
            },
            destroy: function () {
                Layer.fn.destroy.call(this);
                this._view.destroy();
                this._view = null;
            },
            _beforeReset: function () {
                var map = this.map;
                var origin = map.locationToLayer(map.extent().nw).round();
                this._view.viewOrigin(origin);
            },
            _reset: function () {
                Layer.fn._reset.call(this);
                this._updateView();
                this._view.reset();
            },
            _viewType: function () {
                return TileView;
            },
            _activate: function () {
                Layer.fn._activate.call(this);
                if (!kendo.support.mobileOS) {
                    if (!this._pan) {
                        this._pan = kendo.throttle(proxy(this._render, this), 100);
                    }
                    this.map.bind('pan', this._pan);
                }
            },
            _deactivate: function () {
                Layer.fn._deactivate.call(this);
                if (this._pan) {
                    this.map.unbind('pan', this._pan);
                }
            },
            _updateView: function () {
                var view = this._view, map = this.map, extent = map.extent(), extentToPoint = {
                        nw: map.locationToLayer(extent.nw).round(),
                        se: map.locationToLayer(extent.se).round()
                    };
                view.center(map.locationToLayer(map.center()));
                view.extent(extentToPoint);
                view.zoom(map.zoom());
            },
            _resize: function () {
                this._render();
            },
            _panEnd: function (e) {
                Layer.fn._panEnd.call(this, e);
                this._render();
            },
            _render: function () {
                this._updateView();
                this._view.render();
            }
        });
        var TileView = Class.extend({
            init: function (element, options) {
                this.element = element;
                this._initOptions(options);
                this.pool = new TilePool();
            },
            options: {
                tileSize: 256,
                subdomains: [
                    'a',
                    'b',
                    'c'
                ],
                urlTemplate: ''
            },
            center: function (center) {
                this._center = center;
            },
            extent: function (extent) {
                this._extent = extent;
            },
            viewOrigin: function (origin) {
                this._viewOrigin = origin;
            },
            zoom: function (zoom) {
                this._zoom = zoom;
            },
            pointToTileIndex: function (point) {
                return new Point(math.floor(point.x / this.options.tileSize), math.floor(point.y / this.options.tileSize));
            },
            tileCount: function () {
                var size = this.size(), firstTileIndex = this.pointToTileIndex(this._extent.nw), nw = this._extent.nw, point = this.indexToPoint(firstTileIndex).translate(-nw.x, -nw.y);
                return {
                    x: math.ceil((math.abs(point.x) + size.width) / this.options.tileSize),
                    y: math.ceil((math.abs(point.y) + size.height) / this.options.tileSize)
                };
            },
            size: function () {
                var nw = this._extent.nw, se = this._extent.se, diff = se.clone().translate(-nw.x, -nw.y);
                return {
                    width: diff.x,
                    height: diff.y
                };
            },
            indexToPoint: function (index) {
                var x = index.x, y = index.y;
                return new Point(x * this.options.tileSize, y * this.options.tileSize);
            },
            subdomainText: function () {
                var subdomains = this.options.subdomains;
                return subdomains[this.subdomainIndex++ % subdomains.length];
            },
            destroy: function () {
                this.element.empty();
                this.pool.empty();
            },
            reset: function () {
                this.pool.reset();
                this.subdomainIndex = 0;
                this.render();
            },
            render: function () {
                var size = this.tileCount(), firstTileIndex = this.pointToTileIndex(this._extent.nw), tile, x, y;
                for (x = 0; x < size.x; x++) {
                    for (y = 0; y < size.y; y++) {
                        tile = this.createTile({
                            x: firstTileIndex.x + x,
                            y: firstTileIndex.y + y
                        });
                        if (!tile.visible) {
                            tile.show();
                        }
                    }
                }
            },
            createTile: function (currentIndex) {
                var options = this.tileOptions(currentIndex);
                var tile = this.pool.get(this._center, options);
                if (tile.element.parent().length === 0) {
                    this.element.append(tile.element);
                }
                return tile;
            },
            tileOptions: function (currentIndex) {
                var index = this.wrapIndex(currentIndex), point = this.indexToPoint(currentIndex), origin = this._viewOrigin, offset = point.clone().translate(-origin.x, -origin.y);
                return {
                    index: index,
                    currentIndex: currentIndex,
                    point: point,
                    offset: roundPoint(offset),
                    zoom: this._zoom,
                    size: this.options.tileSize,
                    subdomain: this.subdomainText(),
                    urlTemplate: this.options.urlTemplate,
                    errorUrlTemplate: this.options.errorUrlTemplate
                };
            },
            wrapIndex: function (index) {
                var boundary = math.pow(2, this._zoom);
                return {
                    x: this.wrapValue(index.x, boundary),
                    y: limit(index.y, 0, boundary - 1)
                };
            },
            wrapValue: function (value, boundary) {
                var remainder = math.abs(value) % boundary;
                if (value >= 0) {
                    value = remainder;
                } else {
                    value = boundary - (remainder === 0 ? boundary : remainder);
                }
                return value;
            }
        });
        var ImageTile = Class.extend({
            init: function (id, options) {
                this.id = id;
                this.visible = true;
                this._initOptions(options);
                this.createElement();
                this.show();
            },
            options: {
                urlTemplate: '',
                errorUrlTemplate: ''
            },
            createElement: function () {
                this.element = $('<img style=\'position: absolute; display: block;\' alt=\'\' />').css({
                    width: this.options.size,
                    height: this.options.size
                }).on('error', proxy(function (e) {
                    if (this.errorUrl()) {
                        e.target.setAttribute('src', this.errorUrl());
                    } else {
                        e.target.removeAttribute('src');
                    }
                }, this));
            },
            show: function () {
                var element = this.element[0];
                element.style.top = renderSize(this.options.offset.y);
                element.style.left = renderSize(this.options.offset.x);
                var url = this.url();
                if (url) {
                    element.setAttribute('src', url);
                }
                element.style.visibility = 'visible';
                this.visible = true;
            },
            hide: function () {
                this.element[0].style.visibility = 'hidden';
                this.visible = false;
            },
            url: function () {
                var urlResult = template(this.options.urlTemplate);
                return urlResult(this.urlOptions());
            },
            errorUrl: function () {
                var urlResult = template(this.options.errorUrlTemplate);
                return urlResult(this.urlOptions());
            },
            urlOptions: function () {
                var options = this.options;
                return {
                    zoom: options.zoom,
                    subdomain: options.subdomain,
                    z: options.zoom,
                    x: options.index.x,
                    y: options.index.y,
                    s: options.subdomain,
                    quadkey: options.quadkey,
                    q: options.quadkey,
                    culture: options.culture,
                    c: options.culture
                };
            },
            destroy: function () {
                if (this.element) {
                    this.element.remove();
                    this.element = null;
                }
            }
        });
        var TilePool = Class.extend({
            init: function () {
                this._items = [];
            },
            options: { maxSize: 100 },
            get: function (center, options) {
                if (this._items.length >= this.options.maxSize) {
                    this._remove(center);
                }
                return this._create(options);
            },
            empty: function () {
                var items = this._items;
                for (var i = 0; i < items.length; i++) {
                    items[i].destroy();
                }
                this._items = [];
            },
            reset: function () {
                var items = this._items;
                for (var i = 0; i < items.length; i++) {
                    items[i].hide();
                }
            },
            _create: function (options) {
                var items = this._items;
                var tile;
                var id = util.hashKey(options.point.toString() + options.offset.toString() + options.zoom + options.urlTemplate);
                for (var i = 0; i < items.length; i++) {
                    if (items[i].id === id) {
                        tile = items[i];
                        break;
                    }
                }
                if (tile) {
                    tile.show();
                } else {
                    tile = new ImageTile(id, options);
                    this._items.push(tile);
                }
                return tile;
            },
            _remove: function (center) {
                var items = this._items;
                var maxDist = -1;
                var index = -1;
                for (var i = 0; i < items.length; i++) {
                    var dist = items[i].options.point.distanceTo(center);
                    if (dist > maxDist && !items[i].visible) {
                        index = i;
                        maxDist = dist;
                    }
                }
                if (index !== -1) {
                    items[index].destroy();
                    items.splice(index, 1);
                }
            }
        });
        function roundPoint(point) {
            return new Point(round(point.x), round(point.y));
        }
        deepExtend(dataviz, {
            map: {
                layers: {
                    tile: TileLayer,
                    TileLayer: TileLayer,
                    ImageTile: ImageTile,
                    TilePool: TilePool,
                    TileView: TileView
                }
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/layers/bing', ['dataviz/map/layers/tile'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, dataviz = kendo.dataviz, deepExtend = kendo.deepExtend, defined = kendo.drawing.util.defined, Extent = dataviz.map.Extent, Location = dataviz.map.Location, TileLayer = dataviz.map.layers.TileLayer, TileView = dataviz.map.layers.TileView;
        var BingLayer = TileLayer.extend({
            init: function (map, options) {
                this.options.baseUrl = this._scheme() + '://dev.virtualearth.net/REST/v1/Imagery/Metadata/';
                TileLayer.fn.init.call(this, map, options);
                this._onMetadata = $.proxy(this._onMetadata, this);
                this._fetchMetadata();
            },
            options: { imagerySet: 'road' },
            _fetchMetadata: function () {
                var options = this.options;
                if (!options.key) {
                    throw new Error('Bing tile layer: API key is required');
                }
                $.ajax({
                    url: options.baseUrl + options.imagerySet,
                    data: {
                        output: 'json',
                        include: 'ImageryProviders',
                        key: options.key,
                        uriScheme: this._scheme()
                    },
                    type: 'get',
                    dataType: 'jsonp',
                    jsonp: 'jsonp',
                    success: this._onMetadata
                });
            },
            _scheme: function (proto) {
                proto = proto || window.location.protocol;
                return proto.replace(':', '') === 'https' ? 'https' : 'http';
            },
            _onMetadata: function (data) {
                if (data && data.resourceSets.length) {
                    var resource = this.resource = data.resourceSets[0].resources[0];
                    deepExtend(this._view.options, {
                        urlTemplate: resource.imageUrl.replace('{subdomain}', '#= subdomain #').replace('{quadkey}', '#= quadkey #').replace('{culture}', '#= culture #'),
                        subdomains: resource.imageUrlSubdomains
                    });
                    var options = this.options;
                    if (!defined(options.minZoom)) {
                        options.minZoom = resource.zoomMin;
                    }
                    if (!defined(options.maxZoom)) {
                        options.maxZoom = resource.zoomMax;
                    }
                    this._addAttribution();
                    if (this.element.css('display') !== 'none') {
                        this._reset();
                    }
                }
            },
            _viewType: function () {
                return BingView;
            },
            _addAttribution: function () {
                var attr = this.map.attribution;
                if (attr) {
                    var items = this.resource.imageryProviders;
                    if (items) {
                        for (var i = 0; i < items.length; i++) {
                            var item = items[i];
                            for (var y = 0; y < item.coverageAreas.length; y++) {
                                var area = item.coverageAreas[y];
                                attr.add({
                                    text: item.attribution,
                                    minZoom: area.zoomMin,
                                    maxZoom: area.zoomMax,
                                    extent: new Extent(new Location(area.bbox[2], area.bbox[1]), new Location(area.bbox[0], area.bbox[3]))
                                });
                            }
                        }
                    }
                }
            },
            imagerySet: function (value) {
                if (value) {
                    this.options.imagerySet = value;
                    this.map.attribution.clear();
                    this._fetchMetadata();
                } else {
                    return this.options.imagerySet;
                }
            }
        });
        var BingView = TileView.extend({
            options: { culture: 'en-US' },
            tileOptions: function (currentIndex) {
                var options = TileView.fn.tileOptions.call(this, currentIndex);
                options.culture = this.options.culture;
                options.quadkey = this.tileQuadKey(this.wrapIndex(currentIndex));
                return options;
            },
            tileQuadKey: function (index) {
                var quadKey = '', digit, mask, i;
                for (i = this._zoom; i > 0; i--) {
                    digit = 0;
                    mask = 1 << i - 1;
                    if ((index.x & mask) !== 0) {
                        digit++;
                    }
                    if ((index.y & mask) !== 0) {
                        digit += 2;
                    }
                    quadKey += digit;
                }
                return quadKey;
            }
        });
        deepExtend(dataviz, {
            map: {
                layers: {
                    bing: BingLayer,
                    BingLayer: BingLayer,
                    BingView: BingView
                }
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/layers/marker', [
        'dataviz/map/layers/base',
        'dataviz/map/location',
        'kendo.data',
        'kendo.tooltip'
    ], f);
}(function () {
    (function ($, undefined) {
        var doc = document, math = Math, indexOf = $.inArray, proxy = $.proxy, kendo = window.kendo, Class = kendo.Class, DataSource = kendo.data.DataSource, Tooltip = kendo.ui.Tooltip, dataviz = kendo.dataviz, deepExtend = kendo.deepExtend, map = dataviz.map, Location = map.Location, Layer = map.layers.Layer;
        var MarkerLayer = Layer.extend({
            init: function (map, options) {
                Layer.fn.init.call(this, map, options);
                this._markerClick = proxy(this._markerClick, this);
                this.element.on('click', '.k-marker', this._markerClick);
                this.items = [];
                this._initDataSource();
            },
            destroy: function () {
                Layer.fn.destroy.call(this);
                this.element.off('click', '.k-marker', this._markerClick);
                this.dataSource.unbind('change', this._dataChange);
                this.clear();
            },
            options: {
                zIndex: 1000,
                autoBind: true,
                dataSource: {},
                locationField: 'location',
                titleField: 'title'
            },
            add: function (arg) {
                if ($.isArray(arg)) {
                    for (var i = 0; i < arg.length; i++) {
                        this._addOne(arg[i]);
                    }
                } else {
                    return this._addOne(arg);
                }
            },
            remove: function (marker) {
                marker.destroy();
                var index = indexOf(marker, this.items);
                if (index > -1) {
                    this.items.splice(index, 1);
                }
            },
            clear: function () {
                for (var i = 0; i < this.items.length; i++) {
                    this.items[i].destroy();
                }
                this.items = [];
            },
            update: function (marker) {
                var loc = marker.location();
                if (loc) {
                    marker.showAt(this.map.locationToView(loc));
                    var args = {
                        marker: marker,
                        layer: this
                    };
                    this.map.trigger('markerActivate', args);
                }
            },
            _reset: function () {
                Layer.fn._reset.call(this);
                var items = this.items;
                for (var i = 0; i < items.length; i++) {
                    this.update(items[i]);
                }
            },
            bind: function (options, dataItem) {
                var marker = map.Marker.create(options, this.options);
                marker.dataItem = dataItem;
                var args = {
                    marker: marker,
                    layer: this
                };
                var cancelled = this.map.trigger('markerCreated', args);
                if (!cancelled) {
                    this.add(marker);
                    return marker;
                }
            },
            setDataSource: function (dataSource) {
                if (this.dataSource) {
                    this.dataSource.unbind('change', this._dataChange);
                }
                this.dataSource = kendo.data.DataSource.create(dataSource);
                this.dataSource.bind('change', this._dataChange);
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            _addOne: function (arg) {
                var marker = Marker.create(arg, this.options);
                marker.addTo(this);
                return marker;
            },
            _initDataSource: function () {
                var dsOptions = this.options.dataSource;
                this._dataChange = proxy(this._dataChange, this);
                this.dataSource = DataSource.create(dsOptions).bind('change', this._dataChange);
                if (dsOptions && this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            _dataChange: function (e) {
                this._load(e.sender.view());
            },
            _load: function (data) {
                this._data = data;
                this.clear();
                var getLocation = kendo.getter(this.options.locationField);
                var getTitle = kendo.getter(this.options.titleField);
                for (var i = 0; i < data.length; i++) {
                    var dataItem = data[i];
                    this.bind({
                        location: getLocation(dataItem),
                        title: getTitle(dataItem)
                    }, dataItem);
                }
            },
            _markerClick: function (e) {
                var args = {
                    marker: $(e.target).data('kendoMarker'),
                    layer: this
                };
                this.map.trigger('markerClick', args);
            }
        });
        var Marker = Class.extend({
            init: function (options) {
                this.options = options || {};
            },
            addTo: function (parent) {
                this.layer = parent.markers || parent;
                this.layer.items.push(this);
                this.layer.update(this);
            },
            location: function (value) {
                if (value) {
                    this.options.location = Location.create(value).toArray();
                    if (this.layer) {
                        this.layer.update(this);
                    }
                    return this;
                } else {
                    return Location.create(this.options.location);
                }
            },
            showAt: function (point) {
                this.render();
                this.element.css({
                    left: math.round(point.x),
                    top: math.round(point.y)
                });
                if (this.tooltip && this.tooltip.popup) {
                    this.tooltip.popup._position();
                }
            },
            hide: function () {
                if (this.element) {
                    this.element.remove();
                    this.element = null;
                }
                if (this.tooltip) {
                    this.tooltip.destroy();
                    this.tooltip = null;
                }
            },
            destroy: function () {
                this.layer = null;
                this.hide();
            },
            render: function () {
                if (!this.element) {
                    var options = this.options;
                    var layer = this.layer;
                    this.element = $(doc.createElement('span')).addClass('k-marker k-icon k-i-marker-' + kendo.toHyphens(options.shape || 'pin')).attr('title', options.title).attr(options.attributes || {}).data('kendoMarker', this).css('zIndex', options.zIndex);
                    if (layer) {
                        layer.element.append(this.element);
                    }
                    this.renderTooltip();
                }
            },
            renderTooltip: function () {
                var marker = this;
                var title = marker.options.title;
                var options = marker.options.tooltip || {};
                if (options && Tooltip) {
                    var template = options.template;
                    if (template) {
                        var contentTemplate = kendo.template(template);
                        options.content = function (e) {
                            e.location = marker.location();
                            e.marker = marker;
                            return contentTemplate(e);
                        };
                    }
                    if (title || options.content || options.contentUrl) {
                        this.tooltip = new Tooltip(this.element, options);
                        this.tooltip.marker = this;
                    }
                }
            }
        });
        Marker.create = function (arg, defaults) {
            if (arg instanceof Marker) {
                return arg;
            }
            return new Marker(deepExtend({}, defaults, arg));
        };
        deepExtend(dataviz, {
            map: {
                layers: {
                    marker: MarkerLayer,
                    MarkerLayer: MarkerLayer
                },
                Marker: Marker
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/map/main', [
        'dataviz/map/crs',
        'dataviz/map/location'
    ], f);
}(function () {
    (function ($, undefined) {
        var doc = document, math = Math, min = math.min, pow = math.pow, proxy = $.proxy, kendo = window.kendo, Widget = kendo.ui.Widget, deepExtend = kendo.deepExtend, dataviz = kendo.dataviz, ui = dataviz.ui, g = kendo.geometry, Point = g.Point, map = dataviz.map, Extent = map.Extent, Location = map.Location, EPSG3857 = map.crs.EPSG3857, util = kendo.util, renderPos = util.renderPos, drawingUtil = kendo.drawing.util, defined = drawingUtil.defined, limit = drawingUtil.limitValue, valueOrDefault = drawingUtil.valueOrDefault;
        var CSS_PREFIX = 'k-', FRICTION = 0.9, FRICTION_MOBILE = 0.93, MOUSEWHEEL = 'DOMMouseScroll mousewheel', VELOCITY_MULTIPLIER = 5;
        var Map = Widget.extend({
            init: function (element, options) {
                kendo.destroy(element);
                Widget.fn.init.call(this, element);
                this._initOptions(options);
                this.bind(this.events, options);
                this.crs = new EPSG3857();
                this.element.addClass(CSS_PREFIX + this.options.name.toLowerCase()).css('position', 'relative').empty().append(doc.createElement('div'));
                this._viewOrigin = this._getOrigin();
                this._initScroller();
                this._initMarkers();
                this._initControls();
                this._initLayers();
                this._reset();
                this._mousewheel = proxy(this._mousewheel, this);
                this.element.bind('click', proxy(this._click, this));
                this.element.bind(MOUSEWHEEL, this._mousewheel);
            },
            options: {
                name: 'Map',
                controls: {
                    attribution: true,
                    navigator: { panStep: 100 },
                    zoom: true
                },
                layers: [],
                layerDefaults: {
                    shape: {
                        style: {
                            fill: { color: '#fff' },
                            stroke: {
                                color: '#aaa',
                                width: 0.5
                            }
                        }
                    },
                    bubble: {
                        style: {
                            fill: {
                                color: '#fff',
                                opacity: 0.5
                            },
                            stroke: {
                                color: '#aaa',
                                width: 0.5
                            }
                        }
                    },
                    marker: {
                        shape: 'pinTarget',
                        tooltip: { position: 'top' }
                    }
                },
                center: [
                    0,
                    0
                ],
                zoom: 3,
                minSize: 256,
                minZoom: 1,
                maxZoom: 19,
                markers: [],
                markerDefaults: {
                    shape: 'pinTarget',
                    tooltip: { position: 'top' }
                },
                wraparound: true
            },
            events: [
                'beforeReset',
                'click',
                'markerActivate',
                'markerClick',
                'markerCreated',
                'pan',
                'panEnd',
                'reset',
                'shapeClick',
                'shapeCreated',
                'shapeFeatureCreated',
                'shapeMouseEnter',
                'shapeMouseLeave',
                'zoomEnd',
                'zoomStart'
            ],
            destroy: function () {
                this.scroller.destroy();
                if (this.navigator) {
                    this.navigator.destroy();
                }
                if (this.attribution) {
                    this.attribution.destroy();
                }
                if (this.zoomControl) {
                    this.zoomControl.destroy();
                }
                this.markers.destroy();
                for (var i = 0; i < this.layers.length; i++) {
                    this.layers[i].destroy();
                }
                Widget.fn.destroy.call(this);
            },
            zoom: function (level) {
                var options = this.options;
                if (defined(level)) {
                    level = math.round(limit(level, options.minZoom, options.maxZoom));
                    if (options.zoom !== level) {
                        options.zoom = level;
                        this._reset();
                    }
                    return this;
                } else {
                    return options.zoom;
                }
            },
            center: function (center) {
                if (center) {
                    this.options.center = Location.create(center).toArray();
                    this._reset();
                    return this;
                } else {
                    return Location.create(this.options.center);
                }
            },
            extent: function (extent) {
                if (extent) {
                    this._setExtent(extent);
                    return this;
                } else {
                    return this._getExtent();
                }
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._reset();
            },
            locationToLayer: function (location, zoom) {
                var clamp = !this.options.wraparound;
                location = Location.create(location);
                return this.crs.toPoint(location, this._layerSize(zoom), clamp);
            },
            layerToLocation: function (point, zoom) {
                var clamp = !this.options.wraparound;
                point = Point.create(point);
                return this.crs.toLocation(point, this._layerSize(zoom), clamp);
            },
            locationToView: function (location) {
                location = Location.create(location);
                var origin = this.locationToLayer(this._viewOrigin);
                var point = this.locationToLayer(location);
                return point.translateWith(origin.scale(-1));
            },
            viewToLocation: function (point, zoom) {
                var origin = this.locationToLayer(this._getOrigin(), zoom);
                point = Point.create(point);
                point = point.clone().translateWith(origin);
                return this.layerToLocation(point, zoom);
            },
            eventOffset: function (e) {
                var offset = this.element.offset();
                var event = e.originalEvent || e;
                var x = valueOrDefault(event.pageX, event.clientX) - offset.left;
                var y = valueOrDefault(event.pageY, event.clientY) - offset.top;
                return new g.Point(x, y);
            },
            eventToView: function (e) {
                var cursor = this.eventOffset(e);
                return this.locationToView(this.viewToLocation(cursor));
            },
            eventToLayer: function (e) {
                return this.locationToLayer(this.eventToLocation(e));
            },
            eventToLocation: function (e) {
                var cursor = this.eventOffset(e);
                return this.viewToLocation(cursor);
            },
            viewSize: function () {
                var element = this.element;
                var scale = this._layerSize();
                var width = element.width();
                if (!this.options.wraparound) {
                    width = min(scale, width);
                }
                return {
                    width: width,
                    height: min(scale, element.height())
                };
            },
            exportVisual: function () {
                this._reset();
                return false;
            },
            _setOrigin: function (origin, zoom) {
                var size = this.viewSize(), topLeft;
                origin = this._origin = Location.create(origin);
                topLeft = this.locationToLayer(origin, zoom);
                topLeft.x += size.width / 2;
                topLeft.y += size.height / 2;
                this.options.center = this.layerToLocation(topLeft, zoom).toArray();
                return this;
            },
            _getOrigin: function (invalidate) {
                var size = this.viewSize(), topLeft;
                if (invalidate || !this._origin) {
                    topLeft = this.locationToLayer(this.center());
                    topLeft.x -= size.width / 2;
                    topLeft.y -= size.height / 2;
                    this._origin = this.layerToLocation(topLeft);
                }
                return this._origin;
            },
            _setExtent: function (extent) {
                var raw = Extent.create(extent);
                var se = raw.se.clone();
                if (this.options.wraparound && se.lng < 0 && extent.nw.lng > 0) {
                    se.lng = 180 + (180 + se.lng);
                }
                extent = new Extent(raw.nw, se);
                this.center(extent.center());
                var width = this.element.width();
                var height = this.element.height();
                for (var zoom = this.options.maxZoom; zoom >= this.options.minZoom; zoom--) {
                    var topLeft = this.locationToLayer(extent.nw, zoom);
                    var bottomRight = this.locationToLayer(extent.se, zoom);
                    var layerWidth = math.abs(bottomRight.x - topLeft.x);
                    var layerHeight = math.abs(bottomRight.y - topLeft.y);
                    if (layerWidth <= width && layerHeight <= height) {
                        break;
                    }
                }
                this.zoom(zoom);
            },
            _getExtent: function () {
                var nw = this._getOrigin();
                var bottomRight = this.locationToLayer(nw);
                var size = this.viewSize();
                bottomRight.x += size.width;
                bottomRight.y += size.height;
                var se = this.layerToLocation(bottomRight);
                return new Extent(nw, se);
            },
            _zoomAround: function (pivot, level) {
                this._setOrigin(this.layerToLocation(pivot, level), level);
                this.zoom(level);
            },
            _initControls: function () {
                var controls = this.options.controls;
                if (ui.Attribution && controls.attribution) {
                    this._createAttribution(controls.attribution);
                }
                if (!kendo.support.mobileOS) {
                    if (ui.Navigator && controls.navigator) {
                        this._createNavigator(controls.navigator);
                    }
                    if (ui.ZoomControl && controls.zoom) {
                        this._createZoomControl(controls.zoom);
                    }
                }
            },
            _createControlElement: function (options, defaultPos) {
                var pos = options.position || defaultPos;
                var posSelector = '.' + renderPos(pos).replace(' ', '.');
                var wrap = $('.k-map-controls' + posSelector, this.element);
                if (wrap.length === 0) {
                    wrap = $('<div>').addClass('k-map-controls ' + renderPos(pos)).appendTo(this.element);
                }
                return $('<div>').appendTo(wrap);
            },
            _createAttribution: function (options) {
                var element = this._createControlElement(options, 'bottomRight');
                this.attribution = new ui.Attribution(element, options);
            },
            _createNavigator: function (options) {
                var element = this._createControlElement(options, 'topLeft');
                var navigator = this.navigator = new ui.Navigator(element, options);
                this._navigatorPan = proxy(this._navigatorPan, this);
                navigator.bind('pan', this._navigatorPan);
                this._navigatorCenter = proxy(this._navigatorCenter, this);
                navigator.bind('center', this._navigatorCenter);
            },
            _navigatorPan: function (e) {
                var map = this;
                var scroller = map.scroller;
                var x = scroller.scrollLeft + e.x;
                var y = scroller.scrollTop - e.y;
                var bounds = this._virtualSize;
                var height = this.element.height();
                var width = this.element.width();
                x = limit(x, bounds.x.min, bounds.x.max - width);
                y = limit(y, bounds.y.min, bounds.y.max - height);
                map.scroller.one('scroll', function (e) {
                    map._scrollEnd(e);
                });
                map.scroller.scrollTo(-x, -y);
            },
            _navigatorCenter: function () {
                this.center(this.options.center);
            },
            _createZoomControl: function (options) {
                var element = this._createControlElement(options, 'topLeft');
                var zoomControl = this.zoomControl = new ui.ZoomControl(element, options);
                this._zoomControlChange = proxy(this._zoomControlChange, this);
                zoomControl.bind('change', this._zoomControlChange);
            },
            _zoomControlChange: function (e) {
                if (!this.trigger('zoomStart', { originalEvent: e })) {
                    this.zoom(this.zoom() + e.delta);
                    this.trigger('zoomEnd', { originalEvent: e });
                }
            },
            _initScroller: function () {
                var friction = kendo.support.mobileOS ? FRICTION_MOBILE : FRICTION;
                var zoomable = this.options.zoomable !== false;
                var scroller = this.scroller = new kendo.mobile.ui.Scroller(this.element.children(0), {
                    friction: friction,
                    velocityMultiplier: VELOCITY_MULTIPLIER,
                    zoom: zoomable,
                    mousewheelScrolling: false
                });
                scroller.bind('scroll', proxy(this._scroll, this));
                scroller.bind('scrollEnd', proxy(this._scrollEnd, this));
                scroller.userEvents.bind('gesturestart', proxy(this._scaleStart, this));
                scroller.userEvents.bind('gestureend', proxy(this._scale, this));
                this.scrollElement = scroller.scrollElement;
            },
            _initLayers: function () {
                var defs = this.options.layers, layers = this.layers = [];
                for (var i = 0; i < defs.length; i++) {
                    var options = defs[i];
                    var type = options.type || 'shape';
                    var defaults = this.options.layerDefaults[type];
                    var impl = dataviz.map.layers[type];
                    layers.push(new impl(this, deepExtend({}, defaults, options)));
                }
            },
            _initMarkers: function () {
                this.markers = new map.layers.MarkerLayer(this, this.options.markerDefaults);
                this.markers.add(this.options.markers);
            },
            _scroll: function (e) {
                var origin = this.locationToLayer(this._viewOrigin).round();
                var movable = e.sender.movable;
                var offset = new g.Point(movable.x, movable.y).scale(-1).scale(1 / movable.scale);
                origin.x += offset.x;
                origin.y += offset.y;
                this._scrollOffset = offset;
                this._setOrigin(this.layerToLocation(origin));
                this.trigger('pan', {
                    originalEvent: e,
                    origin: this._getOrigin(),
                    center: this.center()
                });
            },
            _scrollEnd: function (e) {
                if (!this._scrollOffset || !this._panComplete()) {
                    return;
                }
                this._scrollOffset = null;
                this._panEndTS = new Date();
                this.trigger('panEnd', {
                    originalEvent: e,
                    origin: this._getOrigin(),
                    center: this.center()
                });
            },
            _panComplete: function () {
                return new Date() - (this._panEndTS || 0) > 50;
            },
            _scaleStart: function (e) {
                if (this.trigger('zoomStart', { originalEvent: e })) {
                    var touch = e.touches[1];
                    if (touch) {
                        touch.cancel();
                    }
                }
            },
            _scale: function (e) {
                var scale = this.scroller.movable.scale;
                var zoom = this._scaleToZoom(scale);
                var gestureCenter = new g.Point(e.center.x, e.center.y);
                var centerLocation = this.viewToLocation(gestureCenter, zoom);
                var centerPoint = this.locationToLayer(centerLocation, zoom);
                var originPoint = centerPoint.translate(-gestureCenter.x, -gestureCenter.y);
                this._zoomAround(originPoint, zoom);
                this.trigger('zoomEnd', { originalEvent: e });
            },
            _scaleToZoom: function (scaleDelta) {
                var scale = this._layerSize() * scaleDelta;
                var tiles = scale / this.options.minSize;
                var zoom = math.log(tiles) / math.log(2);
                return math.round(zoom);
            },
            _reset: function () {
                if (this.attribution) {
                    this.attribution.filter(this.center(), this.zoom());
                }
                this._viewOrigin = this._getOrigin(true);
                this._resetScroller();
                this.trigger('beforeReset');
                this.trigger('reset');
            },
            _resetScroller: function () {
                var scroller = this.scroller;
                var x = scroller.dimensions.x;
                var y = scroller.dimensions.y;
                var scale = this._layerSize();
                var nw = this.extent().nw;
                var topLeft = this.locationToLayer(nw).round();
                scroller.movable.round = true;
                scroller.reset();
                scroller.userEvents.cancel();
                var zoom = this.zoom();
                scroller.dimensions.forcedMinScale = pow(2, this.options.minZoom - zoom);
                scroller.dimensions.maxScale = pow(2, this.options.maxZoom - zoom);
                var xBounds = {
                    min: -topLeft.x,
                    max: scale - topLeft.x
                };
                var yBounds = {
                    min: -topLeft.y,
                    max: scale - topLeft.y
                };
                if (this.options.wraparound) {
                    xBounds.max = 20 * scale;
                    xBounds.min = -xBounds.max;
                }
                if (this.options.pannable === false) {
                    var viewSize = this.viewSize();
                    xBounds.min = yBounds.min = 0;
                    xBounds.max = viewSize.width;
                    yBounds.max = viewSize.height;
                }
                x.makeVirtual();
                y.makeVirtual();
                x.virtualSize(xBounds.min, xBounds.max);
                y.virtualSize(yBounds.min, yBounds.max);
                this._virtualSize = {
                    x: xBounds,
                    y: yBounds
                };
            },
            _renderLayers: function () {
                var defs = this.options.layers, layers = this.layers = [], scrollWrap = this.scrollWrap;
                scrollWrap.empty();
                for (var i = 0; i < defs.length; i++) {
                    var options = defs[i];
                    var type = options.type || 'shape';
                    var defaults = this.options.layerDefaults[type];
                    var impl = dataviz.map.layers[type];
                    layers.push(new impl(this, deepExtend({}, defaults, options)));
                }
            },
            _layerSize: function (zoom) {
                zoom = valueOrDefault(zoom, this.options.zoom);
                return this.options.minSize * pow(2, zoom);
            },
            _click: function (e) {
                if (!this._panComplete()) {
                    return;
                }
                var cursor = this.eventOffset(e);
                this.trigger('click', {
                    originalEvent: e,
                    location: this.viewToLocation(cursor)
                });
            },
            _mousewheel: function (e) {
                e.preventDefault();
                var delta = dataviz.mwDelta(e) > 0 ? -1 : 1;
                var options = this.options;
                var fromZoom = this.zoom();
                var toZoom = limit(fromZoom + delta, options.minZoom, options.maxZoom);
                if (options.zoomable !== false && toZoom !== fromZoom) {
                    if (!this.trigger('zoomStart', { originalEvent: e })) {
                        var cursor = this.eventOffset(e);
                        var location = this.viewToLocation(cursor);
                        var postZoom = this.locationToLayer(location, toZoom);
                        var origin = postZoom.translate(-cursor.x, -cursor.y);
                        this._zoomAround(origin, toZoom);
                        this.trigger('zoomEnd', { originalEvent: e });
                    }
                }
            }
        });
        dataviz.ui.plugin(Map);
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.map', [
        'kendo.data',
        'kendo.userevents',
        'kendo.tooltip',
        'kendo.mobile.scroller',
        'kendo.draganddrop',
        'kendo.dataviz.core',
        'dataviz/map/location',
        'dataviz/map/attribution',
        'dataviz/map/navigator',
        'dataviz/map/zoom',
        'dataviz/map/crs',
        'dataviz/map/layers/base',
        'dataviz/map/layers/shape',
        'dataviz/map/layers/bubble',
        'dataviz/map/layers/tile',
        'dataviz/map/layers/bing',
        'dataviz/map/layers/marker',
        'dataviz/map/main'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.map',
        name: 'Map',
        category: 'dataviz',
        description: 'The Kendo DataViz Map displays spatial data',
        depends: [
            'data',
            'userevents',
            'tooltip',
            'dataviz.core',
            'drawing',
            'mobile.scroller'
        ]
    };
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/diagram/utils', ['kendo.core'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, diagram = kendo.dataviz.diagram = {}, deepExtend = kendo.deepExtend, isArray = $.isArray, EPSILON = 0.000001;
        var Utils = {};
        deepExtend(Utils, {
            isNearZero: function (num) {
                return Math.abs(num) < EPSILON;
            },
            isDefined: function (obj) {
                return typeof obj !== 'undefined';
            },
            isUndefined: function (obj) {
                return typeof obj === 'undefined' || obj === null;
            },
            isObject: function (obj) {
                return obj === Object(obj);
            },
            has: function (obj, key) {
                return Object.hasOwnProperty.call(obj, key);
            },
            isString: function (obj) {
                return Object.prototype.toString.call(obj) == '[object String]';
            },
            isBoolean: function (obj) {
                return Object.prototype.toString.call(obj) == '[object Boolean]';
            },
            isType: function (obj, type) {
                return Object.prototype.toString.call(obj) == '[object ' + type + ']';
            },
            isNumber: function (obj) {
                return !isNaN(parseFloat(obj)) && isFinite(obj);
            },
            isEmpty: function (obj) {
                if (obj === null) {
                    return true;
                }
                if (isArray(obj) || Utils.isString(obj)) {
                    return obj.length === 0;
                }
                for (var key in obj) {
                    if (Utils.has(obj, key)) {
                        return false;
                    }
                }
                return true;
            },
            simpleExtend: function (destination, source) {
                if (!Utils.isObject(source)) {
                    return;
                }
                for (var name in source) {
                    destination[name] = source[name];
                }
            },
            initArray: function createIdArray(size, value) {
                var array = [];
                for (var i = 0; i < size; ++i) {
                    array[i] = value;
                }
                return array;
            },
            serializePoints: function (points) {
                var res = [];
                for (var i = 0; i < points.length; i++) {
                    var p = points[i];
                    res.push(p.x + ';' + p.y);
                }
                return res.join(';');
            },
            deserializePoints: function (s) {
                var v = s.split(';'), points = [];
                if (v.length % 2 !== 0) {
                    throw 'Not an array of points.';
                }
                for (var i = 0; i < v.length; i += 2) {
                    points.push(new diagram.Point(parseInt(v[i], 10), parseInt(v[i + 1], 10)));
                }
                return points;
            },
            randomInteger: function (lower, upper) {
                return parseInt(Math.floor(Math.random() * upper) + lower, 10);
            },
            DFT: function (el, func) {
                func(el);
                if (el.childNodes) {
                    for (var i = 0; i < el.childNodes.length; i++) {
                        var item = el.childNodes[i];
                        this.DFT(item, func);
                    }
                }
            },
            getMatrixAngle: function (m) {
                if (m === null || m.d === 0) {
                    return 0;
                }
                return Math.atan2(m.b, m.d) * 180 / Math.PI;
            },
            getMatrixScaling: function (m) {
                var sX = Math.sqrt(m.a * m.a + m.c * m.c);
                var sY = Math.sqrt(m.b * m.b + m.d * m.d);
                return [
                    sX,
                    sY
                ];
            }
        });
        function Range(start, stop, step) {
            if (typeof start == 'undefined' || typeof stop == 'undefined') {
                return [];
            }
            if (step && Utils.sign(stop - start) != Utils.sign(step)) {
                throw 'The sign of the increment should allow to reach the stop-value.';
            }
            step = step || 1;
            start = start || 0;
            stop = stop || start;
            if ((stop - start) / step === Infinity) {
                throw 'Infinite range defined.';
            }
            var range = [], i = -1, j;
            function rangeIntegerScale(x) {
                var k = 1;
                while (x * k % 1) {
                    k *= 10;
                }
                return k;
            }
            var k = rangeIntegerScale(Math.abs(step));
            start *= k;
            stop *= k;
            step *= k;
            if (start > stop && step > 0) {
                step = -step;
            }
            if (step < 0) {
                while ((j = start + step * ++i) >= stop) {
                    range.push(j / k);
                }
            } else {
                while ((j = start + step * ++i) <= stop) {
                    range.push(j / k);
                }
            }
            return range;
        }
        function findRadian(start, end) {
            if (start == end) {
                return 0;
            }
            var sngXComp = end.x - start.x, sngYComp = start.y - end.y, atan = Math.atan(sngXComp / sngYComp);
            if (sngYComp >= 0) {
                return sngXComp < 0 ? atan + 2 * Math.PI : atan;
            }
            return atan + Math.PI;
        }
        Utils.sign = function (number) {
            return number ? number < 0 ? -1 : 1 : 0;
        };
        Utils.findAngle = function (center, end) {
            return findRadian(center, end) * 180 / Math.PI;
        };
        Utils.forEach = function (arr, iterator, thisRef) {
            for (var i = 0; i < arr.length; i++) {
                iterator.call(thisRef, arr[i], i, arr);
            }
        };
        Utils.any = function (arr, predicate) {
            for (var i = 0; i < arr.length; ++i) {
                if (predicate(arr[i])) {
                    return arr[i];
                }
            }
            return null;
        };
        Utils.remove = function (arr, what) {
            var ax;
            while ((ax = Utils.indexOf(arr, what)) !== -1) {
                arr.splice(ax, 1);
            }
            return arr;
        };
        Utils.contains = function (arr, obj) {
            return Utils.indexOf(arr, obj) !== -1;
        };
        Utils.indexOf = function (arr, what) {
            return $.inArray(what, arr);
        };
        Utils.fold = function (list, iterator, acc, context) {
            var initial = arguments.length > 2;
            for (var i = 0; i < list.length; i++) {
                var value = list[i];
                if (!initial) {
                    acc = value;
                    initial = true;
                } else {
                    acc = iterator.call(context, acc, value, i, list);
                }
            }
            if (!initial) {
                throw 'Reduce of empty array with no initial value';
            }
            return acc;
        };
        Utils.find = function (arr, iterator, context) {
            var result;
            Utils.any(arr, function (value, index, list) {
                if (iterator.call(context, value, index, list)) {
                    result = value;
                    return true;
                }
                return false;
            });
            return result;
        };
        Utils.first = function (arr, constraint, context) {
            if (arr.length === 0) {
                return null;
            }
            if (Utils.isUndefined(constraint)) {
                return arr[0];
            }
            return Utils.find(arr, constraint, context);
        };
        Utils.insert = function (arr, element, position) {
            arr.splice(position, 0, element);
            return arr;
        };
        Utils.all = function (arr, iterator, context) {
            var result = true;
            var value;
            for (var i = 0; i < arr.length; i++) {
                value = arr[i];
                result = result && iterator.call(context, value, i, arr);
                if (!result) {
                    break;
                }
            }
            return result;
        };
        Utils.clear = function (arr) {
            arr.splice(0, arr.length);
        };
        Utils.bisort = function (a, b, sortfunc) {
            if (Utils.isUndefined(a)) {
                throw 'First array is not specified.';
            }
            if (Utils.isUndefined(b)) {
                throw 'Second array is not specified.';
            }
            if (a.length != b.length) {
                throw 'The two arrays should have equal length';
            }
            var all = [], i;
            for (i = 0; i < a.length; i++) {
                all.push({
                    'x': a[i],
                    'y': b[i]
                });
            }
            if (Utils.isUndefined(sortfunc)) {
                all.sort(function (m, n) {
                    return m.x - n.x;
                });
            } else {
                all.sort(function (m, n) {
                    return sortfunc(m.x, n.x);
                });
            }
            Utils.clear(a);
            Utils.clear(b);
            for (i = 0; i < all.length; i++) {
                a.push(all[i].x);
                b.push(all[i].y);
            }
        };
        Utils.addRange = function (arr, range) {
            arr.push.apply(arr, range);
        };
        var Easing = {
            easeInOut: function (pos) {
                return -Math.cos(pos * Math.PI) / 2 + 0.5;
            }
        };
        var Ticker = kendo.Class.extend({
            init: function () {
                this.adapters = [];
                this.target = 0;
                this.tick = 0;
                this.interval = 20;
                this.duration = 800;
                this.lastTime = null;
                this.handlers = [];
                var _this = this;
                this.transition = Easing.easeInOut;
                this.timerDelegate = function () {
                    _this.onTimerEvent();
                };
            },
            addAdapter: function (a) {
                this.adapters.push(a);
            },
            onComplete: function (handler) {
                this.handlers.push(handler);
            },
            removeHandler: function (handler) {
                this.handlers = $.grep(this.handlers, function (h) {
                    return h !== handler;
                });
            },
            trigger: function () {
                var _this = this;
                if (this.handlers) {
                    Utils.forEach(this.handlers, function (h) {
                        return h.call(_this.caller !== null ? _this.caller : _this);
                    });
                }
            },
            onStep: function () {
            },
            seekTo: function (to) {
                this.seekFromTo(this.tick, to);
            },
            seekFromTo: function (from, to) {
                this.target = Math.max(0, Math.min(1, to));
                this.tick = Math.max(0, Math.min(1, from));
                this.lastTime = new Date().getTime();
                if (!this.intervalId) {
                    this.intervalId = window.setInterval(this.timerDelegate, this.interval);
                }
            },
            stop: function () {
                if (this.intervalId) {
                    window.clearInterval(this.intervalId);
                    this.intervalId = null;
                    this.trigger();
                }
            },
            play: function (origin) {
                if (this.adapters.length === 0) {
                    return;
                }
                if (origin !== null) {
                    this.caller = origin;
                }
                this.initState();
                this.seekFromTo(0, 1);
            },
            reverse: function () {
                this.seekFromTo(1, 0);
            },
            initState: function () {
                if (this.adapters.length === 0) {
                    return;
                }
                for (var i = 0; i < this.adapters.length; i++) {
                    this.adapters[i].initState();
                }
            },
            propagate: function () {
                var value = this.transition(this.tick);
                for (var i = 0; i < this.adapters.length; i++) {
                    this.adapters[i].update(value);
                }
            },
            onTimerEvent: function () {
                var now = new Date().getTime();
                var timePassed = now - this.lastTime;
                this.lastTime = now;
                var movement = timePassed / this.duration * (this.tick < this.target ? 1 : -1);
                if (Math.abs(movement) >= Math.abs(this.tick - this.target)) {
                    this.tick = this.target;
                } else {
                    this.tick += movement;
                }
                try {
                    this.propagate();
                } finally {
                    this.onStep.call(this);
                    if (this.target == this.tick) {
                        this.stop();
                    }
                }
            }
        });
        kendo.deepExtend(diagram, {
            init: function (element) {
                kendo.init(element, diagram.ui);
            },
            Utils: Utils,
            Range: Range,
            Ticker: Ticker
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/diagram/math', [
        'dataviz/diagram/utils',
        'kendo.dataviz.core'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, diagram = kendo.dataviz.diagram, Class = kendo.Class, deepExtend = kendo.deepExtend, dataviz = kendo.dataviz, Utils = diagram.Utils, Point = dataviz.Point2D, isFunction = kendo.isFunction, contains = Utils.contains, map = $.map;
        var HITTESTAREA = 3, EPSILON = 0.000001;
        deepExtend(Point.fn, {
            plus: function (p) {
                return new Point(this.x + p.x, this.y + p.y);
            },
            minus: function (p) {
                return new Point(this.x - p.x, this.y - p.y);
            },
            offset: function (value) {
                return new Point(this.x - value, this.y - value);
            },
            times: function (s) {
                return new Point(this.x * s, this.y * s);
            },
            normalize: function () {
                if (this.length() === 0) {
                    return new Point();
                }
                return this.times(1 / this.length());
            },
            length: function () {
                return Math.sqrt(this.x * this.x + this.y * this.y);
            },
            toString: function () {
                return '(' + this.x + ',' + this.y + ')';
            },
            lengthSquared: function () {
                return this.x * this.x + this.y * this.y;
            },
            middleOf: function MiddleOf(p, q) {
                return new Point(q.x - p.x, q.y - p.y).times(0.5).plus(p);
            },
            toPolar: function (useDegrees) {
                var factor = 1;
                if (useDegrees) {
                    factor = 180 / Math.PI;
                }
                var a = Math.atan2(Math.abs(this.y), Math.abs(this.x));
                var halfpi = Math.PI / 2;
                var len = this.length();
                if (this.x === 0) {
                    if (this.y === 0) {
                        return new Polar(0, 0);
                    }
                    if (this.y > 0) {
                        return new Polar(len, factor * halfpi);
                    }
                    if (this.y < 0) {
                        return new Polar(len, factor * 3 * halfpi);
                    }
                } else if (this.x > 0) {
                    if (this.y === 0) {
                        return new Polar(len, 0);
                    }
                    if (this.y > 0) {
                        return new Polar(len, factor * a);
                    }
                    if (this.y < 0) {
                        return new Polar(len, factor * (4 * halfpi - a));
                    }
                } else {
                    if (this.y === 0) {
                        return new Polar(len, 2 * halfpi);
                    }
                    if (this.y > 0) {
                        return new Polar(len, factor * (2 * halfpi - a));
                    }
                    if (this.y < 0) {
                        return new Polar(len, factor * (2 * halfpi + a));
                    }
                }
            },
            isOnLine: function (from, to) {
                if (from.x > to.x) {
                    var temp = to;
                    to = from;
                    from = temp;
                }
                var r1 = new Rect(from.x, from.y).inflate(HITTESTAREA, HITTESTAREA), r2 = new Rect(to.x, to.y).inflate(HITTESTAREA, HITTESTAREA), o1, u1;
                if (r1.union(r2).contains(this)) {
                    if (from.x === to.x || from.y === to.y) {
                        return true;
                    } else if (from.y < to.y) {
                        o1 = r1.x + (r2.x - r1.x) * (this.y - (r1.y + r1.height)) / (r2.y + r2.height - (r1.y + r1.height));
                        u1 = r1.x + r1.width + (r2.x + r2.width - (r1.x + r1.width)) * (this.y - r1.y) / (r2.y - r1.y);
                    } else {
                        o1 = r1.x + (r2.x - r1.x) * (this.y - r1.y) / (r2.y - r1.y);
                        u1 = r1.x + r1.width + (r2.x + r2.width - (r1.x + r1.width)) * (this.y - (r1.y + r1.height)) / (r2.y + r2.height - (r1.y + r1.height));
                    }
                    return this.x > o1 && this.x < u1;
                }
                return false;
            }
        });
        deepExtend(Point, {
            parse: function (str) {
                var tempStr = str.slice(1, str.length - 1), xy = tempStr.split(','), x = parseInt(xy[0], 10), y = parseInt(xy[1], 10);
                if (!isNaN(x) && !isNaN(y)) {
                    return new Point(x, y);
                }
            }
        });
        var PathDefiner = Class.extend({
            init: function (p, left, right) {
                this.point = p;
                this.left = left;
                this.right = right;
            }
        });
        var Rect = Class.extend({
            init: function (x, y, width, height) {
                this.x = x || 0;
                this.y = y || 0;
                this.width = width || 0;
                this.height = height || 0;
            },
            contains: function (point) {
                return point.x >= this.x && point.x <= this.x + this.width && point.y >= this.y && point.y <= this.y + this.height;
            },
            inflate: function (dx, dy) {
                if (dy === undefined) {
                    dy = dx;
                }
                this.x -= dx;
                this.y -= dy;
                this.width += 2 * dx + 1;
                this.height += 2 * dy + 1;
                return this;
            },
            offset: function (dx, dy) {
                var x = dx, y = dy;
                if (dx instanceof Point) {
                    x = dx.x;
                    y = dx.y;
                }
                this.x += x;
                this.y += y;
                return this;
            },
            union: function (r) {
                var x1 = Math.min(this.x, r.x);
                var y1 = Math.min(this.y, r.y);
                var x2 = Math.max(this.x + this.width, r.x + r.width);
                var y2 = Math.max(this.y + this.height, r.y + r.height);
                return new Rect(x1, y1, x2 - x1, y2 - y1);
            },
            center: function () {
                return new Point(this.x + this.width / 2, this.y + this.height / 2);
            },
            top: function () {
                return new Point(this.x + this.width / 2, this.y);
            },
            right: function () {
                return new Point(this.x + this.width, this.y + this.height / 2);
            },
            bottom: function () {
                return new Point(this.x + this.width / 2, this.y + this.height);
            },
            left: function () {
                return new Point(this.x, this.y + this.height / 2);
            },
            topLeft: function () {
                return new Point(this.x, this.y);
            },
            topRight: function () {
                return new Point(this.x + this.width, this.y);
            },
            bottomLeft: function () {
                return new Point(this.x, this.y + this.height);
            },
            bottomRight: function () {
                return new Point(this.x + this.width, this.y + this.height);
            },
            clone: function () {
                return new Rect(this.x, this.y, this.width, this.height);
            },
            isEmpty: function () {
                return !this.width && !this.height;
            },
            equals: function (rect) {
                return this.x === rect.x && this.y === rect.y && this.width === rect.width && this.height === rect.height;
            },
            rotatedBounds: function (angle) {
                var rect = this.clone(), points = this.rotatedPoints(angle), tl = points[0], tr = points[1], br = points[2], bl = points[3];
                rect.x = Math.min(br.x, tl.x, tr.x, bl.x);
                rect.y = Math.min(br.y, tl.y, tr.y, bl.y);
                rect.width = Math.max(br.x, tl.x, tr.x, bl.x) - rect.x;
                rect.height = Math.max(br.y, tl.y, tr.y, bl.y) - rect.y;
                return rect;
            },
            rotatedPoints: function (angle) {
                var rect = this, c = rect.center(), br = rect.bottomRight().rotate(c, 360 - angle), tl = rect.topLeft().rotate(c, 360 - angle), tr = rect.topRight().rotate(c, 360 - angle), bl = rect.bottomLeft().rotate(c, 360 - angle);
                return [
                    tl,
                    tr,
                    br,
                    bl
                ];
            },
            toString: function (delimiter) {
                delimiter = delimiter || ' ';
                return this.x + delimiter + this.y + delimiter + this.width + delimiter + this.height;
            },
            scale: function (scaleX, scaleY, staicPoint, adornerCenter, angle) {
                var tl = this.topLeft();
                var thisCenter = this.center();
                tl.rotate(thisCenter, 360 - angle).rotate(adornerCenter, angle);
                var delta = staicPoint.minus(tl);
                var scaled = new Point(delta.x * scaleX, delta.y * scaleY);
                var position = delta.minus(scaled);
                tl = tl.plus(position);
                tl.rotate(adornerCenter, 360 - angle).rotate(thisCenter, angle);
                this.x = tl.x;
                this.y = tl.y;
                this.width *= scaleX;
                this.height *= scaleY;
            },
            zoom: function (zoom) {
                this.x *= zoom;
                this.y *= zoom;
                this.width *= zoom;
                this.height *= zoom;
                return this;
            },
            overlaps: function (rect) {
                var bottomRight = this.bottomRight();
                var rectBottomRight = rect.bottomRight();
                var overlaps = !(bottomRight.x < rect.x || bottomRight.y < rect.y || rectBottomRight.x < this.x || rectBottomRight.y < this.y);
                return overlaps;
            }
        });
        var Size = Class.extend({
            init: function (width, height) {
                this.width = width;
                this.height = height;
            }
        });
        Size.prototype.Empty = new Size(0, 0);
        Rect.toRect = function (rect) {
            if (!(rect instanceof Rect)) {
                rect = new Rect(rect.x, rect.y, rect.width, rect.height);
            }
            return rect;
        };
        Rect.empty = function () {
            return new Rect(0, 0, 0, 0);
        };
        Rect.fromPoints = function (p, q) {
            if (isNaN(p.x) || isNaN(p.y) || isNaN(q.x) || isNaN(q.y)) {
                throw 'Some values are NaN.';
            }
            return new Rect(Math.min(p.x, q.x), Math.min(p.y, q.y), Math.abs(p.x - q.x), Math.abs(p.y - q.y));
        };
        function isNearZero(num) {
            return Math.abs(num) < EPSILON;
        }
        function intersectLine(start1, end1, start2, end2, isSegment) {
            var tangensdiff = (end1.x - start1.x) * (end2.y - start2.y) - (end1.y - start1.y) * (end2.x - start2.x);
            if (isNearZero(tangensdiff)) {
                return;
            }
            var num1 = (start1.y - start2.y) * (end2.x - start2.x) - (start1.x - start2.x) * (end2.y - start2.y);
            var num2 = (start1.y - start2.y) * (end1.x - start1.x) - (start1.x - start2.x) * (end1.y - start1.y);
            var r = num1 / tangensdiff;
            var s = num2 / tangensdiff;
            if (isSegment && (r < 0 || r > 1 || s < 0 || s > 1)) {
                return;
            }
            return new Point(start1.x + r * (end1.x - start1.x), start1.y + r * (end1.y - start1.y));
        }
        var Intersect = {
            lines: function (start1, end1, start2, end2) {
                return intersectLine(start1, end1, start2, end2);
            },
            segments: function (start1, end1, start2, end2) {
                return intersectLine(start1, end1, start2, end2, true);
            },
            rectWithLine: function (rect, start, end) {
                return Intersect.segments(start, end, rect.topLeft(), rect.topRight()) || Intersect.segments(start, end, rect.topRight(), rect.bottomRight()) || Intersect.segments(start, end, rect.bottomLeft(), rect.bottomRight()) || Intersect.segments(start, end, rect.topLeft(), rect.bottomLeft());
            },
            rects: function (rect1, rect2, angle) {
                var tl = rect2.topLeft(), tr = rect2.topRight(), bl = rect2.bottomLeft(), br = rect2.bottomRight();
                var center = rect2.center();
                if (angle) {
                    tl = tl.rotate(center, angle);
                    tr = tr.rotate(center, angle);
                    bl = bl.rotate(center, angle);
                    br = br.rotate(center, angle);
                }
                var intersect = rect1.contains(tl) || rect1.contains(tr) || rect1.contains(bl) || rect1.contains(br) || Intersect.rectWithLine(rect1, tl, tr) || Intersect.rectWithLine(rect1, tl, bl) || Intersect.rectWithLine(rect1, tr, br) || Intersect.rectWithLine(rect1, bl, br);
                if (!intersect) {
                    tl = rect1.topLeft();
                    tr = rect1.topRight();
                    bl = rect1.bottomLeft();
                    br = rect1.bottomRight();
                    if (angle) {
                        var reverseAngle = 360 - angle;
                        tl = tl.rotate(center, reverseAngle);
                        tr = tr.rotate(center, reverseAngle);
                        bl = bl.rotate(center, reverseAngle);
                        br = br.rotate(center, reverseAngle);
                    }
                    intersect = rect2.contains(tl) || rect2.contains(tr) || rect2.contains(bl) || rect2.contains(br);
                }
                return intersect;
            }
        };
        var RectAlign = Class.extend({
            init: function (container) {
                this.container = Rect.toRect(container);
            },
            align: function (content, alignment) {
                var alignValues = alignment.toLowerCase().split(' ');
                for (var i = 0; i < alignValues.length; i++) {
                    content = this._singleAlign(content, alignValues[i]);
                }
                return content;
            },
            _singleAlign: function (content, alignment) {
                if (isFunction(this[alignment])) {
                    return this[alignment](content);
                } else {
                    return content;
                }
            },
            left: function (content) {
                return this._align(content, this._left);
            },
            center: function (content) {
                return this._align(content, this._center);
            },
            right: function (content) {
                return this._align(content, this._right);
            },
            stretch: function (content) {
                return this._align(content, this._stretch);
            },
            top: function (content) {
                return this._align(content, this._top);
            },
            middle: function (content) {
                return this._align(content, this._middle);
            },
            bottom: function (content) {
                return this._align(content, this._bottom);
            },
            _left: function (container, content) {
                content.x = container.x;
            },
            _center: function (container, content) {
                content.x = (container.width - content.width) / 2 || 0;
            },
            _right: function (container, content) {
                content.x = container.width - content.width;
            },
            _top: function (container, content) {
                content.y = container.y;
            },
            _middle: function (container, content) {
                content.y = (container.height - content.height) / 2 || 0;
            },
            _bottom: function (container, content) {
                content.y = container.height - content.height;
            },
            _stretch: function (container, content) {
                content.x = 0;
                content.y = 0;
                content.height = container.height;
                content.width = container.width;
            },
            _align: function (content, alignCalc) {
                content = Rect.toRect(content);
                alignCalc(this.container, content);
                return content;
            }
        });
        var Polar = Class.extend({
            init: function (r, a) {
                this.r = r;
                this.angle = a;
            }
        });
        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;
            },
            plus: function (m) {
                this.a += m.a;
                this.b += m.b;
                this.c += m.c;
                this.d += m.d;
                this.e += m.e;
                this.f += m.f;
            },
            minus: function (m) {
                this.a -= m.a;
                this.b -= m.b;
                this.c -= m.c;
                this.d -= m.d;
                this.e -= m.e;
                this.f -= m.f;
            },
            times: 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);
            },
            apply: function (p) {
                return new Point(this.a * p.x + this.c * p.y + this.e, this.b * p.x + this.d * p.y + this.f);
            },
            applyRect: function (r) {
                return Rect.fromPoints(this.apply(r.topLeft()), this.apply(r.bottomRight()));
            },
            toString: function () {
                return 'matrix(' + this.a + ' ' + this.b + ' ' + this.c + ' ' + this.d + ' ' + this.e + ' ' + this.f + ')';
            }
        });
        deepExtend(Matrix, {
            fromSVGMatrix: function (vm) {
                var m = new Matrix();
                m.a = vm.a;
                m.b = vm.b;
                m.c = vm.c;
                m.d = vm.d;
                m.e = vm.e;
                m.f = vm.f;
                return m;
            },
            fromMatrixVector: function (v) {
                var m = new Matrix();
                m.a = v.a;
                m.b = v.b;
                m.c = v.c;
                m.d = v.d;
                m.e = v.e;
                m.f = v.f;
                return m;
            },
            fromList: function (v) {
                if (v.length !== 6) {
                    throw 'The given list should consist of six elements.';
                }
                var m = new Matrix();
                m.a = v[0];
                m.b = v[1];
                m.c = v[2];
                m.d = v[3];
                m.e = v[4];
                m.f = v[5];
                return m;
            },
            translation: function (x, y) {
                var m = new Matrix();
                m.a = 1;
                m.b = 0;
                m.c = 0;
                m.d = 1;
                m.e = x;
                m.f = y;
                return m;
            },
            unit: function () {
                return new Matrix(1, 0, 0, 1, 0, 0);
            },
            rotation: function (angle, x, y) {
                var m = new Matrix();
                m.a = Math.cos(angle * Math.PI / 180);
                m.b = Math.sin(angle * Math.PI / 180);
                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;
            },
            scaling: function (scaleX, scaleY) {
                var m = new Matrix();
                m.a = scaleX;
                m.b = 0;
                m.c = 0;
                m.d = scaleY;
                m.e = 0;
                m.f = 0;
                return m;
            },
            parse: function (v) {
                var parts, nums;
                if (v) {
                    v = v.trim();
                    if (v.slice(0, 6).toLowerCase() === 'matrix') {
                        nums = v.slice(7, v.length - 1).trim();
                        parts = nums.split(',');
                        if (parts.length === 6) {
                            return Matrix.fromList(map(parts, function (p) {
                                return parseFloat(p);
                            }));
                        }
                        parts = nums.split(' ');
                        if (parts.length === 6) {
                            return Matrix.fromList(map(parts, function (p) {
                                return parseFloat(p);
                            }));
                        }
                    }
                    if (v.slice(0, 1) === '(' && v.slice(v.length - 1) === ')') {
                        v = v.substr(1, v.length - 1);
                    }
                    if (v.indexOf(',') > 0) {
                        parts = v.split(',');
                        if (parts.length === 6) {
                            return Matrix.fromList(map(parts, function (p) {
                                return parseFloat(p);
                            }));
                        }
                    }
                    if (v.indexOf(' ') > 0) {
                        parts = v.split(' ');
                        if (parts.length === 6) {
                            return Matrix.fromList(map(parts, function (p) {
                                return parseFloat(p);
                            }));
                        }
                    }
                }
                return parts;
            }
        });
        var MatrixVector = 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;
            },
            fromMatrix: function FromMatrix(m) {
                var v = new MatrixVector();
                v.a = m.a;
                v.b = m.b;
                v.c = m.c;
                v.d = m.d;
                v.e = m.e;
                v.f = m.f;
                return v;
            }
        });
        function normalVariable(mean, deviation) {
            var x, y, r;
            do {
                x = Math.random() * 2 - 1;
                y = Math.random() * 2 - 1;
                r = x * x + y * y;
            } while (!r || r > 1);
            return mean + deviation * x * Math.sqrt(-2 * Math.log(r) / r);
        }
        function randomId(length) {
            if (Utils.isUndefined(length)) {
                length = 10;
            }
            var result = '';
            var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
            for (var i = length; i > 0; --i) {
                result += chars.charAt(Math.round(Math.random() * (chars.length - 1)));
            }
            return result;
        }
        var Geometry = {
            _distanceToLineSquared: function (p, a, b) {
                function d2(pt1, pt2) {
                    return (pt1.x - pt2.x) * (pt1.x - pt2.x) + (pt1.y - pt2.y) * (pt1.y - pt2.y);
                }
                if (a === b) {
                    return d2(p, a);
                }
                var vx = b.x - a.x, vy = b.y - a.y, dot = (p.x - a.x) * vx + (p.y - a.y) * vy;
                if (dot < 0) {
                    return d2(a, p);
                }
                dot = (b.x - p.x) * vx + (b.y - p.y) * vy;
                if (dot < 0) {
                    return d2(b, p);
                }
                dot = (b.x - p.x) * vy - (b.y - p.y) * vx;
                return dot * dot / (vx * vx + vy * vy);
            },
            distanceToLine: function (p, a, b) {
                return Math.sqrt(this._distanceToLineSquared(p, a, b));
            },
            distanceToPolyline: function (p, points) {
                var minimum = Number.MAX_VALUE;
                if (Utils.isUndefined(points) || points.length === 0) {
                    return Number.MAX_VALUE;
                }
                for (var s = 0; s < points.length - 1; s++) {
                    var p1 = points[s];
                    var p2 = points[s + 1];
                    var d = this._distanceToLineSquared(p, p1, p2);
                    if (d < minimum) {
                        minimum = d;
                    }
                }
                return Math.sqrt(minimum);
            }
        };
        var HashTable = kendo.Class.extend({
            init: function () {
                this._buckets = [];
                this.length = 0;
            },
            add: function (key, value) {
                var obj = this._createGetBucket(key);
                if (Utils.isDefined(value)) {
                    obj.value = value;
                }
                return obj;
            },
            get: function (key) {
                if (this._bucketExists(key)) {
                    return this._createGetBucket(key);
                }
                return null;
            },
            set: function (key, value) {
                this.add(key, value);
            },
            containsKey: function (key) {
                return this._bucketExists(key);
            },
            remove: function (key) {
                if (this._bucketExists(key)) {
                    var hashId = this._hash(key);
                    delete this._buckets[hashId];
                    this.length--;
                    return key;
                }
            },
            forEach: function (func) {
                var hashes = this._hashes();
                for (var i = 0, len = hashes.length; i < len; i++) {
                    var hash = hashes[i];
                    var bucket = this._buckets[hash];
                    if (Utils.isUndefined(bucket)) {
                        continue;
                    }
                    func(bucket);
                }
            },
            clone: function () {
                var ht = new HashTable();
                var hashes = this._hashes();
                for (var i = 0, len = hashes.length; i < len; i++) {
                    var hash = hashes[i];
                    var bucket = this._buckets[hash];
                    if (Utils.isUndefined(bucket)) {
                        continue;
                    }
                    ht.add(bucket.key, bucket.value);
                }
                return ht;
            },
            _hashes: function () {
                var hashes = [];
                for (var hash in this._buckets) {
                    if (this._buckets.hasOwnProperty(hash)) {
                        hashes.push(hash);
                    }
                }
                return hashes;
            },
            _bucketExists: function (key) {
                var hashId = this._hash(key);
                return Utils.isDefined(this._buckets[hashId]);
            },
            _createGetBucket: function (key) {
                var hashId = this._hash(key);
                var bucket = this._buckets[hashId];
                if (Utils.isUndefined(bucket)) {
                    bucket = { key: key };
                    this._buckets[hashId] = bucket;
                    this.length++;
                }
                return bucket;
            },
            _hash: function (key) {
                if (Utils.isNumber(key)) {
                    return key;
                }
                if (Utils.isString(key)) {
                    return this._hashString(key);
                }
                if (Utils.isObject(key)) {
                    return this._objectHashId(key);
                }
                throw 'Unsupported key type.';
            },
            _hashString: function (s) {
                var result = 0;
                if (s.length === 0) {
                    return result;
                }
                for (var i = 0; i < s.length; i++) {
                    var ch = s.charCodeAt(i);
                    result = result * 32 - result + ch;
                }
                return result;
            },
            _objectHashId: function (key) {
                var id = key._hashId;
                if (Utils.isUndefined(id)) {
                    id = randomId();
                    key._hashId = id;
                }
                return id;
            }
        });
        var Dictionary = kendo.Observable.extend({
            init: function (dictionary) {
                var that = this;
                kendo.Observable.fn.init.call(that);
                this._hashTable = new HashTable();
                this.length = 0;
                if (Utils.isDefined(dictionary)) {
                    if ($.isArray(dictionary)) {
                        for (var i = 0; i < dictionary.length; i++) {
                            this.add(dictionary[i]);
                        }
                    } else {
                        dictionary.forEach(function (k, v) {
                            this.add(k, v);
                        }, this);
                    }
                }
            },
            add: function (key, value) {
                var entry = this._hashTable.get(key);
                if (!entry) {
                    entry = this._hashTable.add(key);
                    this.length++;
                    this.trigger('changed');
                }
                entry.value = value;
            },
            set: function (key, value) {
                this.add(key, value);
            },
            get: function (key) {
                var entry = this._hashTable.get(key);
                if (entry) {
                    return entry.value;
                }
                throw new Error('Cannot find key ' + key);
            },
            containsKey: function (key) {
                return this._hashTable.containsKey(key);
            },
            remove: function (key) {
                if (this.containsKey(key)) {
                    this.trigger('changed');
                    this.length--;
                    return this._hashTable.remove(key);
                }
            },
            forEach: function (func, thisRef) {
                this._hashTable.forEach(function (entry) {
                    func.call(thisRef, entry.key, entry.value);
                });
            },
            forEachValue: function (func, thisRef) {
                this._hashTable.forEach(function (entry) {
                    func.call(thisRef, entry.value);
                });
            },
            forEachKey: function (func, thisRef) {
                this._hashTable.forEach(function (entry) {
                    func.call(thisRef, entry.key);
                });
            },
            keys: function () {
                var keys = [];
                this.forEachKey(function (key) {
                    keys.push(key);
                });
                return keys;
            }
        });
        var Queue = kendo.Class.extend({
            init: function () {
                this._tail = null;
                this._head = null;
                this.length = 0;
            },
            enqueue: function (value) {
                var entry = {
                    value: value,
                    next: null
                };
                if (!this._head) {
                    this._head = entry;
                    this._tail = this._head;
                } else {
                    this._tail.next = entry;
                    this._tail = this._tail.next;
                }
                this.length++;
            },
            dequeue: function () {
                if (this.length < 1) {
                    throw new Error('The queue is empty.');
                }
                var value = this._head.value;
                this._head = this._head.next;
                this.length--;
                return value;
            },
            contains: function (item) {
                var current = this._head;
                while (current) {
                    if (current.value === item) {
                        return true;
                    }
                    current = current.next;
                }
                return false;
            }
        });
        var Set = kendo.Observable.extend({
            init: function (resource) {
                var that = this;
                kendo.Observable.fn.init.call(that);
                this._hashTable = new HashTable();
                this.length = 0;
                if (Utils.isDefined(resource)) {
                    if (resource instanceof HashTable) {
                        resource.forEach(function (d) {
                            this.add(d);
                        });
                    } else if (resource instanceof Dictionary) {
                        resource.forEach(function (k, v) {
                            this.add({
                                key: k,
                                value: v
                            });
                        }, this);
                    }
                }
            },
            contains: function (item) {
                return this._hashTable.containsKey(item);
            },
            add: function (item) {
                var entry = this._hashTable.get(item);
                if (!entry) {
                    this._hashTable.add(item, item);
                    this.length++;
                    this.trigger('changed');
                }
            },
            get: function (item) {
                if (this.contains(item)) {
                    return this._hashTable.get(item).value;
                } else {
                    return null;
                }
            },
            hash: function (item) {
                return this._hashTable._hash(item);
            },
            remove: function (item) {
                if (this.contains(item)) {
                    this._hashTable.remove(item);
                    this.length--;
                    this.trigger('changed');
                }
            },
            forEach: function (func, context) {
                this._hashTable.forEach(function (kv) {
                    func(kv.value);
                }, context);
            },
            toArray: function () {
                var r = [];
                this.forEach(function (d) {
                    r.push(d);
                });
                return r;
            }
        });
        var Node = kendo.Class.extend({
            init: function (id, shape) {
                this.links = [];
                this.outgoing = [];
                this.incoming = [];
                this.weight = 1;
                if (Utils.isDefined(id)) {
                    this.id = id;
                } else {
                    this.id = randomId();
                }
                if (Utils.isDefined(shape)) {
                    this.associatedShape = shape;
                    var b = shape.bounds();
                    this.width = b.width;
                    this.height = b.height;
                    this.x = b.x;
                    this.y = b.y;
                } else {
                    this.associatedShape = null;
                }
                this.data = null;
                this.type = 'Node';
                this.shortForm = 'Node \'' + this.id + '\'';
                this.isVirtual = false;
            },
            isIsolated: function () {
                return Utils.isEmpty(this.links);
            },
            bounds: function (r) {
                if (!Utils.isDefined(r)) {
                    return new diagram.Rect(this.x, this.y, this.width, this.height);
                }
                this.x = r.x;
                this.y = r.y;
                this.width = r.width;
                this.height = r.height;
            },
            isLinkedTo: function (node) {
                var that = this;
                return Utils.any(that.links, function (link) {
                    return link.getComplement(that) === node;
                });
            },
            getChildren: function () {
                if (this.outgoing.length === 0) {
                    return [];
                }
                var children = [];
                for (var i = 0, len = this.outgoing.length; i < len; i++) {
                    var link = this.outgoing[i];
                    children.push(link.getComplement(this));
                }
                return children;
            },
            getParents: function () {
                if (this.incoming.length === 0) {
                    return [];
                }
                var parents = [];
                for (var i = 0, len = this.incoming.length; i < len; i++) {
                    var link = this.incoming[i];
                    parents.push(link.getComplement(this));
                }
                return parents;
            },
            clone: function () {
                var copy = new Node();
                if (Utils.isDefined(this.weight)) {
                    copy.weight = this.weight;
                }
                if (Utils.isDefined(this.balance)) {
                    copy.balance = this.balance;
                }
                if (Utils.isDefined(this.owner)) {
                    copy.owner = this.owner;
                }
                copy.associatedShape = this.associatedShape;
                copy.x = this.x;
                copy.y = this.y;
                copy.width = this.width;
                copy.height = this.height;
                return copy;
            },
            adjacentTo: function (node) {
                return this.isLinkedTo(node) !== null;
            },
            removeLink: function (link) {
                if (link.source === this) {
                    Utils.remove(this.links, link);
                    Utils.remove(this.outgoing, link);
                    link.source = null;
                }
                if (link.target === this) {
                    Utils.remove(this.links, link);
                    Utils.remove(this.incoming, link);
                    link.target = null;
                }
            },
            hasLinkTo: function (node) {
                return Utils.any(this.outgoing, function (link) {
                    return link.target === node;
                });
            },
            degree: function () {
                return this.links.length;
            },
            incidentWith: function (link) {
                return contains(this.links, link);
            },
            getLinksWith: function (node) {
                return Utils.all(this.links, function (link) {
                    return link.getComplement(this) === node;
                }, this);
            },
            getNeighbors: function () {
                var neighbors = [];
                Utils.forEach(this.incoming, function (e) {
                    neighbors.push(e.getComplement(this));
                }, this);
                Utils.forEach(this.outgoing, function (e) {
                    neighbors.push(e.getComplement(this));
                }, this);
                return neighbors;
            }
        });
        var Link = kendo.Class.extend({
            init: function (source, target, id, connection) {
                if (Utils.isUndefined(source)) {
                    throw 'The source of the new link is not set.';
                }
                if (Utils.isUndefined(target)) {
                    throw 'The target of the new link is not set.';
                }
                var sourceFound, targetFound;
                if (Utils.isString(source)) {
                    sourceFound = new Node(source);
                } else {
                    sourceFound = source;
                }
                if (Utils.isString(target)) {
                    targetFound = new Node(target);
                } else {
                    targetFound = target;
                }
                this.source = sourceFound;
                this.target = targetFound;
                this.source.links.push(this);
                this.target.links.push(this);
                this.source.outgoing.push(this);
                this.target.incoming.push(this);
                if (Utils.isDefined(id)) {
                    this.id = id;
                } else {
                    this.id = randomId();
                }
                if (Utils.isDefined(connection)) {
                    this.associatedConnection = connection;
                } else {
                    this.associatedConnection = null;
                }
                this.type = 'Link';
                this.shortForm = 'Link \'' + this.source.id + '->' + this.target.id + '\'';
            },
            getComplement: function (node) {
                if (this.source !== node && this.target !== node) {
                    throw 'The given node is not incident with this link.';
                }
                return this.source === node ? this.target : this.source;
            },
            getCommonNode: function (link) {
                if (this.source === link.source || this.source === link.target) {
                    return this.source;
                }
                if (this.target === link.source || this.target === link.target) {
                    return this.target;
                }
                return null;
            },
            isBridging: function (v1, v2) {
                return this.source === v1 && this.target === v2 || this.source === v2 && this.target === v1;
            },
            getNodes: function () {
                return [
                    this.source,
                    this.target
                ];
            },
            incidentWith: function (node) {
                return this.source === node || this.target === node;
            },
            adjacentTo: function (link) {
                return contains(this.source.links, link) || contains(this.target.links, link);
            },
            changeSource: function (node) {
                Utils.remove(this.source.links, this);
                Utils.remove(this.source.outgoing, this);
                node.links.push(this);
                node.outgoing.push(this);
                this.source = node;
            },
            changeTarget: function (node) {
                Utils.remove(this.target.links, this);
                Utils.remove(this.target.incoming, this);
                node.links.push(this);
                node.incoming.push(this);
                this.target = node;
            },
            changesNodes: function (v, w) {
                if (this.source === v) {
                    this.changeSource(w);
                } else if (this.target === v) {
                    this.changeTarget(w);
                }
            },
            reverse: function () {
                var oldSource = this.source;
                var oldTarget = this.target;
                this.source = oldTarget;
                Utils.remove(oldSource.outgoing, this);
                this.source.outgoing.push(this);
                this.target = oldSource;
                Utils.remove(oldTarget.incoming, this);
                this.target.incoming.push(this);
                return this;
            },
            directTo: function (target) {
                if (this.source !== target && this.target !== target) {
                    throw 'The given node is not incident with this link.';
                }
                if (this.target !== target) {
                    this.reverse();
                }
            },
            createReverseEdge: function () {
                var r = this.clone();
                r.reverse();
                r.reversed = true;
                return r;
            },
            clone: function () {
                var clone = new Link(this.source, this.target);
                return clone;
            }
        });
        var Graph = kendo.Class.extend({
            init: function (idOrDiagram) {
                this.links = [];
                this.nodes = [];
                this._nodeMap = new Dictionary();
                this.diagram = null;
                this._root = null;
                if (Utils.isDefined(idOrDiagram)) {
                    if (Utils.isString(idOrDiagram)) {
                        this.id = idOrDiagram;
                    } else {
                        this.diagram = idOrDiagram;
                        this.id = idOrDiagram.id;
                    }
                } else {
                    this.id = randomId();
                }
                this.bounds = new Rect();
                this._hasCachedRelationships = false;
                this.type = 'Graph';
            },
            cacheRelationships: function (forceRebuild) {
                if (Utils.isUndefined(forceRebuild)) {
                    forceRebuild = false;
                }
                if (this._hasCachedRelationships && !forceRebuild) {
                    return;
                }
                for (var i = 0, len = this.nodes.length; i < len; i++) {
                    var node = this.nodes[i];
                    node.children = this.getChildren(node);
                    node.parents = this.getParents(node);
                }
                this._hasCachedRelationships = true;
            },
            assignLevels: function (startNode, offset, visited) {
                if (!startNode) {
                    throw 'Start node not specified.';
                }
                if (Utils.isUndefined(offset)) {
                    offset = 0;
                }
                this.cacheRelationships();
                if (Utils.isUndefined(visited)) {
                    visited = new Dictionary();
                    Utils.forEach(this.nodes, function (n) {
                        visited.add(n, false);
                    });
                }
                visited.set(startNode, true);
                startNode.level = offset;
                var children = startNode.children;
                for (var i = 0, len = children.length; i < len; i++) {
                    var child = children[i];
                    if (!child || visited.get(child)) {
                        continue;
                    }
                    this.assignLevels(child, offset + 1, visited);
                }
            },
            root: function (value) {
                if (Utils.isUndefined(value)) {
                    if (!this._root) {
                        var found = Utils.first(this.nodes, function (n) {
                            return n.incoming.length === 0;
                        });
                        if (found) {
                            return found;
                        }
                        return Utils.first(this.nodes);
                    } else {
                        return this._root;
                    }
                } else {
                    this._root = value;
                }
            },
            getConnectedComponents: function () {
                this.componentIndex = 0;
                this.setItemIndices();
                var componentId = Utils.initArray(this.nodes.length, -1);
                for (var v = 0; v < this.nodes.length; v++) {
                    if (componentId[v] === -1) {
                        this._collectConnectedNodes(componentId, v);
                        this.componentIndex++;
                    }
                }
                var components = [], i;
                for (i = 0; i < this.componentIndex; ++i) {
                    components[i] = new Graph();
                }
                for (i = 0; i < componentId.length; ++i) {
                    var graph = components[componentId[i]];
                    graph.addNodeAndOutgoings(this.nodes[i]);
                }
                components.sort(function (a, b) {
                    return b.nodes.length - a.nodes.length;
                });
                return components;
            },
            _collectConnectedNodes: function (setIds, nodeIndex) {
                setIds[nodeIndex] = this.componentIndex;
                var node = this.nodes[nodeIndex];
                Utils.forEach(node.links, function (link) {
                    var next = link.getComplement(node);
                    var nextId = next.index;
                    if (setIds[nextId] === -1) {
                        this._collectConnectedNodes(setIds, nextId);
                    }
                }, this);
            },
            calcBounds: function () {
                if (this.isEmpty()) {
                    this.bounds = new Rect();
                    return this.bounds;
                }
                var b = null;
                for (var i = 0, len = this.nodes.length; i < len; i++) {
                    var node = this.nodes[i];
                    if (!b) {
                        b = node.bounds();
                    } else {
                        b = b.union(node.bounds());
                    }
                }
                this.bounds = b;
                return this.bounds;
            },
            getSpanningTree: function (root) {
                var tree = new Graph();
                var map = new Dictionary(), source, target;
                tree.root = root.clone();
                tree.root.level = 0;
                tree.root.id = root.id;
                map.add(root, tree.root);
                root.level = 0;
                var visited = [];
                var remaining = [];
                tree._addNode(tree.root);
                visited.push(root);
                remaining.push(root);
                var levelCount = 1;
                while (remaining.length > 0) {
                    var next = remaining.pop();
                    for (var ni = 0; ni < next.links.length; ni++) {
                        var link = next.links[ni];
                        var cn = link.getComplement(next);
                        if (contains(visited, cn)) {
                            continue;
                        }
                        cn.level = next.level + 1;
                        if (levelCount < cn.level + 1) {
                            levelCount = cn.level + 1;
                        }
                        if (!contains(remaining, cn)) {
                            remaining.push(cn);
                        }
                        if (!contains(visited, cn)) {
                            visited.push(cn);
                        }
                        if (map.containsKey(next)) {
                            source = map.get(next);
                        } else {
                            source = next.clone();
                            source.level = next.level;
                            source.id = next.id;
                            map.add(next, source);
                        }
                        if (map.containsKey(cn)) {
                            target = map.get(cn);
                        } else {
                            target = cn.clone();
                            target.level = cn.level;
                            target.id = cn.id;
                            map.add(cn, target);
                        }
                        var newLink = new Link(source, target);
                        tree.addLink(newLink);
                    }
                }
                var treeLevels = [];
                for (var i = 0; i < levelCount; i++) {
                    treeLevels.push([]);
                }
                Utils.forEach(tree.nodes, function (node) {
                    treeLevels[node.level].push(node);
                });
                tree.treeLevels = treeLevels;
                tree.cacheRelationships();
                return tree;
            },
            takeRandomNode: function (excludedNodes, incidenceLessThan) {
                if (Utils.isUndefined(excludedNodes)) {
                    excludedNodes = [];
                }
                if (Utils.isUndefined(incidenceLessThan)) {
                    incidenceLessThan = 4;
                }
                if (this.nodes.length === 0) {
                    return null;
                }
                if (this.nodes.length === 1) {
                    return contains(excludedNodes, this.nodes[0]) ? null : this.nodes[0];
                }
                var pool = $.grep(this.nodes, function (node) {
                    return !contains(excludedNodes, node) && node.degree() <= incidenceLessThan;
                });
                if (Utils.isEmpty(pool)) {
                    return null;
                }
                return pool[Utils.randomInteger(0, pool.length)];
            },
            isEmpty: function () {
                return Utils.isEmpty(this.nodes);
            },
            isHealthy: function () {
                return Utils.all(this.links, function (link) {
                    return contains(this.nodes, link.source) && contains(this.nodes, link.target);
                }, this);
            },
            getParents: function (n) {
                if (!this.hasNode(n)) {
                    throw 'The given node is not part of this graph.';
                }
                return n.getParents();
            },
            getChildren: function (n) {
                if (!this.hasNode(n)) {
                    throw 'The given node is not part of this graph.';
                }
                return n.getChildren();
            },
            addLink: function (sourceOrLink, target, owner) {
                if (Utils.isUndefined(sourceOrLink)) {
                    throw 'The source of the link is not defined.';
                }
                if (Utils.isUndefined(target)) {
                    if (Utils.isDefined(sourceOrLink.type) && sourceOrLink.type === 'Link') {
                        this.addExistingLink(sourceOrLink);
                        return;
                    } else {
                        throw 'The target of the link is not defined.';
                    }
                }
                var foundSource = this.getNode(sourceOrLink);
                if (Utils.isUndefined(foundSource)) {
                    foundSource = this.addNode(sourceOrLink);
                }
                var foundTarget = this.getNode(target);
                if (Utils.isUndefined(foundTarget)) {
                    foundTarget = this.addNode(target);
                }
                var newLink = new Link(foundSource, foundTarget);
                if (Utils.isDefined(owner)) {
                    newLink.owner = owner;
                }
                this.links.push(newLink);
                return newLink;
            },
            removeAllLinks: function () {
                while (this.links.length > 0) {
                    var link = this.links[0];
                    this.removeLink(link);
                }
            },
            addExistingLink: function (link) {
                if (this.hasLink(link)) {
                    return;
                }
                this.links.push(link);
                if (this.hasNode(link.source.id)) {
                    var s = this.getNode(link.source.id);
                    link.changeSource(s);
                } else {
                    this.addNode(link.source);
                }
                if (this.hasNode(link.target.id)) {
                    var t = this.getNode(link.target.id);
                    link.changeTarget(t);
                } else {
                    this.addNode(link.target);
                }
            },
            hasLink: function (linkOrId) {
                if (Utils.isString(linkOrId)) {
                    return Utils.any(this.links, function (link) {
                        return link.id === linkOrId;
                    });
                }
                if (linkOrId.type === 'Link') {
                    return contains(this.links, linkOrId);
                }
                throw 'The given object is neither an identifier nor a Link.';
            },
            getNode: function (nodeOrId) {
                var id = nodeOrId.id || nodeOrId;
                if (this._nodeMap.containsKey(id)) {
                    return this._nodeMap.get(id);
                }
            },
            hasNode: function (nodeOrId) {
                var id = nodeOrId.id || nodeOrId;
                return this._nodeMap.containsKey(id);
            },
            _addNode: function (node) {
                this.nodes.push(node);
                this._nodeMap.add(node.id, node);
            },
            _removeNode: function (node) {
                Utils.remove(this.nodes, node);
                this._nodeMap.remove(node.id);
            },
            removeNode: function (nodeOrId) {
                var n = nodeOrId;
                if (Utils.isString(nodeOrId)) {
                    n = this.getNode(nodeOrId);
                }
                if (Utils.isDefined(n)) {
                    var links = n.links;
                    n.links = [];
                    for (var i = 0, len = links.length; i < len; i++) {
                        var link = links[i];
                        this.removeLink(link);
                    }
                    this._removeNode(n);
                } else {
                    throw 'The identifier should be a Node or the Id (string) of a node.';
                }
            },
            areConnected: function (n1, n2) {
                return Utils.any(this.links, function (link) {
                    return link.source == n1 && link.target == n2 || link.source == n2 && link.target == n1;
                });
            },
            removeLink: function (link) {
                Utils.remove(this.links, link);
                Utils.remove(link.source.outgoing, link);
                Utils.remove(link.source.links, link);
                Utils.remove(link.target.incoming, link);
                Utils.remove(link.target.links, link);
            },
            addNode: function (nodeOrId, layoutRect, owner) {
                var newNode = null;
                if (!Utils.isDefined(nodeOrId)) {
                    throw 'No Node or identifier for a new Node is given.';
                }
                if (Utils.isString(nodeOrId)) {
                    if (this.hasNode(nodeOrId)) {
                        return this.getNode(nodeOrId);
                    }
                    newNode = new Node(nodeOrId);
                } else {
                    if (this.hasNode(nodeOrId)) {
                        return this.getNode(nodeOrId);
                    }
                    newNode = nodeOrId;
                }
                if (Utils.isDefined(layoutRect)) {
                    newNode.bounds(layoutRect);
                }
                if (Utils.isDefined(owner)) {
                    newNode.owner = owner;
                }
                this._addNode(newNode);
                return newNode;
            },
            addNodeAndOutgoings: function (node) {
                if (!this.hasNode(node)) {
                    this._addNode(node);
                }
                var newLinks = node.outgoing;
                node.outgoing = [];
                Utils.forEach(newLinks, function (link) {
                    this.addExistingLink(link);
                }, this);
            },
            setItemIndices: function () {
                var i;
                for (i = 0; i < this.nodes.length; ++i) {
                    this.nodes[i].index = i;
                }
                for (i = 0; i < this.links.length; ++i) {
                    this.links[i].index = i;
                }
            },
            clone: function (saveMapping) {
                var copy = new Graph();
                var save = Utils.isDefined(saveMapping) && saveMapping === true;
                if (save) {
                    copy.nodeMap = new Dictionary();
                    copy.linkMap = new Dictionary();
                }
                var map = new Dictionary();
                Utils.forEach(this.nodes, function (nOriginal) {
                    var nCopy = nOriginal.clone();
                    map.set(nOriginal, nCopy);
                    copy._addNode(nCopy);
                    if (save) {
                        copy.nodeMap.set(nCopy, nOriginal);
                    }
                });
                Utils.forEach(this.links, function (linkOriginal) {
                    if (map.containsKey(linkOriginal.source) && map.containsKey(linkOriginal.target)) {
                        var linkCopy = copy.addLink(map.get(linkOriginal.source), map.get(linkOriginal.target));
                        if (save) {
                            copy.linkMap.set(linkCopy, linkOriginal);
                        }
                    }
                });
                return copy;
            },
            linearize: function (addIds) {
                return Graph.Utils.linearize(this, addIds);
            },
            depthFirstTraversal: function (startNode, action) {
                if (Utils.isUndefined(startNode)) {
                    throw 'You need to supply a starting node.';
                }
                if (Utils.isUndefined(action)) {
                    throw 'You need to supply an action.';
                }
                if (!this.hasNode(startNode)) {
                    throw 'The given start-node is not part of this graph';
                }
                var foundNode = this.getNode(startNode);
                var visited = [];
                this._dftIterator(foundNode, action, visited);
            },
            _dftIterator: function (node, action, visited) {
                action(node);
                visited.push(node);
                var children = node.getChildren();
                for (var i = 0, len = children.length; i < len; i++) {
                    var child = children[i];
                    if (contains(visited, child)) {
                        continue;
                    }
                    this._dftIterator(child, action, visited);
                }
            },
            breadthFirstTraversal: function (startNode, action) {
                if (Utils.isUndefined(startNode)) {
                    throw 'You need to supply a starting node.';
                }
                if (Utils.isUndefined(action)) {
                    throw 'You need to supply an action.';
                }
                if (!this.hasNode(startNode)) {
                    throw 'The given start-node is not part of this graph';
                }
                var foundNode = this.getNode(startNode);
                var queue = new Queue();
                var visited = [];
                queue.enqueue(foundNode);
                while (queue.length > 0) {
                    var node = queue.dequeue();
                    action(node);
                    visited.push(node);
                    var children = node.getChildren();
                    for (var i = 0, len = children.length; i < len; i++) {
                        var child = children[i];
                        if (contains(visited, child) || contains(queue, child)) {
                            continue;
                        }
                        queue.enqueue(child);
                    }
                }
            },
            _stronglyConnectedComponents: function (excludeSingleItems, node, indices, lowLinks, connected, stack, index) {
                indices.add(node, index);
                lowLinks.add(node, index);
                index++;
                stack.push(node);
                var children = node.getChildren(), next;
                for (var i = 0, len = children.length; i < len; i++) {
                    next = children[i];
                    if (!indices.containsKey(next)) {
                        this._stronglyConnectedComponents(excludeSingleItems, next, indices, lowLinks, connected, stack, index);
                        lowLinks.add(node, Math.min(lowLinks.get(node), lowLinks.get(next)));
                    } else if (contains(stack, next)) {
                        lowLinks.add(node, Math.min(lowLinks.get(node), indices.get(next)));
                    }
                }
                if (lowLinks.get(node) === indices.get(node)) {
                    var component = [];
                    do {
                        next = stack.pop();
                        component.push(next);
                    } while (next !== node);
                    if (!excludeSingleItems || component.length > 1) {
                        connected.push(component);
                    }
                }
            },
            findCycles: function (excludeSingleItems) {
                if (Utils.isUndefined(excludeSingleItems)) {
                    excludeSingleItems = true;
                }
                var indices = new Dictionary();
                var lowLinks = new Dictionary();
                var connected = [];
                var stack = [];
                for (var i = 0, len = this.nodes.length; i < len; i++) {
                    var node = this.nodes[i];
                    if (indices.containsKey(node)) {
                        continue;
                    }
                    this._stronglyConnectedComponents(excludeSingleItems, node, indices, lowLinks, connected, stack, 0);
                }
                return connected;
            },
            isAcyclic: function () {
                return Utils.isEmpty(this.findCycles());
            },
            isSubGraph: function (other) {
                var otherArray = other.linearize();
                var thisArray = this.linearize();
                return Utils.all(otherArray, function (s) {
                    return contains(thisArray, s);
                });
            },
            makeAcyclic: function () {
                if (this.isEmpty() || this.nodes.length <= 1 || this.links.length <= 1) {
                    return [];
                }
                if (this.nodes.length == 2) {
                    var result = [];
                    if (this.links.length > 1) {
                        var oneLink = this.links[0];
                        var oneNode = oneLink.source;
                        for (var i = 0, len = this.links.length; i < len; i++) {
                            var link = this.links[i];
                            if (link.source == oneNode) {
                                continue;
                            }
                            var rev = link.reverse();
                            result.push(rev);
                        }
                    }
                    return result;
                }
                var copy = this.clone(true);
                var N = this.nodes.length;
                var intensityCatalog = new Dictionary();
                var flowIntensity = function (node) {
                    if (node.outgoing.length === 0) {
                        return 2 - N;
                    } else if (node.incoming.length === 0) {
                        return N - 2;
                    } else {
                        return node.outgoing.length - node.incoming.length;
                    }
                };
                var catalogEqualIntensity = function (node, intensityCatalog) {
                    var intensity = flowIntensity(node, N);
                    if (!intensityCatalog.containsKey(intensity)) {
                        intensityCatalog.set(intensity, []);
                    }
                    intensityCatalog.get(intensity).push(node);
                };
                Utils.forEach(copy.nodes, function (v) {
                    catalogEqualIntensity(v, intensityCatalog);
                });
                var sourceStack = [];
                var targetStack = [];
                while (copy.nodes.length > 0) {
                    var source, target, intensity;
                    if (intensityCatalog.containsKey(2 - N)) {
                        var targets = intensityCatalog.get(2 - N);
                        while (targets.length > 0) {
                            target = targets.pop();
                            for (var li = 0; li < target.links.length; li++) {
                                var targetLink = target.links[li];
                                source = targetLink.getComplement(target);
                                intensity = flowIntensity(source, N);
                                Utils.remove(intensityCatalog.get(intensity), source);
                                source.removeLink(targetLink);
                                catalogEqualIntensity(source, intensityCatalog);
                            }
                            copy._removeNode(target);
                            targetStack.unshift(target);
                        }
                    }
                    if (intensityCatalog.containsKey(N - 2)) {
                        var sources = intensityCatalog.get(N - 2);
                        while (sources.length > 0) {
                            source = sources.pop();
                            for (var si = 0; si < source.links.length; si++) {
                                var sourceLink = source.links[si];
                                target = sourceLink.getComplement(source);
                                intensity = flowIntensity(target, N);
                                Utils.remove(intensityCatalog.get(intensity), target);
                                target.removeLink(sourceLink);
                                catalogEqualIntensity(target, intensityCatalog);
                            }
                            sourceStack.push(source);
                            copy._removeNode(source);
                        }
                    }
                    if (copy.nodes.length > 0) {
                        for (var k = N - 3; k > 2 - N; k--) {
                            if (intensityCatalog.containsKey(k) && intensityCatalog.get(k).length > 0) {
                                var maxdiff = intensityCatalog.get(k);
                                var v = maxdiff.pop();
                                for (var ri = 0; ri < v.links.length; ri++) {
                                    var ril = v.links[ri];
                                    var u = ril.getComplement(v);
                                    intensity = flowIntensity(u, N);
                                    Utils.remove(intensityCatalog.get(intensity), u);
                                    u.removeLink(ril);
                                    catalogEqualIntensity(u, intensityCatalog);
                                }
                                sourceStack.push(v);
                                copy._removeNode(v);
                                break;
                            }
                        }
                    }
                }
                sourceStack = sourceStack.concat(targetStack);
                var vertexOrder = new Dictionary();
                for (var kk = 0; kk < this.nodes.length; kk++) {
                    vertexOrder.set(copy.nodeMap.get(sourceStack[kk]), kk);
                }
                var reversedEdges = [];
                Utils.forEach(this.links, function (link) {
                    if (vertexOrder.get(link.source) > vertexOrder.get(link.target)) {
                        link.reverse();
                        reversedEdges.push(link);
                    }
                });
                return reversedEdges;
            }
        });
        Graph.Predefined = {
            EightGraph: function () {
                return Graph.Utils.parse([
                    '1->2',
                    '2->3',
                    '3->4',
                    '4->1',
                    '3->5',
                    '5->6',
                    '6->7',
                    '7->3'
                ]);
            },
            Mindmap: function () {
                return Graph.Utils.parse([
                    '0->1',
                    '0->2',
                    '0->3',
                    '0->4',
                    '0->5',
                    '1->6',
                    '1->7',
                    '7->8',
                    '2->9',
                    '9->10',
                    '9->11',
                    '3->12',
                    '12->13',
                    '13->14',
                    '4->15',
                    '4->16',
                    '15->17',
                    '15->18',
                    '18->19',
                    '18->20',
                    '14->21',
                    '14->22',
                    '5->23',
                    '23->24',
                    '23->25',
                    '6->26'
                ]);
            },
            ThreeGraph: function () {
                return Graph.Utils.parse([
                    '1->2',
                    '2->3',
                    '3->1'
                ]);
            },
            BinaryTree: function (levels) {
                if (Utils.isUndefined(levels)) {
                    levels = 5;
                }
                return Graph.Utils.createBalancedTree(levels, 2);
            },
            Linear: function (length) {
                if (Utils.isUndefined(length)) {
                    length = 10;
                }
                return Graph.Utils.createBalancedTree(length, 1);
            },
            Tree: function (levels, siblingsCount) {
                return Graph.Utils.createBalancedTree(levels, siblingsCount);
            },
            Forest: function (levels, siblingsCount, trees) {
                return Graph.Utils.createBalancedForest(levels, siblingsCount, trees);
            },
            Workflow: function () {
                return Graph.Utils.parse([
                    '0->1',
                    '1->2',
                    '2->3',
                    '1->4',
                    '4->3',
                    '3->5',
                    '5->6',
                    '6->3',
                    '6->7',
                    '5->4'
                ]);
            },
            Grid: function (n, m) {
                var g = new diagram.Graph();
                if (n <= 0 && m <= 0) {
                    return g;
                }
                for (var i = 0; i < n + 1; i++) {
                    var previous = null;
                    for (var j = 0; j < m + 1; j++) {
                        var node = new Node(i.toString() + '.' + j.toString());
                        g.addNode(node);
                        if (previous) {
                            g.addLink(previous, node);
                        }
                        if (i > 0) {
                            var left = g.getNode((i - 1).toString() + '.' + j.toString());
                            g.addLink(left, node);
                        }
                        previous = node;
                    }
                }
                return g;
            }
        };
        Graph.Utils = {
            parse: function (graphString) {
                var previousLink, graph = new diagram.Graph(), parts = graphString.slice();
                for (var i = 0, len = parts.length; i < len; i++) {
                    var part = parts[i];
                    if (Utils.isString(part)) {
                        if (part.indexOf('->') < 0) {
                            throw 'The link should be specified as \'a->b\'.';
                        }
                        var p = part.split('->');
                        if (p.length != 2) {
                            throw 'The link should be specified as \'a->b\'.';
                        }
                        previousLink = new Link(p[0], p[1]);
                        graph.addLink(previousLink);
                    }
                    if (Utils.isObject(part)) {
                        if (!previousLink) {
                            throw 'Specification found before Link definition.';
                        }
                        kendo.deepExtend(previousLink, part);
                    }
                }
                return graph;
            },
            linearize: function (graph, addIds) {
                if (Utils.isUndefined(graph)) {
                    throw 'Expected an instance of a Graph object in slot one.';
                }
                if (Utils.isUndefined(addIds)) {
                    addIds = false;
                }
                var lin = [];
                for (var i = 0, len = graph.links.length; i < len; i++) {
                    var link = graph.links[i];
                    lin.push(link.source.id + '->' + link.target.id);
                    if (addIds) {
                        lin.push({ id: link.id });
                    }
                }
                return lin;
            },
            _addShape: function (kendoDiagram, p, id, shapeDefaults) {
                if (Utils.isUndefined(p)) {
                    p = new diagram.Point(0, 0);
                }
                if (Utils.isUndefined(id)) {
                    id = randomId();
                }
                shapeDefaults = kendo.deepExtend({
                    width: 20,
                    height: 20,
                    id: id,
                    radius: 10,
                    fill: '#778899',
                    data: 'circle',
                    undoable: false,
                    x: p.x,
                    y: p.y
                }, shapeDefaults);
                return kendoDiagram.addShape(shapeDefaults);
            },
            _addConnection: function (diagram, from, to, options) {
                return diagram.connect(from, to, options);
            },
            createDiagramFromGraph: function (diagram, graph, doLayout, randomSize) {
                if (Utils.isUndefined(diagram)) {
                    throw 'The diagram surface is undefined.';
                }
                if (Utils.isUndefined(graph)) {
                    throw 'No graph specification defined.';
                }
                if (Utils.isUndefined(doLayout)) {
                    doLayout = true;
                }
                if (Utils.isUndefined(randomSize)) {
                    randomSize = false;
                }
                var width = diagram.element.clientWidth || 200;
                var height = diagram.element.clientHeight || 200;
                var map = [], node, shape;
                for (var i = 0, len = graph.nodes.length; i < len; i++) {
                    node = graph.nodes[i];
                    var p = node.position;
                    if (Utils.isUndefined(p)) {
                        if (Utils.isDefined(node.x) && Utils.isDefined(node.y)) {
                            p = new Point(node.x, node.y);
                        } else {
                            p = new Point(Utils.randomInteger(10, width - 20), Utils.randomInteger(10, height - 20));
                        }
                    }
                    var opt = {};
                    if (node.id === '0') {
                    } else if (randomSize) {
                        kendo.deepExtend(opt, {
                            width: Math.random() * 150 + 20,
                            height: Math.random() * 80 + 50,
                            data: 'rectangle',
                            fill: { color: '#778899' }
                        });
                    }
                    shape = this._addShape(diagram, p, node.id, opt);
                    var bounds = shape.bounds();
                    if (Utils.isDefined(bounds)) {
                        node.x = bounds.x;
                        node.y = bounds.y;
                        node.width = bounds.width;
                        node.height = bounds.height;
                    }
                    map[node.id] = shape;
                }
                for (var gli = 0; gli < graph.links.length; gli++) {
                    var link = graph.links[gli];
                    var sourceShape = map[link.source.id];
                    if (Utils.isUndefined(sourceShape)) {
                        continue;
                    }
                    var targetShape = map[link.target.id];
                    if (Utils.isUndefined(targetShape)) {
                        continue;
                    }
                    this._addConnection(diagram, sourceShape, targetShape, { id: link.id });
                }
                if (doLayout) {
                    var l = new diagram.SpringLayout(diagram);
                    l.layoutGraph(graph, { limitToView: false });
                    for (var shi = 0; shi < graph.nodes.length; shi++) {
                        node = graph.nodes[shi];
                        shape = map[node.id];
                        shape.bounds(new Rect(node.x, node.y, node.width, node.height));
                    }
                }
            },
            createBalancedTree: function (levels, siblingsCount) {
                if (Utils.isUndefined(levels)) {
                    levels = 3;
                }
                if (Utils.isUndefined(siblingsCount)) {
                    siblingsCount = 3;
                }
                var g = new diagram.Graph(), counter = -1, lastAdded = [], news;
                if (levels <= 0 || siblingsCount <= 0) {
                    return g;
                }
                var root = new Node((++counter).toString());
                g.addNode(root);
                g.root = root;
                lastAdded.push(root);
                for (var i = 0; i < levels; i++) {
                    news = [];
                    for (var j = 0; j < lastAdded.length; j++) {
                        var parent = lastAdded[j];
                        for (var k = 0; k < siblingsCount; k++) {
                            var item = new Node((++counter).toString());
                            g.addLink(parent, item);
                            news.push(item);
                        }
                    }
                    lastAdded = news;
                }
                return g;
            },
            createBalancedForest: function (levels, siblingsCount, treeCount) {
                if (Utils.isUndefined(levels)) {
                    levels = 3;
                }
                if (Utils.isUndefined(siblingsCount)) {
                    siblingsCount = 3;
                }
                if (Utils.isUndefined(treeCount)) {
                    treeCount = 5;
                }
                var g = new diagram.Graph(), counter = -1, lastAdded = [], news;
                if (levels <= 0 || siblingsCount <= 0 || treeCount <= 0) {
                    return g;
                }
                for (var t = 0; t < treeCount; t++) {
                    var root = new Node((++counter).toString());
                    g.addNode(root);
                    lastAdded = [root];
                    for (var i = 0; i < levels; i++) {
                        news = [];
                        for (var j = 0; j < lastAdded.length; j++) {
                            var parent = lastAdded[j];
                            for (var k = 0; k < siblingsCount; k++) {
                                var item = new Node((++counter).toString());
                                g.addLink(parent, item);
                                news.push(item);
                            }
                        }
                        lastAdded = news;
                    }
                }
                return g;
            },
            createRandomConnectedGraph: function (nodeCount, maxIncidence, isTree) {
                if (Utils.isUndefined(nodeCount)) {
                    nodeCount = 40;
                }
                if (Utils.isUndefined(maxIncidence)) {
                    maxIncidence = 4;
                }
                if (Utils.isUndefined(isTree)) {
                    isTree = false;
                }
                var g = new diagram.Graph(), counter = -1;
                if (nodeCount <= 0) {
                    return g;
                }
                var root = new Node((++counter).toString());
                g.addNode(root);
                if (nodeCount === 1) {
                    return g;
                }
                if (nodeCount > 1) {
                    for (var i = 1; i < nodeCount; i++) {
                        var poolNode = g.takeRandomNode([], maxIncidence);
                        if (!poolNode) {
                            break;
                        }
                        var newNode = g.addNode(i.toString());
                        g.addLink(poolNode, newNode);
                    }
                    if (!isTree && nodeCount > 1) {
                        var randomAdditions = Utils.randomInteger(1, nodeCount);
                        for (var ri = 0; ri < randomAdditions; ri++) {
                            var n1 = g.takeRandomNode([], maxIncidence);
                            var n2 = g.takeRandomNode([], maxIncidence);
                            if (n1 && n2 && !g.areConnected(n1, n2)) {
                                g.addLink(n1, n2);
                            }
                        }
                    }
                    return g;
                }
            },
            randomDiagram: function (diagram, shapeCount, maxIncidence, isTree, randomSize) {
                var g = kendo.dataviz.diagram.Graph.Utils.createRandomConnectedGraph(shapeCount, maxIncidence, isTree);
                Graph.Utils.createDiagramFromGraph(diagram, g, false, randomSize);
            }
        };
        kendo.deepExtend(diagram, {
            init: function (element) {
                kendo.init(element, diagram.ui);
            },
            Point: Point,
            Intersect: Intersect,
            Geometry: Geometry,
            Rect: Rect,
            Size: Size,
            RectAlign: RectAlign,
            Matrix: Matrix,
            MatrixVector: MatrixVector,
            normalVariable: normalVariable,
            randomId: randomId,
            Dictionary: Dictionary,
            HashTable: HashTable,
            Queue: Queue,
            Set: Set,
            Node: Node,
            Link: Link,
            Graph: Graph,
            PathDefiner: PathDefiner
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/diagram/svg', [
        'kendo.drawing',
        'dataviz/diagram/math'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, diagram = kendo.dataviz.diagram, Class = kendo.Class, deepExtend = kendo.deepExtend, Point = diagram.Point, Rect = diagram.Rect, Matrix = diagram.Matrix, Utils = diagram.Utils, isNumber = Utils.isNumber, isString = Utils.isString, MatrixVector = diagram.MatrixVector, g = kendo.geometry, d = kendo.drawing, defined = d.util.defined, inArray = $.inArray;
        var TRANSPARENT = 'transparent', Markers = {
                none: 'none',
                arrowStart: 'ArrowStart',
                filledCircle: 'FilledCircle',
                arrowEnd: 'ArrowEnd'
            }, FULL_CIRCLE_ANGLE = 360, START = 'start', END = 'end', WIDTH = 'width', HEIGHT = 'height', X = 'x', Y = 'y';
        diagram.Markers = Markers;
        function diffNumericOptions(options, fields) {
            var elementOptions = this.options;
            var hasChanges = false;
            var value, field;
            for (var i = 0; i < fields.length; i++) {
                field = fields[i];
                value = options[field];
                if (isNumber(value) && elementOptions[field] !== value) {
                    elementOptions[field] = value;
                    hasChanges = true;
                }
            }
            return hasChanges;
        }
        var Scale = Class.extend({
            init: function (x, y) {
                this.x = x;
                this.y = y;
            },
            toMatrix: function () {
                return Matrix.scaling(this.x, this.y);
            },
            toString: function () {
                return kendo.format('scale({0},{1})', this.x, this.y);
            },
            invert: function () {
                return new Scale(1 / this.x, 1 / this.y);
            }
        });
        var Translation = Class.extend({
            init: function (x, y) {
                this.x = x;
                this.y = y;
            },
            toMatrixVector: function () {
                return new MatrixVector(0, 0, 0, 0, this.x, this.y);
            },
            toMatrix: function () {
                return Matrix.translation(this.x, this.y);
            },
            toString: function () {
                return kendo.format('translate({0},{1})', this.x, this.y);
            },
            plus: function (delta) {
                this.x += delta.x;
                this.y += delta.y;
            },
            times: function (factor) {
                this.x *= factor;
                this.y *= factor;
            },
            length: function () {
                return Math.sqrt(this.x * this.x + this.y * this.y);
            },
            normalize: function () {
                if (this.Length === 0) {
                    return;
                }
                this.times(1 / this.length());
            },
            invert: function () {
                return new Translation(-this.x, -this.y);
            }
        });
        var Rotation = Class.extend({
            init: function (angle, x, y) {
                this.x = x || 0;
                this.y = y || 0;
                this.angle = angle;
            },
            toString: function () {
                if (this.x && this.y) {
                    return kendo.format('rotate({0},{1},{2})', this.angle, this.x, this.y);
                } else {
                    return kendo.format('rotate({0})', this.angle);
                }
            },
            toMatrix: function () {
                return Matrix.rotation(this.angle, this.x, this.y);
            },
            center: function () {
                return new Point(this.x, this.y);
            },
            invert: function () {
                return new Rotation(FULL_CIRCLE_ANGLE - this.angle, this.x, this.y);
            }
        });
        Rotation.ZERO = new Rotation(0);
        Rotation.create = function (rotation) {
            return new Rotation(rotation.angle, rotation.x, rotation.y);
        };
        Rotation.parse = function (str) {
            var values = str.slice(1, str.length - 1).split(','), angle = values[0], x = values[1], y = values[2];
            var rotation = new Rotation(angle, x, y);
            return rotation;
        };
        var CompositeTransform = Class.extend({
            init: function (x, y, scaleX, scaleY, angle, center) {
                this.translate = new Translation(x, y);
                if (scaleX !== undefined && scaleY !== undefined) {
                    this.scale = new Scale(scaleX, scaleY);
                }
                if (angle !== undefined) {
                    this.rotate = center ? new Rotation(angle, center.x, center.y) : new Rotation(angle);
                }
            },
            toString: function () {
                var toString = function (transform) {
                    return transform ? transform.toString() : '';
                };
                return toString(this.translate) + toString(this.rotate) + toString(this.scale);
            },
            render: function (visual) {
                visual._transform = this;
                visual._renderTransform();
            },
            toMatrix: function () {
                var m = Matrix.unit();
                if (this.translate) {
                    m = m.times(this.translate.toMatrix());
                }
                if (this.rotate) {
                    m = m.times(this.rotate.toMatrix());
                }
                if (this.scale) {
                    m = m.times(this.scale.toMatrix());
                }
                return m;
            },
            invert: function () {
                var rotate = this.rotate ? this.rotate.invert() : undefined, rotateMatrix = rotate ? rotate.toMatrix() : Matrix.unit(), scale = this.scale ? this.scale.invert() : undefined, scaleMatrix = scale ? scale.toMatrix() : Matrix.unit();
                var translatePoint = new Point(-this.translate.x, -this.translate.y);
                translatePoint = rotateMatrix.times(scaleMatrix).apply(translatePoint);
                var translate = new Translation(translatePoint.x, translatePoint.y);
                var transform = new CompositeTransform();
                transform.translate = translate;
                transform.rotate = rotate;
                transform.scale = scale;
                return transform;
            }
        });
        var AutoSizeableMixin = {
            _setScale: function () {
                var options = this.options;
                var originWidth = this._originWidth;
                var originHeight = this._originHeight;
                var scaleX = options.width / originWidth;
                var scaleY = options.height / originHeight;
                if (!isNumber(scaleX)) {
                    scaleX = 1;
                }
                if (!isNumber(scaleY)) {
                    scaleY = 1;
                }
                this._transform.scale = new Scale(scaleX, scaleY);
            },
            _setTranslate: function () {
                var options = this.options;
                var x = options.x || 0;
                var y = options.y || 0;
                this._transform.translate = new Translation(x, y);
            },
            _initSize: function () {
                var options = this.options;
                var transform = false;
                if (options.autoSize !== false && (defined(options.width) || defined(options.height))) {
                    this._measure(true);
                    this._setScale();
                    transform = true;
                }
                if (defined(options.x) || defined(options.y)) {
                    this._setTranslate();
                    transform = true;
                }
                if (transform) {
                    this._renderTransform();
                }
            },
            _updateSize: function (options) {
                var update = false;
                if (this.options.autoSize !== false && this._diffNumericOptions(options, [
                        WIDTH,
                        HEIGHT
                    ])) {
                    update = true;
                    this._measure(true);
                    this._setScale();
                }
                if (this._diffNumericOptions(options, [
                        X,
                        Y
                    ])) {
                    update = true;
                    this._setTranslate();
                }
                if (update) {
                    this._renderTransform();
                }
                return update;
            }
        };
        var Element = Class.extend({
            init: function (options) {
                var element = this;
                element.options = deepExtend({}, element.options, options);
                element.id = element.options.id;
                element._originSize = Rect.empty();
                element._transform = new CompositeTransform();
            },
            visible: function (value) {
                return this.drawingContainer().visible(value);
            },
            redraw: function (options) {
                if (options && options.id) {
                    this.id = options.id;
                }
            },
            position: function (x, y) {
                var options = this.options;
                if (!defined(x)) {
                    return new Point(options.x, options.y);
                }
                if (defined(y)) {
                    options.x = x;
                    options.y = y;
                } else if (x instanceof Point) {
                    options.x = x.x;
                    options.y = x.y;
                }
                this._transform.translate = new Translation(options.x, options.y);
                this._renderTransform();
            },
            rotate: function (angle, center) {
                if (defined(angle)) {
                    this._transform.rotate = new Rotation(angle, center.x, center.y);
                    this._renderTransform();
                }
                return this._transform.rotate || Rotation.ZERO;
            },
            drawingContainer: function () {
                return this.drawingElement;
            },
            _renderTransform: function () {
                var matrix = this._transform.toMatrix();
                this.drawingContainer().transform(new g.Matrix(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f));
            },
            _hover: function () {
            },
            _diffNumericOptions: diffNumericOptions,
            _measure: function (force) {
                var rect;
                if (!this._measured || force) {
                    var box = this._boundingBox() || new g.Rect();
                    var startPoint = box.topLeft();
                    rect = new Rect(startPoint.x, startPoint.y, box.width(), box.height());
                    this._originSize = rect;
                    this._originWidth = rect.width;
                    this._originHeight = rect.height;
                    this._measured = true;
                } else {
                    rect = this._originSize;
                }
                return rect;
            },
            _boundingBox: function () {
                return this.drawingElement.rawBBox();
            }
        });
        var VisualBase = Element.extend({
            init: function (options) {
                Element.fn.init.call(this, options);
                options = this.options;
                options.fill = normalizeDrawingOptions(options.fill);
                options.stroke = normalizeDrawingOptions(options.stroke);
            },
            options: {
                stroke: {
                    color: 'gray',
                    width: 1
                },
                fill: { color: TRANSPARENT }
            },
            fill: function (color, opacity) {
                this._fill({
                    color: getColor(color),
                    opacity: opacity
                });
            },
            stroke: function (color, width, opacity) {
                this._stroke({
                    color: getColor(color),
                    width: width,
                    opacity: opacity
                });
            },
            redraw: function (options) {
                if (options) {
                    var stroke = options.stroke;
                    var fill = options.fill;
                    if (stroke) {
                        this._stroke(normalizeDrawingOptions(stroke));
                    }
                    if (fill) {
                        this._fill(normalizeDrawingOptions(fill));
                    }
                    Element.fn.redraw.call(this, options);
                }
            },
            _hover: function (show) {
                var drawingElement = this.drawingElement;
                var options = this.options;
                var hover = options.hover;
                if (hover && hover.fill) {
                    var fill = show ? normalizeDrawingOptions(hover.fill) : options.fill;
                    drawingElement.fill(fill.color, fill.opacity);
                }
            },
            _stroke: function (strokeOptions) {
                var options = this.options;
                deepExtend(options, { stroke: strokeOptions });
                strokeOptions = options.stroke;
                var stroke = null;
                if (strokeOptions.width > 0) {
                    stroke = {
                        color: strokeOptions.color,
                        width: strokeOptions.width,
                        opacity: strokeOptions.opacity,
                        dashType: strokeOptions.dashType
                    };
                }
                this.drawingElement.options.set('stroke', stroke);
            },
            _fill: function (fillOptions) {
                var options = this.options;
                deepExtend(options, { fill: fillOptions || {} });
                var fill = options.fill;
                if (fill.gradient) {
                    var gradient = fill.gradient;
                    var GradientClass = gradient.type === 'radial' ? d.RadialGradient : d.LinearGradient;
                    this.drawingElement.fill(new GradientClass(gradient));
                } else {
                    this.drawingElement.fill(fill.color, fill.opacity);
                }
            }
        });
        var TextBlock = VisualBase.extend({
            init: function (options) {
                options = this._textColor(options);
                VisualBase.fn.init.call(this, options);
                this._font();
                this._initText();
                this._initSize();
            },
            options: {
                fontSize: 15,
                fontFamily: 'sans-serif',
                stroke: { width: 0 },
                fill: { color: 'black' },
                autoSize: true
            },
            _initText: function () {
                var options = this.options;
                this.drawingElement = new d.Text(defined(options.text) ? options.text : '', new g.Point(), { font: options.font });
                this._fill();
                this._stroke();
            },
            _textColor: function (options) {
                if (options && options.color) {
                    options = deepExtend({}, options, { fill: { color: options.color } });
                }
                return options;
            },
            _font: function () {
                var options = this.options;
                if (options.fontFamily && defined(options.fontSize)) {
                    var fontOptions = [];
                    if (options.fontStyle) {
                        fontOptions.push(options.fontStyle);
                    }
                    if (options.fontWeight) {
                        fontOptions.push(options.fontWeight);
                    }
                    fontOptions.push(options.fontSize + (isNumber(options.fontSize) ? 'px' : ''));
                    fontOptions.push(options.fontFamily);
                    options.font = fontOptions.join(' ');
                } else {
                    delete options.font;
                }
            },
            content: function (text) {
                return this.drawingElement.content(text);
            },
            redraw: function (options) {
                if (options) {
                    var sizeChanged = false;
                    var textOptions = this.options;
                    options = this._textColor(options);
                    VisualBase.fn.redraw.call(this, options);
                    if (options.fontFamily || defined(options.fontSize) || options.fontStyle || options.fontWeight) {
                        deepExtend(textOptions, {
                            fontFamily: options.fontFamily,
                            fontSize: options.fontSize,
                            fontStyle: options.fontStyle,
                            fontWeight: options.fontWeight
                        });
                        this._font();
                        this.drawingElement.options.set('font', textOptions.font);
                        sizeChanged = true;
                    }
                    if (options.text) {
                        this.content(options.text);
                        sizeChanged = true;
                    }
                    if (!this._updateSize(options) && sizeChanged) {
                        this._initSize();
                    }
                }
            }
        });
        deepExtend(TextBlock.fn, AutoSizeableMixin);
        var Rectangle = VisualBase.extend({
            init: function (options) {
                VisualBase.fn.init.call(this, options);
                this._initPath();
                this._setPosition();
            },
            _setPosition: function () {
                var options = this.options;
                var x = options.x;
                var y = options.y;
                if (defined(x) || defined(y)) {
                    this.position(x || 0, y || 0);
                }
            },
            redraw: function (options) {
                if (options) {
                    VisualBase.fn.redraw.call(this, options);
                    if (this._diffNumericOptions(options, [
                            WIDTH,
                            HEIGHT
                        ])) {
                        this._drawPath();
                    }
                    if (this._diffNumericOptions(options, [
                            X,
                            Y
                        ])) {
                        this._setPosition();
                    }
                }
            },
            _initPath: function () {
                var options = this.options;
                this.drawingElement = new d.Path({
                    stroke: options.stroke,
                    closed: true
                });
                this._fill();
                this._drawPath();
            },
            _drawPath: function () {
                var drawingElement = this.drawingElement;
                var sizeOptions = sizeOptionsOrDefault(this.options);
                var width = sizeOptions.width;
                var height = sizeOptions.height;
                drawingElement.segments.elements([
                    createSegment(0, 0),
                    createSegment(width, 0),
                    createSegment(width, height),
                    createSegment(0, height)
                ]);
            }
        });
        var MarkerBase = VisualBase.extend({
            init: function (options) {
                VisualBase.fn.init.call(this, options);
                var anchor = this.options.anchor;
                this.anchor = new g.Point(anchor.x, anchor.y);
                this.createElement();
            },
            options: {
                stroke: {
                    color: TRANSPARENT,
                    width: 0
                },
                fill: { color: 'black' }
            },
            _transformToPath: function (point, path) {
                var transform = path.transform();
                if (point && transform) {
                    point = point.transformCopy(transform);
                }
                return point;
            },
            redraw: function (options) {
                if (options) {
                    if (options.position) {
                        this.options.position = options.position;
                    }
                    VisualBase.fn.redraw.call(this, options);
                }
            }
        });
        var CircleMarker = MarkerBase.extend({
            options: {
                radius: 4,
                anchor: {
                    x: 0,
                    y: 0
                }
            },
            createElement: function () {
                var options = this.options;
                this.drawingElement = new d.Circle(new g.Circle(this.anchor, options.radius), {
                    fill: options.fill,
                    stroke: options.stroke
                });
            },
            positionMarker: function (path) {
                var options = this.options;
                var position = options.position;
                var segments = path.segments;
                var targetSegment;
                var point;
                if (position == START) {
                    targetSegment = segments[0];
                } else {
                    targetSegment = segments[segments.length - 1];
                }
                if (targetSegment) {
                    point = this._transformToPath(targetSegment.anchor(), path);
                    this.drawingElement.transform(g.transform().translate(point.x, point.y));
                }
            }
        });
        var ArrowMarker = MarkerBase.extend({
            options: {
                path: 'M 0 0 L 10 5 L 0 10 L 3 5 z',
                anchor: {
                    x: 10,
                    y: 5
                }
            },
            createElement: function () {
                var options = this.options;
                this.drawingElement = d.Path.parse(options.path, {
                    fill: options.fill,
                    stroke: options.stroke
                });
            },
            positionMarker: function (path) {
                var points = this._linePoints(path);
                var start = points.start;
                var end = points.end;
                var transform = g.transform();
                if (start) {
                    transform.rotate(lineAngle(start, end), end);
                }
                if (end) {
                    var anchor = this.anchor;
                    var translate = end.clone().translate(-anchor.x, -anchor.y);
                    transform.translate(translate.x, translate.y);
                }
                this.drawingElement.transform(transform);
            },
            _linePoints: function (path) {
                var options = this.options;
                var segments = path.segments;
                var startPoint, endPoint, targetSegment;
                if (options.position == START) {
                    targetSegment = segments[0];
                    if (targetSegment) {
                        endPoint = targetSegment.anchor();
                        startPoint = targetSegment.controlOut();
                        var nextSegment = segments[1];
                        if (!startPoint && nextSegment) {
                            startPoint = nextSegment.anchor();
                        }
                    }
                } else {
                    targetSegment = segments[segments.length - 1];
                    if (targetSegment) {
                        endPoint = targetSegment.anchor();
                        startPoint = targetSegment.controlIn();
                        var prevSegment = segments[segments.length - 2];
                        if (!startPoint && prevSegment) {
                            startPoint = prevSegment.anchor();
                        }
                    }
                }
                if (endPoint) {
                    return {
                        start: this._transformToPath(startPoint, path),
                        end: this._transformToPath(endPoint, path)
                    };
                }
            }
        });
        var MarkerPathMixin = {
            _getPath: function (position) {
                var path = this.drawingElement;
                if (path instanceof d.MultiPath) {
                    if (position == START) {
                        path = path.paths[0];
                    } else {
                        path = path.paths[path.paths.length - 1];
                    }
                }
                if (path && path.segments.length) {
                    return path;
                }
            },
            _normalizeMarkerOptions: function (options) {
                var startCap = options.startCap;
                var endCap = options.endCap;
                if (isString(startCap)) {
                    options.startCap = { type: startCap };
                }
                if (isString(endCap)) {
                    options.endCap = { type: endCap };
                }
            },
            _removeMarker: function (position) {
                var marker = this._markers[position];
                if (marker) {
                    this.drawingContainer().remove(marker.drawingElement);
                    delete this._markers[position];
                }
            },
            _createMarkers: function () {
                var options = this.options;
                this._normalizeMarkerOptions(options);
                this._markers = {};
                this._markers[START] = this._createMarker(options.startCap, START);
                this._markers[END] = this._createMarker(options.endCap, END);
            },
            _createMarker: function (options, position) {
                var type = (options || {}).type;
                var path = this._getPath(position);
                var markerType, marker;
                if (!path) {
                    this._removeMarker(position);
                    return;
                }
                if (type == Markers.filledCircle) {
                    markerType = CircleMarker;
                } else if (type == Markers.arrowStart || type == Markers.arrowEnd) {
                    markerType = ArrowMarker;
                } else {
                    this._removeMarker(position);
                }
                if (markerType) {
                    marker = new markerType(deepExtend({}, options, { position: position }));
                    marker.positionMarker(path);
                    this.drawingContainer().append(marker.drawingElement);
                    return marker;
                }
            },
            _positionMarker: function (position) {
                var marker = this._markers[position];
                if (marker) {
                    var path = this._getPath(position);
                    if (path) {
                        marker.positionMarker(path);
                    } else {
                        this._removeMarker(position);
                    }
                }
            },
            _capMap: {
                start: 'startCap',
                end: 'endCap'
            },
            _redrawMarker: function (pathChange, position, options) {
                this._normalizeMarkerOptions(options);
                var pathOptions = this.options;
                var cap = this._capMap[position];
                var pathCapType = (pathOptions[cap] || {}).type;
                var optionsCap = options[cap];
                var created = false;
                if (optionsCap) {
                    pathOptions[cap] = deepExtend({}, pathOptions[cap], optionsCap);
                    if (optionsCap.type && pathCapType != optionsCap.type) {
                        this._removeMarker(position);
                        this._markers[position] = this._createMarker(pathOptions[cap], position);
                        created = true;
                    } else if (this._markers[position]) {
                        this._markers[position].redraw(optionsCap);
                    }
                } else if (pathChange && !this._markers[position] && pathOptions[cap]) {
                    this._markers[position] = this._createMarker(pathOptions[cap], position);
                    created = true;
                }
                return created;
            },
            _redrawMarkers: function (pathChange, options) {
                if (!this._redrawMarker(pathChange, START, options) && pathChange) {
                    this._positionMarker(START);
                }
                if (!this._redrawMarker(pathChange, END, options) && pathChange) {
                    this._positionMarker(END);
                }
            }
        };
        var Path = VisualBase.extend({
            init: function (options) {
                VisualBase.fn.init.call(this, options);
                this.container = new d.Group();
                this._createElements();
                this._initSize();
            },
            options: { autoSize: true },
            drawingContainer: function () {
                return this.container;
            },
            data: function (value) {
                var options = this.options;
                if (value) {
                    if (options.data != value) {
                        options.data = value;
                        this._setData(value);
                        this._initSize();
                        this._redrawMarkers(true, {});
                    }
                } else {
                    return options.data;
                }
            },
            redraw: function (options) {
                if (options) {
                    VisualBase.fn.redraw.call(this, options);
                    var pathOptions = this.options;
                    var data = options.data;
                    if (defined(data) && pathOptions.data != data) {
                        pathOptions.data = data;
                        this._setData(data);
                        if (!this._updateSize(options)) {
                            this._initSize();
                        }
                        this._redrawMarkers(true, options);
                    } else {
                        this._updateSize(options);
                        this._redrawMarkers(false, options);
                    }
                }
            },
            _createElements: function () {
                var options = this.options;
                this.drawingElement = d.Path.parse(options.data || '', { stroke: options.stroke });
                this._fill();
                this.container.append(this.drawingElement);
                this._createMarkers();
            },
            _setData: function (data) {
                var drawingElement = this.drawingElement;
                var multipath = d.Path.parse(data || '');
                var paths = multipath.paths.slice(0);
                multipath.paths.elements([]);
                drawingElement.paths.elements(paths);
            }
        });
        deepExtend(Path.fn, AutoSizeableMixin);
        deepExtend(Path.fn, MarkerPathMixin);
        var Line = VisualBase.extend({
            init: function (options) {
                VisualBase.fn.init.call(this, options);
                this.container = new d.Group();
                this._initPath();
                this._createMarkers();
            },
            drawingContainer: function () {
                return this.container;
            },
            redraw: function (options) {
                if (options) {
                    options = options || {};
                    var from = options.from;
                    var to = options.to;
                    if (from) {
                        this.options.from = from;
                    }
                    if (to) {
                        this.options.to = to;
                    }
                    if (from || to) {
                        this._drawPath();
                        this._redrawMarkers(true, options);
                    } else {
                        this._redrawMarkers(false, options);
                    }
                    VisualBase.fn.redraw.call(this, options);
                }
            },
            _initPath: function () {
                var options = this.options;
                var drawingElement = this.drawingElement = new d.Path({ stroke: options.stroke });
                this._fill();
                this._drawPath();
                this.container.append(drawingElement);
            },
            _drawPath: function () {
                var options = this.options;
                var drawingElement = this.drawingElement;
                var from = options.from || new Point();
                var to = options.to || new Point();
                drawingElement.segments.elements([
                    createSegment(from.x, from.y),
                    createSegment(to.x, to.y)
                ]);
            }
        });
        deepExtend(Line.fn, MarkerPathMixin);
        var Polyline = VisualBase.extend({
            init: function (options) {
                VisualBase.fn.init.call(this, options);
                this.container = new d.Group();
                this._initPath();
                this._createMarkers();
            },
            drawingContainer: function () {
                return this.container;
            },
            points: function (points) {
                var options = this.options;
                if (points) {
                    options.points = points;
                    this._updatePath();
                } else {
                    return options.points;
                }
            },
            redraw: function (options) {
                if (options) {
                    var points = options.points;
                    VisualBase.fn.redraw.call(this, options);
                    if (points && this._pointsDiffer(points)) {
                        this.points(points);
                        this._redrawMarkers(true, options);
                    } else {
                        this._redrawMarkers(false, options);
                    }
                }
            },
            _initPath: function () {
                var options = this.options;
                this.drawingElement = new d.Path({ stroke: options.stroke });
                this._fill();
                this.container.append(this.drawingElement);
                if (options.points) {
                    this._updatePath();
                }
            },
            _pointsDiffer: function (points) {
                var currentPoints = this.options.points;
                var differ = currentPoints.length !== points.length;
                if (!differ) {
                    for (var i = 0; i < points.length; i++) {
                        if (currentPoints[i].x !== points[i].x || currentPoints[i].y !== points[i].y) {
                            differ = true;
                            break;
                        }
                    }
                }
                return differ;
            },
            _updatePath: function () {
                var drawingElement = this.drawingElement;
                var options = this.options;
                var points = options.points;
                var segments = [];
                var point;
                for (var i = 0; i < points.length; i++) {
                    point = points[i];
                    segments.push(createSegment(point.x, point.y));
                }
                drawingElement.segments.elements(segments);
            },
            options: { points: [] }
        });
        deepExtend(Polyline.fn, MarkerPathMixin);
        var Image = Element.extend({
            init: function (options) {
                Element.fn.init.call(this, options);
                this._initImage();
            },
            redraw: function (options) {
                if (options) {
                    if (options.source) {
                        this.drawingElement.src(options.source);
                    }
                    if (this._diffNumericOptions(options, [
                            WIDTH,
                            HEIGHT,
                            X,
                            Y
                        ])) {
                        this.drawingElement.rect(this._rect());
                    }
                    Element.fn.redraw.call(this, options);
                }
            },
            _initImage: function () {
                var options = this.options;
                var rect = this._rect();
                this.drawingElement = new d.Image(options.source, rect, {});
            },
            _rect: function () {
                var sizeOptions = sizeOptionsOrDefault(this.options);
                var origin = new g.Point(sizeOptions.x, sizeOptions.y);
                var size = new g.Size(sizeOptions.width, sizeOptions.height);
                return new g.Rect(origin, size);
            }
        });
        var Group = Element.extend({
            init: function (options) {
                this.children = [];
                Element.fn.init.call(this, options);
                this.drawingElement = new d.Group();
                this._initSize();
            },
            options: { autoSize: false },
            append: function (visual) {
                this.drawingElement.append(visual.drawingContainer());
                this.children.push(visual);
                this._childrenChange = true;
            },
            remove: function (visual) {
                if (this._remove(visual)) {
                    this._childrenChange = true;
                }
            },
            _remove: function (visual) {
                var index = inArray(visual, this.children);
                if (index >= 0) {
                    this.drawingElement.removeAt(index);
                    this.children.splice(index, 1);
                    return true;
                }
            },
            clear: function () {
                this.drawingElement.clear();
                this.children = [];
                this._childrenChange = true;
            },
            toFront: function (visuals) {
                var visual;
                for (var i = 0; i < visuals.length; i++) {
                    visual = visuals[i];
                    if (this._remove(visual)) {
                        this.append(visual);
                    }
                }
            },
            toBack: function (visuals) {
                this._reorderChildren(visuals, 0);
            },
            toIndex: function (visuals, indices) {
                this._reorderChildren(visuals, indices);
            },
            _reorderChildren: function (visuals, indices) {
                var group = this.drawingElement;
                var drawingChildren = group.children.slice(0);
                var children = this.children;
                var fixedPosition = isNumber(indices);
                var i, index, toIndex, drawingElement, visual;
                for (i = 0; i < visuals.length; i++) {
                    visual = visuals[i];
                    drawingElement = visual.drawingContainer();
                    index = inArray(visual, children);
                    if (index >= 0) {
                        drawingChildren.splice(index, 1);
                        children.splice(index, 1);
                        toIndex = fixedPosition ? indices : indices[i];
                        drawingChildren.splice(toIndex, 0, drawingElement);
                        children.splice(toIndex, 0, visual);
                    }
                }
                group.clear();
                group.append.apply(group, drawingChildren);
            },
            redraw: function (options) {
                if (options) {
                    if (this._childrenChange) {
                        this._childrenChange = false;
                        if (!this._updateSize(options)) {
                            this._initSize();
                        }
                    } else {
                        this._updateSize(options);
                    }
                    Element.fn.redraw.call(this, options);
                }
            },
            _boundingBox: function () {
                var children = this.children;
                var boundingBox;
                var visual, childBoundingBox;
                for (var i = 0; i < children.length; i++) {
                    visual = children[i];
                    if (visual.visible() && visual._includeInBBox !== false) {
                        childBoundingBox = visual.drawingContainer().clippedBBox(null);
                        if (childBoundingBox) {
                            if (boundingBox) {
                                boundingBox = g.Rect.union(boundingBox, childBoundingBox);
                            } else {
                                boundingBox = childBoundingBox;
                            }
                        }
                    }
                }
                return boundingBox;
            }
        });
        deepExtend(Group.fn, AutoSizeableMixin);
        var Layout = Group.extend({
            init: function (rect, options) {
                this.children = [];
                Element.fn.init.call(this, options);
                this.drawingElement = new d.Layout(toDrawingRect(rect), options);
                this._initSize();
            },
            rect: function (rect) {
                if (rect) {
                    this.drawingElement.rect(toDrawingRect(rect));
                } else {
                    var drawingRect = this.drawingElement.rect();
                    if (drawingRect) {
                        return new Rect(drawingRect.origin.x, drawingRect.origin.y, drawingRect.size.width, drawingRect.size.height);
                    }
                }
            },
            reflow: function () {
                this.drawingElement.reflow();
            },
            redraw: function (options) {
                kendo.deepExtend(this.drawingElement.options, options);
                Group.fn.redraw.call(this, options);
            }
        });
        var Circle = VisualBase.extend({
            init: function (options) {
                VisualBase.fn.init.call(this, options);
                this._initCircle();
                this._initSize();
            },
            redraw: function (options) {
                if (options) {
                    var circleOptions = this.options;
                    if (options.center) {
                        deepExtend(circleOptions, { center: options.center });
                        this._center.move(circleOptions.center.x, circleOptions.center.y);
                    }
                    if (this._diffNumericOptions(options, ['radius'])) {
                        this._circle.setRadius(circleOptions.radius);
                    }
                    this._updateSize(options);
                    VisualBase.fn.redraw.call(this, options);
                }
            },
            _initCircle: function () {
                var options = this.options;
                var width = options.width;
                var height = options.height;
                var radius = options.radius;
                if (!defined(radius)) {
                    if (!defined(width)) {
                        width = height;
                    }
                    if (!defined(height)) {
                        height = width;
                    }
                    options.radius = radius = Math.min(width, height) / 2;
                }
                var center = options.center || {
                    x: radius,
                    y: radius
                };
                this._center = new g.Point(center.x, center.y);
                this._circle = new g.Circle(this._center, radius);
                this.drawingElement = new d.Circle(this._circle, { stroke: options.stroke });
                this._fill();
            }
        });
        deepExtend(Circle.fn, AutoSizeableMixin);
        var Canvas = Class.extend({
            init: function (element, options) {
                options = options || {};
                this.element = element;
                this.surface = d.Surface.create(element, options);
                if (kendo.isFunction(this.surface.translate)) {
                    this.translate = this._translate;
                }
                this.drawingElement = new d.Group();
                this._viewBox = new Rect(0, 0, options.width, options.height);
                this.size(this._viewBox);
            },
            bounds: function () {
                var box = this.drawingElement.clippedBBox();
                return new Rect(0, 0, box.width(), box.height());
            },
            size: function (size) {
                var viewBox = this._viewBox;
                if (defined(size)) {
                    viewBox.width = size.width;
                    viewBox.height = size.height;
                    this.surface.setSize(size);
                }
                return {
                    width: viewBox.width,
                    height: viewBox.height
                };
            },
            _translate: function (x, y) {
                var viewBox = this._viewBox;
                if (defined(x) && defined(y)) {
                    viewBox.x = x;
                    viewBox.y = y;
                    this.surface.translate({
                        x: x,
                        y: y
                    });
                }
                return {
                    x: viewBox.x,
                    y: viewBox.y
                };
            },
            draw: function () {
                this.surface.draw(this.drawingElement);
            },
            append: function (visual) {
                this.drawingElement.append(visual.drawingContainer());
                return this;
            },
            remove: function (visual) {
                this.drawingElement.remove(visual.drawingContainer());
            },
            insertBefore: function () {
            },
            clear: function () {
                this.drawingElement.clear();
            },
            destroy: function (clearHtml) {
                this.surface.destroy();
                if (clearHtml) {
                    $(this.element).remove();
                }
            }
        });
        function sizeOptionsOrDefault(options) {
            return {
                x: options.x || 0,
                y: options.y || 0,
                width: options.width || 0,
                height: options.height || 0
            };
        }
        function normalizeDrawingOptions(options) {
            if (options) {
                var drawingOptions = options;
                if (isString(drawingOptions)) {
                    drawingOptions = { color: drawingOptions };
                }
                if (drawingOptions.color) {
                    drawingOptions.color = getColor(drawingOptions.color);
                }
                return drawingOptions;
            }
        }
        function getColor(value) {
            var color;
            if (value != TRANSPARENT) {
                color = new d.Color(value).toHex();
            } else {
                color = value;
            }
            return color;
        }
        function lineAngle(p1, p2) {
            var xDiff = p2.x - p1.x;
            var yDiff = p2.y - p1.y;
            var angle = d.util.deg(Math.atan2(yDiff, xDiff));
            return angle;
        }
        function createSegment(x, y) {
            return new d.Segment(new g.Point(x, y));
        }
        function toDrawingRect(rect) {
            if (rect) {
                return new g.Rect([
                    rect.x,
                    rect.y
                ], [
                    rect.width,
                    rect.height
                ]);
            }
        }
        kendo.deepExtend(diagram, {
            init: function (element) {
                kendo.init(element, diagram.ui);
            },
            diffNumericOptions: diffNumericOptions,
            Element: Element,
            Scale: Scale,
            Translation: Translation,
            Rotation: Rotation,
            Circle: Circle,
            Group: Group,
            Rectangle: Rectangle,
            Canvas: Canvas,
            Path: Path,
            Layout: Layout,
            Line: Line,
            MarkerBase: MarkerBase,
            ArrowMarker: ArrowMarker,
            CircleMarker: CircleMarker,
            Polyline: Polyline,
            CompositeTransform: CompositeTransform,
            TextBlock: TextBlock,
            Image: Image,
            VisualBase: VisualBase
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/diagram/services', [
        'kendo.drawing',
        'dataviz/diagram/svg'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, dataviz = kendo.dataviz, diagram = dataviz.diagram, Class = kendo.Class, Group = diagram.Group, Rect = diagram.Rect, Rectangle = diagram.Rectangle, Utils = diagram.Utils, isUndefined = Utils.isUndefined, Point = diagram.Point, Circle = diagram.Circle, Ticker = diagram.Ticker, deepExtend = kendo.deepExtend, Movable = kendo.ui.Movable, browser = kendo.support.browser, util = kendo.drawing.util, defined = util.defined, inArray = $.inArray, proxy = $.proxy;
        var Cursors = {
                arrow: 'default',
                grip: 'pointer',
                cross: 'pointer',
                add: 'pointer',
                move: 'move',
                select: 'pointer',
                south: 's-resize',
                east: 'e-resize',
                west: 'w-resize',
                north: 'n-resize',
                rowresize: 'row-resize',
                colresize: 'col-resize'
            }, HIT_TEST_DISTANCE = 10, AUTO = 'Auto', TOP = 'Top', RIGHT = 'Right', LEFT = 'Left', BOTTOM = 'Bottom', DEFAULT_SNAP_SIZE = 10, DEFAULT_SNAP_ANGLE = 10, DRAG_START = 'dragStart', DRAG = 'drag', DRAG_END = 'dragEnd', ITEMROTATE = 'itemRotate', ITEMBOUNDSCHANGE = 'itemBoundsChange', MIN_SNAP_SIZE = 5, MIN_SNAP_ANGLE = 5, MOUSE_ENTER = 'mouseEnter', MOUSE_LEAVE = 'mouseLeave', ZOOM_START = 'zoomStart', ZOOM_END = 'zoomEnd', SCROLL_MIN = -20000, SCROLL_MAX = 20000, FRICTION = 0.9, FRICTION_MOBILE = 0.93, VELOCITY_MULTIPLIER = 5, TRANSPARENT = 'transparent', PAN = 'pan', ROTATED = 'rotated', SOURCE = 'source', TARGET = 'target', HANDLE_NAMES = {
                '-1': SOURCE,
                '1': TARGET
            };
        diagram.Cursors = Cursors;
        var PositionAdapter = kendo.Class.extend({
            init: function (layoutState) {
                this.layoutState = layoutState;
                this.diagram = layoutState.diagram;
            },
            initState: function () {
                this.froms = [];
                this.tos = [];
                this.subjects = [];
                function pusher(id, bounds) {
                    var shape = this.diagram.getShapeById(id);
                    if (shape) {
                        this.subjects.push(shape);
                        this.froms.push(shape.bounds().topLeft());
                        this.tos.push(bounds.topLeft());
                    }
                }
                this.layoutState.nodeMap.forEach(pusher, this);
            },
            update: function (tick) {
                if (this.subjects.length <= 0) {
                    return;
                }
                for (var i = 0; i < this.subjects.length; i++) {
                    this.subjects[i].position(new Point(this.froms[i].x + (this.tos[i].x - this.froms[i].x) * tick, this.froms[i].y + (this.tos[i].y - this.froms[i].y) * tick));
                }
            }
        });
        var LayoutUndoUnit = Class.extend({
            init: function (initialState, finalState, animate) {
                if (isUndefined(animate)) {
                    this.animate = false;
                } else {
                    this.animate = animate;
                }
                this._initialState = initialState;
                this._finalState = finalState;
                this.title = 'Diagram layout';
            },
            undo: function () {
                this.setState(this._initialState);
            },
            redo: function () {
                this.setState(this._finalState);
            },
            setState: function (state) {
                var diagram = state.diagram;
                if (this.animate) {
                    state.linkMap.forEach(function (id, points) {
                        var conn = diagram.getShapeById(id);
                        conn.visible(false);
                        if (conn) {
                            conn.points(points);
                        }
                    });
                    var ticker = new Ticker();
                    ticker.addAdapter(new PositionAdapter(state));
                    ticker.onComplete(function () {
                        state.linkMap.forEach(function (id) {
                            var conn = diagram.getShapeById(id);
                            conn.visible(true);
                        });
                    });
                    ticker.play();
                } else {
                    state.nodeMap.forEach(function (id, bounds) {
                        var shape = diagram.getShapeById(id);
                        if (shape) {
                            shape.position(bounds.topLeft());
                        }
                    });
                    state.linkMap.forEach(function (id, points) {
                        var conn = diagram.getShapeById(id);
                        if (conn) {
                            conn.points(points);
                        }
                    });
                }
            }
        });
        var CompositeUnit = Class.extend({
            init: function (unit) {
                this.units = [];
                this.title = 'Composite unit';
                if (unit !== undefined) {
                    this.units.push(unit);
                }
            },
            add: function (undoUnit) {
                this.units.push(undoUnit);
            },
            undo: function () {
                for (var i = 0; i < this.units.length; i++) {
                    this.units[i].undo();
                }
            },
            redo: function () {
                for (var i = 0; i < this.units.length; i++) {
                    this.units[i].redo();
                }
            }
        });
        var ConnectionEditUnit = Class.extend({
            init: function (item, redoSource, redoTarget) {
                this.item = item;
                this._redoSource = redoSource;
                this._redoTarget = redoTarget;
                if (defined(redoSource)) {
                    this._undoSource = item.source();
                }
                if (defined(redoTarget)) {
                    this._undoTarget = item.target();
                }
                this.title = 'Connection Editing';
            },
            undo: function () {
                if (this._undoSource !== undefined) {
                    this.item._updateConnector(this._undoSource, 'source');
                }
                if (this._undoTarget !== undefined) {
                    this.item._updateConnector(this._undoTarget, 'target');
                }
                this.item.updateModel();
            },
            redo: function () {
                if (this._redoSource !== undefined) {
                    this.item._updateConnector(this._redoSource, 'source');
                }
                if (this._redoTarget !== undefined) {
                    this.item._updateConnector(this._redoTarget, 'target');
                }
                this.item.updateModel();
            }
        });
        var ConnectionEditUndoUnit = Class.extend({
            init: function (item, undoSource, undoTarget) {
                this.item = item;
                this._undoSource = undoSource;
                this._undoTarget = undoTarget;
                this._redoSource = item.source();
                this._redoTarget = item.target();
                this.title = 'Connection Editing';
            },
            undo: function () {
                this.item._updateConnector(this._undoSource, 'source');
                this.item._updateConnector(this._undoTarget, 'target');
                this.item.updateModel();
            },
            redo: function () {
                this.item._updateConnector(this._redoSource, 'source');
                this.item._updateConnector(this._redoTarget, 'target');
                this.item.updateModel();
            }
        });
        var DeleteConnectionUnit = Class.extend({
            init: function (connection) {
                this.connection = connection;
                this.diagram = connection.diagram;
                this.targetConnector = connection.targetConnector;
                this.title = 'Delete connection';
            },
            undo: function () {
                this.diagram._addConnection(this.connection, false);
            },
            redo: function () {
                this.diagram.remove(this.connection, false);
            }
        });
        var DeleteShapeUnit = Class.extend({
            init: function (shape) {
                this.shape = shape;
                this.diagram = shape.diagram;
                this.title = 'Deletion';
            },
            undo: function () {
                this.diagram._addShape(this.shape, false);
                this.shape.select(false);
            },
            redo: function () {
                this.shape.select(false);
                this.diagram.remove(this.shape, false);
            }
        });
        var TransformUnit = Class.extend({
            init: function (shapes, undoStates, adorner) {
                this.shapes = shapes;
                this.undoStates = undoStates;
                this.title = 'Transformation';
                this.redoStates = [];
                this.adorner = adorner;
                for (var i = 0; i < this.shapes.length; i++) {
                    var shape = this.shapes[i];
                    this.redoStates.push(shape.bounds());
                }
            },
            undo: function () {
                for (var i = 0; i < this.shapes.length; i++) {
                    var shape = this.shapes[i];
                    shape.bounds(this.undoStates[i]);
                    if (shape.hasOwnProperty('layout')) {
                        shape.layout(shape, this.redoStates[i], this.undoStates[i]);
                    }
                    shape.updateModel();
                }
                if (this.adorner) {
                    this.adorner.refreshBounds();
                    this.adorner.refresh();
                }
            },
            redo: function () {
                for (var i = 0; i < this.shapes.length; i++) {
                    var shape = this.shapes[i];
                    shape.bounds(this.redoStates[i]);
                    if (shape.hasOwnProperty('layout')) {
                        shape.layout(shape, this.undoStates[i], this.redoStates[i]);
                    }
                    shape.updateModel();
                }
                if (this.adorner) {
                    this.adorner.refreshBounds();
                    this.adorner.refresh();
                }
            }
        });
        var AddConnectionUnit = Class.extend({
            init: function (connection, diagram) {
                this.connection = connection;
                this.diagram = diagram;
                this.title = 'New connection';
            },
            undo: function () {
                this.diagram.remove(this.connection, false);
            },
            redo: function () {
                this.diagram._addConnection(this.connection, false);
            }
        });
        var AddShapeUnit = Class.extend({
            init: function (shape, diagram) {
                this.shape = shape;
                this.diagram = diagram;
                this.title = 'New shape';
            },
            undo: function () {
                this.diagram.deselect();
                this.diagram.remove(this.shape, false);
            },
            redo: function () {
                this.diagram._addShape(this.shape, false);
            }
        });
        var PanUndoUnit = Class.extend({
            init: function (initialPosition, finalPosition, diagram) {
                this.initial = initialPosition;
                this.finalPos = finalPosition;
                this.diagram = diagram;
                this.title = 'Pan Unit';
            },
            undo: function () {
                this.diagram.pan(this.initial);
            },
            redo: function () {
                this.diagram.pan(this.finalPos);
            }
        });
        var RotateUnit = Class.extend({
            init: function (adorner, shapes, undoRotates) {
                this.shapes = shapes;
                this.undoRotates = undoRotates;
                this.title = 'Rotation';
                this.redoRotates = [];
                this.redoAngle = adorner._angle;
                this.adorner = adorner;
                this.center = adorner._innerBounds.center();
                for (var i = 0; i < this.shapes.length; i++) {
                    var shape = this.shapes[i];
                    this.redoRotates.push(shape.rotate().angle);
                }
            },
            undo: function () {
                var i, shape;
                for (i = 0; i < this.shapes.length; i++) {
                    shape = this.shapes[i];
                    shape.rotate(this.undoRotates[i], this.center, false);
                    if (shape.hasOwnProperty('layout')) {
                        shape.layout(shape);
                    }
                    shape.updateModel();
                }
                if (this.adorner) {
                    this.adorner._initialize();
                    this.adorner.refresh();
                }
            },
            redo: function () {
                var i, shape;
                for (i = 0; i < this.shapes.length; i++) {
                    shape = this.shapes[i];
                    shape.rotate(this.redoRotates[i], this.center, false);
                    if (shape.hasOwnProperty('layout')) {
                        shape.layout(shape);
                    }
                    shape.updateModel();
                }
                if (this.adorner) {
                    this.adorner._initialize();
                    this.adorner.refresh();
                }
            }
        });
        var ToFrontUnit = Class.extend({
            init: function (diagram, items, initialIndices) {
                this.diagram = diagram;
                this.indices = initialIndices;
                this.items = items;
                this.title = 'Rotate Unit';
            },
            undo: function () {
                this.diagram._toIndex(this.items, this.indices);
            },
            redo: function () {
                this.diagram.toFront(this.items, false);
            }
        });
        var ToBackUnit = Class.extend({
            init: function (diagram, items, initialIndices) {
                this.diagram = diagram;
                this.indices = initialIndices;
                this.items = items;
                this.title = 'Rotate Unit';
            },
            undo: function () {
                this.diagram._toIndex(this.items, this.indices);
            },
            redo: function () {
                this.diagram.toBack(this.items, false);
            }
        });
        var UndoRedoService = kendo.Observable.extend({
            init: function (options) {
                kendo.Observable.fn.init.call(this, options);
                this.bind(this.events, options);
                this.stack = [];
                this.index = 0;
                this.capacity = 100;
            },
            events: [
                'undone',
                'redone'
            ],
            begin: function () {
                this.composite = new CompositeUnit();
            },
            cancel: function () {
                this.composite = undefined;
            },
            commit: function (execute) {
                if (this.composite.units.length > 0) {
                    this._restart(this.composite, execute);
                }
                this.composite = undefined;
            },
            addCompositeItem: function (undoUnit) {
                if (this.composite) {
                    this.composite.add(undoUnit);
                } else {
                    this.add(undoUnit);
                }
            },
            add: function (undoUnit, execute) {
                this._restart(undoUnit, execute);
            },
            pop: function () {
                if (this.index > 0) {
                    this.stack.pop();
                    this.index--;
                }
            },
            count: function () {
                return this.stack.length;
            },
            undo: function () {
                if (this.index > 0) {
                    this.index--;
                    this.stack[this.index].undo();
                    this.trigger('undone');
                }
            },
            redo: function () {
                if (this.stack.length > 0 && this.index < this.stack.length) {
                    this.stack[this.index].redo();
                    this.index++;
                    this.trigger('redone');
                }
            },
            _restart: function (composite, execute) {
                this.stack.splice(this.index, this.stack.length - this.index);
                this.stack.push(composite);
                if (execute !== false) {
                    this.redo();
                } else {
                    this.index++;
                }
                if (this.stack.length > this.capacity) {
                    this.stack.splice(0, this.stack.length - this.capacity);
                    this.index = this.capacity;
                }
            },
            clear: function () {
                this.stack = [];
                this.index = 0;
            }
        });
        var EmptyTool = Class.extend({
            init: function (toolService) {
                this.toolService = toolService;
            },
            start: function () {
            },
            move: function () {
            },
            end: function () {
            },
            tryActivate: function () {
                return false;
            },
            getCursor: function () {
                return Cursors.arrow;
            }
        });
        var ScrollerTool = EmptyTool.extend({
            init: function (toolService) {
                var tool = this;
                var friction = kendo.support.mobileOS ? FRICTION_MOBILE : FRICTION;
                EmptyTool.fn.init.call(tool, toolService);
                var diagram = tool.toolService.diagram, canvas = diagram.canvas;
                var scroller = diagram.scroller = tool.scroller = $(diagram.scrollable).kendoMobileScroller({
                    friction: friction,
                    velocityMultiplier: VELOCITY_MULTIPLIER,
                    mousewheelScrolling: false,
                    zoom: false,
                    scroll: proxy(tool._move, tool)
                }).data('kendoMobileScroller');
                if (canvas.translate) {
                    tool.movableCanvas = new Movable(canvas.element);
                }
                var virtualScroll = function (dimension, min, max) {
                    dimension.makeVirtual();
                    dimension.virtualSize(min || SCROLL_MIN, max || SCROLL_MAX);
                };
                virtualScroll(scroller.dimensions.x);
                virtualScroll(scroller.dimensions.y);
                scroller.disable();
            },
            tryActivate: function (p, meta) {
                var toolService = this.toolService;
                var options = toolService.diagram.options.pannable;
                var enabled = meta.ctrlKey;
                if (defined(options.key)) {
                    if (!options.key || options.key == 'none') {
                        enabled = noMeta(meta) && !defined(toolService.hoveredItem);
                    } else {
                        enabled = meta[options.key + 'Key'];
                    }
                }
                return options !== false && enabled && !defined(toolService.hoveredAdorner) && !defined(toolService._hoveredConnector);
            },
            start: function () {
                this.scroller.enable();
            },
            move: function () {
            },
            _move: function (args) {
                var tool = this, diagram = tool.toolService.diagram, canvas = diagram.canvas, scrollPos = new Point(args.scrollLeft, args.scrollTop);
                if (canvas.translate) {
                    diagram._storePan(scrollPos.times(-1));
                    tool.movableCanvas.moveTo(scrollPos);
                    canvas.translate(scrollPos.x, scrollPos.y);
                } else {
                    scrollPos = scrollPos.plus(diagram._pan.times(-1));
                }
                diagram.trigger(PAN, { pan: scrollPos });
            },
            end: function () {
                this.scroller.disable();
            },
            getCursor: function () {
                return Cursors.move;
            }
        });
        var PointerTool = Class.extend({
            init: function (toolService) {
                this.toolService = toolService;
            },
            tryActivate: function () {
                return true;
            },
            start: function (p, meta) {
                var toolService = this.toolService, diagram = toolService.diagram, hoveredItem = toolService.hoveredItem;
                if (hoveredItem) {
                    toolService.selectSingle(hoveredItem, meta);
                    if (hoveredItem.adorner) {
                        this.adorner = hoveredItem.adorner;
                        this.handle = this.adorner._hitTest(p);
                    }
                }
                if (!this.handle) {
                    this.handle = diagram._resizingAdorner._hitTest(p);
                    if (this.handle) {
                        this.adorner = diagram._resizingAdorner;
                    }
                }
                if (this.adorner) {
                    if (!this.adorner.isDragHandle(this.handle) || !diagram.trigger(DRAG_START, {
                            shapes: this.adorner.shapes,
                            connections: []
                        })) {
                        this.adorner.start(p);
                    } else {
                        toolService.startPoint = p;
                        toolService.end(p);
                    }
                }
            },
            move: function (p) {
                if (this.adorner) {
                    this.adorner.move(this.handle, p);
                    if (this.adorner.isDragHandle(this.handle)) {
                        this.toolService.diagram.trigger(DRAG, {
                            shapes: this.adorner.shapes,
                            connections: []
                        });
                    }
                }
            },
            end: function () {
                var diagram = this.toolService.diagram, adorner = this.adorner, unit;
                if (adorner) {
                    if (!adorner.isDragHandle(this.handle) || !diagram.trigger(DRAG_END, {
                            shapes: adorner.shapes,
                            connections: []
                        })) {
                        unit = adorner.stop();
                        if (unit) {
                            diagram.undoRedoService.add(unit, false);
                        }
                    } else {
                        adorner.cancel();
                    }
                }
                this.adorner = undefined;
                this.handle = undefined;
            },
            getCursor: function (p) {
                return this.toolService.hoveredItem ? this.toolService.hoveredItem._getCursor(p) : Cursors.arrow;
            }
        });
        var SelectionTool = Class.extend({
            init: function (toolService) {
                this.toolService = toolService;
            },
            tryActivate: function (p, meta) {
                var toolService = this.toolService;
                var selectable = toolService.diagram.options.selectable;
                var enabled = selectable && selectable.multiple !== false;
                if (enabled) {
                    if (selectable.key && selectable.key != 'none') {
                        enabled = meta[selectable.key + 'Key'];
                    } else {
                        enabled = noMeta(meta);
                    }
                }
                return enabled && !defined(toolService.hoveredItem) && !defined(toolService.hoveredAdorner);
            },
            start: function (p) {
                var diagram = this.toolService.diagram;
                diagram.deselect();
                diagram.selector.start(p);
            },
            move: function (p) {
                var diagram = this.toolService.diagram;
                diagram.selector.move(p);
            },
            end: function (p, meta) {
                var diagram = this.toolService.diagram, hoveredItem = this.toolService.hoveredItem;
                var rect = diagram.selector.bounds();
                if ((!hoveredItem || !hoveredItem.isSelected) && !meta.ctrlKey) {
                    diagram.deselect();
                }
                if (!rect.isEmpty()) {
                    diagram.selectArea(rect);
                }
                diagram.selector.end();
            },
            getCursor: function () {
                return Cursors.arrow;
            }
        });
        var ConnectionTool = Class.extend({
            init: function (toolService) {
                this.toolService = toolService;
                this.type = 'ConnectionTool';
            },
            tryActivate: function () {
                return this.toolService._hoveredConnector;
            },
            start: function (p, meta) {
                var toolService = this.toolService, diagram = toolService.diagram, connector = toolService._hoveredConnector, connection = diagram._createConnection({}, connector._c, p);
                if (canDrag(connection) && !diagram.trigger(DRAG_START, {
                        shapes: [],
                        connections: [connection],
                        connectionHandle: TARGET
                    }) && diagram._addConnection(connection)) {
                    toolService._connectionManipulation(connection, connector._c.shape, true);
                    toolService._removeHover();
                    toolService.selectSingle(toolService.activeConnection, meta);
                    if (meta.type == 'touchmove') {
                        diagram._cachedTouchTarget = connector.visual;
                    }
                } else {
                    connection.source(null);
                    toolService.end(p);
                }
            },
            move: function (p) {
                var toolService = this.toolService;
                var connection = toolService.activeConnection;
                connection.target(p);
                toolService.diagram.trigger(DRAG, {
                    shapes: [],
                    connections: [connection],
                    connectionHandle: TARGET
                });
                return true;
            },
            end: function (p) {
                var toolService = this.toolService, d = toolService.diagram, connection = toolService.activeConnection, hoveredItem = toolService.hoveredItem, connector = toolService._hoveredConnector, target, cachedTouchTarget = d._cachedTouchTarget;
                if (!connection) {
                    return;
                }
                if (connector && connector._c != connection.sourceConnector) {
                    target = connector._c;
                } else if (hoveredItem && hoveredItem instanceof diagram.Shape) {
                    target = hoveredItem.getConnector(AUTO) || hoveredItem.getConnector(p);
                } else {
                    target = p;
                }
                connection.target(target);
                if (!d.trigger(DRAG_END, {
                        shapes: [],
                        connections: [connection],
                        connectionHandle: TARGET
                    })) {
                    connection.updateModel();
                    d._syncConnectionChanges();
                } else {
                    d.remove(connection, false);
                    d.undoRedoService.pop();
                }
                toolService._connectionManipulation();
                if (cachedTouchTarget) {
                    d._connectorsAdorner.visual.remove(cachedTouchTarget);
                    d._cachedTouchTarget = null;
                }
            },
            getCursor: function () {
                return Cursors.arrow;
            }
        });
        var ConnectionEditTool = Class.extend({
            init: function (toolService) {
                this.toolService = toolService;
                this.type = 'ConnectionTool';
            },
            tryActivate: function (p, meta) {
                var toolService = this.toolService, diagram = toolService.diagram, selectable = diagram.options.selectable, item = toolService.hoveredItem, isActive = selectable !== false && item && item.path && !(item.isSelected && meta.ctrlKey);
                if (isActive) {
                    this._c = item;
                }
                return isActive;
            },
            start: function (p, meta) {
                var toolService = this.toolService;
                var connection = this._c;
                toolService.selectSingle(connection, meta);
                var adorner = connection.adorner;
                var handle, name;
                if (adorner) {
                    handle = adorner._hitTest(p);
                    name = HANDLE_NAMES[handle];
                }
                if (canDrag(connection) && adorner && !toolService.diagram.trigger(DRAG_START, {
                        shapes: [],
                        connections: [connection],
                        connectionHandle: name
                    })) {
                    this.handle = handle;
                    this.handleName = name;
                    adorner.start(p);
                } else {
                    toolService.startPoint = p;
                    toolService.end(p);
                }
            },
            move: function (p) {
                var adorner = this._c.adorner;
                if (canDrag(this._c) && adorner) {
                    adorner.move(this.handle, p);
                    this.toolService.diagram.trigger(DRAG, {
                        shapes: [],
                        connections: [this._c],
                        connectionHandle: this.handleName
                    });
                    return true;
                }
            },
            end: function (p) {
                var connection = this._c;
                var adorner = connection.adorner;
                var toolService = this.toolService;
                var diagram = toolService.diagram;
                if (adorner) {
                    if (canDrag(connection)) {
                        var unit = adorner.stop(p);
                        if (!diagram.trigger(DRAG_END, {
                                shapes: [],
                                connections: [connection],
                                connectionHandle: this.handleName
                            })) {
                            diagram.undoRedoService.add(unit, false);
                            connection.updateModel();
                            diagram._syncConnectionChanges();
                        } else {
                            unit.undo();
                        }
                    }
                }
            },
            getCursor: function () {
                return Cursors.move;
            }
        });
        function testKey(key, str) {
            return str.charCodeAt(0) == key || str.toUpperCase().charCodeAt(0) == key;
        }
        var ToolService = Class.extend({
            init: function (diagram) {
                this.diagram = diagram;
                this.tools = [
                    new ScrollerTool(this),
                    new ConnectionEditTool(this),
                    new ConnectionTool(this),
                    new SelectionTool(this),
                    new PointerTool(this)
                ];
                this.activeTool = undefined;
            },
            start: function (p, meta) {
                meta = deepExtend({}, meta);
                if (this.activeTool) {
                    this.activeTool.end(p, meta);
                }
                this._updateHoveredItem(p);
                this._activateTool(p, meta);
                this.activeTool.start(p, meta);
                this._updateCursor(p);
                this.diagram.focus();
                this.diagram.canvas.surface.suspendTracking();
                this.startPoint = p;
                return true;
            },
            move: function (p, meta) {
                meta = deepExtend({}, meta);
                var updateHovered = true;
                if (this.activeTool) {
                    updateHovered = this.activeTool.move(p, meta);
                }
                if (updateHovered) {
                    this._updateHoveredItem(p);
                }
                this._updateCursor(p);
                return true;
            },
            end: function (p, meta) {
                meta = deepExtend({}, meta);
                if (this.activeTool) {
                    this.activeTool.end(p, meta);
                }
                this.diagram.canvas.surface.resumeTracking();
                this.activeTool = undefined;
                this._updateCursor(p);
                return true;
            },
            keyDown: function (key, meta) {
                var diagram = this.diagram;
                meta = deepExtend({
                    ctrlKey: false,
                    metaKey: false,
                    altKey: false
                }, meta);
                if ((meta.ctrlKey || meta.metaKey) && !meta.altKey) {
                    if (testKey(key, 'a')) {
                        diagram.selectAll();
                        diagram._destroyToolBar();
                        return true;
                    } else if (testKey(key, 'z')) {
                        diagram.undo();
                        diagram._destroyToolBar();
                        return true;
                    } else if (testKey(key, 'y')) {
                        diagram.redo();
                        diagram._destroyToolBar();
                        return true;
                    } else if (testKey(key, 'c')) {
                        diagram.copy();
                        diagram._destroyToolBar();
                    } else if (testKey(key, 'x')) {
                        diagram.cut();
                        diagram._destroyToolBar();
                    } else if (testKey(key, 'v')) {
                        diagram.paste();
                        diagram._destroyToolBar();
                    } else if (testKey(key, 'l')) {
                        diagram.layout();
                        diagram._destroyToolBar();
                    } else if (testKey(key, 'd')) {
                        diagram._destroyToolBar();
                        diagram.copy();
                        diagram.paste();
                    }
                } else if (key === 46 || key === 8) {
                    var toRemove = this.diagram._triggerRemove(diagram.select());
                    if (toRemove.length) {
                        this.diagram.remove(toRemove, true);
                        this.diagram._syncChanges();
                        this.diagram._destroyToolBar();
                    }
                    return true;
                } else if (key === 27) {
                    this._discardNewConnection();
                    diagram.deselect();
                    diagram._destroyToolBar();
                    return true;
                }
            },
            wheel: function (p, meta) {
                var diagram = this.diagram, delta = meta.delta, z = diagram.zoom(), options = diagram.options, zoomRate = options.zoomRate, zoomOptions = {
                        point: p,
                        meta: meta,
                        zoom: z
                    };
                if (diagram.trigger(ZOOM_START, zoomOptions)) {
                    return;
                }
                if (delta < 0) {
                    z += zoomRate;
                } else {
                    z -= zoomRate;
                }
                z = kendo.dataviz.round(Math.max(options.zoomMin, Math.min(options.zoomMax, z)), 2);
                zoomOptions.zoom = z;
                diagram.zoom(z, zoomOptions);
                diagram.trigger(ZOOM_END, zoomOptions);
                return true;
            },
            setTool: function (tool, index) {
                tool.toolService = this;
                this.tools[index] = tool;
            },
            selectSingle: function (item, meta) {
                var diagram = this.diagram;
                var selectable = diagram.options.selectable;
                if (selectable && !item.isSelected && item.options.selectable !== false) {
                    var addToSelection = meta.ctrlKey && selectable.multiple !== false;
                    diagram.select(item, { addToSelection: addToSelection });
                }
            },
            _discardNewConnection: function () {
                if (this.newConnection) {
                    this.diagram.remove(this.newConnection);
                    this.newConnection = undefined;
                }
            },
            _activateTool: function (p, meta) {
                for (var i = 0; i < this.tools.length; i++) {
                    var tool = this.tools[i];
                    if (tool.tryActivate(p, meta)) {
                        this.activeTool = tool;
                        break;
                    }
                }
            },
            _updateCursor: function (p) {
                var element = this.diagram.element;
                var cursor = this.activeTool ? this.activeTool.getCursor(p) : this.hoveredAdorner ? this.hoveredAdorner._getCursor(p) : this.hoveredItem ? this.hoveredItem._getCursor(p) : Cursors.arrow;
                element.css({ cursor: cursor });
                if (browser.msie && browser.version == 7) {
                    element[0].style.cssText = element[0].style.cssText;
                }
            },
            _connectionManipulation: function (connection, disabledShape, isNew) {
                this.activeConnection = connection;
                this.disabledShape = disabledShape;
                if (isNew) {
                    this.newConnection = this.activeConnection;
                } else {
                    this.newConnection = undefined;
                }
            },
            _updateHoveredItem: function (p) {
                var hit = this._hitTest(p);
                var diagram = this.diagram;
                if (hit != this.hoveredItem && (!this.disabledShape || hit != this.disabledShape)) {
                    if (this.hoveredItem) {
                        diagram.trigger(MOUSE_LEAVE, { item: this.hoveredItem });
                        this.hoveredItem._hover(false);
                    }
                    if (hit && hit.options.enable) {
                        diagram.trigger(MOUSE_ENTER, { item: hit });
                        this.hoveredItem = hit;
                        this.hoveredItem._hover(true);
                    } else {
                        this.hoveredItem = undefined;
                    }
                }
            },
            _removeHover: function () {
                if (this.hoveredItem) {
                    this.hoveredItem._hover(false);
                    this.hoveredItem = undefined;
                }
            },
            _hitTest: function (point) {
                var hit, d = this.diagram, item, i;
                if (this._hoveredConnector) {
                    this._hoveredConnector._hover(false);
                    this._hoveredConnector = undefined;
                }
                if (d._connectorsAdorner._visible) {
                    hit = d._connectorsAdorner._hitTest(point);
                    if (hit) {
                        return hit;
                    }
                }
                hit = this.diagram._resizingAdorner._hitTest(point);
                if (hit) {
                    this.hoveredAdorner = d._resizingAdorner;
                    if (hit.x !== 0 || hit.y !== 0) {
                        return;
                    }
                    hit = undefined;
                } else {
                    this.hoveredAdorner = undefined;
                }
                if (!this.activeTool || this.activeTool.type !== 'ConnectionTool') {
                    var selectedConnections = [];
                    for (i = 0; i < d._selectedItems.length; i++) {
                        item = d._selectedItems[i];
                        if (item instanceof diagram.Connection) {
                            selectedConnections.push(item);
                        }
                    }
                    hit = this._hitTestItems(selectedConnections, point);
                }
                return hit || this._hitTestElements(point);
            },
            _hitTestElements: function (point) {
                var diagram = this.diagram;
                var shapeHit = this._hitTestItems(diagram.shapes, point);
                var connectionHit = this._hitTestItems(diagram.connections, point);
                var hit;
                if ((!this.activeTool || this.activeTool.type != 'ConnectionTool') && shapeHit && connectionHit && !hitTestShapeConnectors(shapeHit, point)) {
                    var mainLayer = diagram.mainLayer;
                    var shapeIdx = inArray(shapeHit.visual, mainLayer.children);
                    var connectionIdx = inArray(connectionHit.visual, mainLayer.children);
                    hit = shapeIdx > connectionIdx ? shapeHit : connectionHit;
                }
                return hit || shapeHit || connectionHit;
            },
            _hitTestItems: function (array, point) {
                var i, item, hit;
                for (i = array.length - 1; i >= 0; i--) {
                    item = array[i];
                    hit = item._hitTest(point);
                    if (hit) {
                        return hit;
                    }
                }
            }
        });
        var ConnectionRouterBase = kendo.Class.extend({
            init: function () {
            }
        });
        var LinearConnectionRouter = ConnectionRouterBase.extend({
            init: function (connection) {
                var that = this;
                ConnectionRouterBase.fn.init.call(that);
                this.connection = connection;
            },
            hitTest: function (p) {
                var rec = this.getBounds().inflate(HIT_TEST_DISTANCE);
                if (!rec.contains(p)) {
                    return false;
                }
                return diagram.Geometry.distanceToPolyline(p, this.connection.allPoints()) < HIT_TEST_DISTANCE;
            },
            getBounds: function () {
                var points = this.connection.allPoints(), s = points[0], e = points[points.length - 1], right = Math.max(s.x, e.x), left = Math.min(s.x, e.x), top = Math.min(s.y, e.y), bottom = Math.max(s.y, e.y);
                for (var i = 1; i < points.length - 1; ++i) {
                    right = Math.max(right, points[i].x);
                    left = Math.min(left, points[i].x);
                    top = Math.min(top, points[i].y);
                    bottom = Math.max(bottom, points[i].y);
                }
                return new Rect(left, top, right - left, bottom - top);
            }
        });
        var PolylineRouter = LinearConnectionRouter.extend({
            init: function (connection) {
                var that = this;
                LinearConnectionRouter.fn.init.call(that);
                this.connection = connection;
            },
            route: function () {
            }
        });
        var CascadingRouter = LinearConnectionRouter.extend({
            SAME_SIDE_DISTANCE_RATIO: 5,
            init: function (connection) {
                var that = this;
                LinearConnectionRouter.fn.init.call(that);
                this.connection = connection;
            },
            routePoints: function (start, end, sourceConnector, targetConnector) {
                var result;
                if (sourceConnector && targetConnector) {
                    result = this._connectorPoints(start, end, sourceConnector, targetConnector);
                } else {
                    result = this._floatingPoints(start, end, sourceConnector);
                }
                return result;
            },
            route: function () {
                var sourceConnector = this.connection._resolvedSourceConnector;
                var targetConnector = this.connection._resolvedTargetConnector;
                var start = this.connection.sourcePoint();
                var end = this.connection.targetPoint();
                var points = this.routePoints(start, end, sourceConnector, targetConnector);
                this.connection.points(points);
            },
            _connectorSides: [
                {
                    name: 'Top',
                    axis: 'y',
                    boundsPoint: 'topLeft',
                    secondarySign: 1
                },
                {
                    name: 'Left',
                    axis: 'x',
                    boundsPoint: 'topLeft',
                    secondarySign: 1
                },
                {
                    name: 'Bottom',
                    axis: 'y',
                    boundsPoint: 'bottomRight',
                    secondarySign: -1
                },
                {
                    name: 'Right',
                    axis: 'x',
                    boundsPoint: 'bottomRight',
                    secondarySign: -1
                }
            ],
            _connectorSide: function (connector, targetPoint) {
                var position = connector.position();
                var shapeBounds = connector.shape.bounds(ROTATED);
                var bounds = {
                    topLeft: shapeBounds.topLeft(),
                    bottomRight: shapeBounds.bottomRight()
                };
                var sides = this._connectorSides;
                var min = util.MAX_NUM;
                var sideDistance;
                var minSide;
                var axis;
                var side;
                for (var idx = 0; idx < sides.length; idx++) {
                    side = sides[idx];
                    axis = side.axis;
                    sideDistance = Math.round(Math.abs(position[axis] - bounds[side.boundsPoint][axis]));
                    if (sideDistance < min) {
                        min = sideDistance;
                        minSide = side;
                    } else if (sideDistance === min && (position[axis] - targetPoint[axis]) * side.secondarySign > (position[minSide.axis] - targetPoint[minSide.axis]) * minSide.secondarySign) {
                        minSide = side;
                    }
                }
                return minSide.name;
            },
            _sameSideDistance: function (connector) {
                var bounds = connector.shape.bounds(ROTATED);
                return Math.min(bounds.width, bounds.height) / this.SAME_SIDE_DISTANCE_RATIO;
            },
            _connectorPoints: function (start, end, sourceConnector, targetConnector) {
                var sourceConnectorSide = this._connectorSide(sourceConnector, end);
                var targetConnectorSide = this._connectorSide(targetConnector, start);
                var deltaX = end.x - start.x;
                var deltaY = end.y - start.y;
                var sameSideDistance = this._sameSideDistance(sourceConnector);
                var result = [];
                var pointX, pointY;
                if (sourceConnectorSide === TOP || sourceConnectorSide == BOTTOM) {
                    if (targetConnectorSide == TOP || targetConnectorSide == BOTTOM) {
                        if (sourceConnectorSide == targetConnectorSide) {
                            if (sourceConnectorSide == TOP) {
                                pointY = Math.min(start.y, end.y) - sameSideDistance;
                            } else {
                                pointY = Math.max(start.y, end.y) + sameSideDistance;
                            }
                            result = [
                                new Point(start.x, pointY),
                                new Point(end.x, pointY)
                            ];
                        } else {
                            result = [
                                new Point(start.x, start.y + deltaY / 2),
                                new Point(end.x, start.y + deltaY / 2)
                            ];
                        }
                    } else {
                        result = [new Point(start.x, end.y)];
                    }
                } else {
                    if (targetConnectorSide == LEFT || targetConnectorSide == RIGHT) {
                        if (sourceConnectorSide == targetConnectorSide) {
                            if (sourceConnectorSide == LEFT) {
                                pointX = Math.min(start.x, end.x) - sameSideDistance;
                            } else {
                                pointX = Math.max(start.x, end.x) + sameSideDistance;
                            }
                            result = [
                                new Point(pointX, start.y),
                                new Point(pointX, end.y)
                            ];
                        } else {
                            result = [
                                new Point(start.x + deltaX / 2, start.y),
                                new Point(start.x + deltaX / 2, start.y + deltaY)
                            ];
                        }
                    } else {
                        result = [new Point(end.x, start.y)];
                    }
                }
                return result;
            },
            _floatingPoints: function (start, end, sourceConnector) {
                var sourceConnectorSide = sourceConnector ? this._connectorSide(sourceConnector, end) : null;
                var cascadeStartHorizontal = this._startHorizontal(start, end, sourceConnectorSide);
                var points = [
                    start,
                    start,
                    end,
                    end
                ];
                var deltaX = end.x - start.x;
                var deltaY = end.y - start.y;
                var length = points.length;
                var shiftX;
                var shiftY;
                for (var idx = 1; idx < length - 1; ++idx) {
                    if (cascadeStartHorizontal) {
                        if (idx % 2 !== 0) {
                            shiftX = deltaX / (length / 2);
                            shiftY = 0;
                        } else {
                            shiftX = 0;
                            shiftY = deltaY / ((length - 1) / 2);
                        }
                    } else {
                        if (idx % 2 !== 0) {
                            shiftX = 0;
                            shiftY = deltaY / (length / 2);
                        } else {
                            shiftX = deltaX / ((length - 1) / 2);
                            shiftY = 0;
                        }
                    }
                    points[idx] = new Point(points[idx - 1].x + shiftX, points[idx - 1].y + shiftY);
                }
                idx--;
                if (cascadeStartHorizontal && idx % 2 !== 0 || !cascadeStartHorizontal && idx % 2 === 0) {
                    points[length - 2] = new Point(points[length - 1].x, points[length - 2].y);
                } else {
                    points[length - 2] = new Point(points[length - 2].x, points[length - 1].y);
                }
                return [
                    points[1],
                    points[2]
                ];
            },
            _startHorizontal: function (start, end, sourceSide) {
                var horizontal;
                if (sourceSide !== null && (sourceSide === RIGHT || sourceSide === LEFT)) {
                    horizontal = true;
                } else {
                    horizontal = Math.abs(start.x - end.x) > Math.abs(start.y - end.y);
                }
                return horizontal;
            }
        });
        var AdornerBase = Class.extend({
            init: function (diagram, options) {
                var that = this;
                that.diagram = diagram;
                that.options = deepExtend({}, that.options, options);
                that.visual = new Group();
                that.diagram._adorners.push(that);
            },
            refresh: function () {
            }
        });
        var ConnectionEditAdorner = AdornerBase.extend({
            init: function (connection, options) {
                var that = this, diagram;
                that.connection = connection;
                diagram = that.connection.diagram;
                that._ts = diagram.toolService;
                AdornerBase.fn.init.call(that, diagram, options);
                var sp = that.connection.sourcePoint();
                var tp = that.connection.targetPoint();
                that.spVisual = new Circle(deepExtend(that.options.handles, { center: sp }));
                that.epVisual = new Circle(deepExtend(that.options.handles, { center: tp }));
                that.visual.append(that.spVisual);
                that.visual.append(that.epVisual);
            },
            options: { handles: {} },
            _getCursor: function () {
                return Cursors.move;
            },
            start: function (p) {
                this.handle = this._hitTest(p);
                this.startPoint = p;
                this._initialSource = this.connection.source();
                this._initialTarget = this.connection.target();
                switch (this.handle) {
                case -1:
                    if (this.connection.targetConnector) {
                        this._ts._connectionManipulation(this.connection, this.connection.targetConnector.shape);
                    }
                    break;
                case 1:
                    if (this.connection.sourceConnector) {
                        this._ts._connectionManipulation(this.connection, this.connection.sourceConnector.shape);
                    }
                    break;
                }
            },
            move: function (handle, p) {
                switch (handle) {
                case -1:
                    this.connection.source(p);
                    break;
                case 1:
                    this.connection.target(p);
                    break;
                default:
                    var delta = p.minus(this.startPoint);
                    this.startPoint = p;
                    if (!this.connection.sourceConnector) {
                        this.connection.source(this.connection.sourcePoint().plus(delta));
                    }
                    if (!this.connection.targetConnector) {
                        this.connection.target(this.connection.targetPoint().plus(delta));
                    }
                    break;
                }
                this.refresh();
                return true;
            },
            stop: function (p) {
                var ts = this.diagram.toolService, item = ts.hoveredItem, target;
                if (ts._hoveredConnector) {
                    target = ts._hoveredConnector._c;
                } else if (item && item instanceof diagram.Shape) {
                    target = item.getConnector(AUTO) || item.getConnector(p);
                } else {
                    target = p;
                }
                if (this.handle === -1) {
                    this.connection.source(target);
                } else if (this.handle === 1) {
                    this.connection.target(target);
                }
                this.handle = undefined;
                this._ts._connectionManipulation();
                return new ConnectionEditUndoUnit(this.connection, this._initialSource, this._initialTarget);
            },
            _hitTest: function (point) {
                var sourcePoint = this.connection.sourcePoint();
                var targetPoint = this.connection.targetPoint();
                var radiusX = this.options.handles.width / 2 + HIT_TEST_DISTANCE;
                var radiusY = this.options.handles.height / 2 + HIT_TEST_DISTANCE;
                var sourcePointDistance = sourcePoint.distanceTo(point);
                var targetPointDistance = targetPoint.distanceTo(point);
                var sourceHandle = new Rect(sourcePoint.x, sourcePoint.y).inflate(radiusX, radiusY).contains(point);
                var targetHandle = new Rect(targetPoint.x, targetPoint.y).inflate(radiusX, radiusY).contains(point);
                var handle = 0;
                if (sourceHandle && (!targetHandle || sourcePointDistance < targetPointDistance)) {
                    handle = -1;
                } else if (targetHandle && (!sourceHandle || targetPointDistance < sourcePointDistance)) {
                    handle = 1;
                }
                return handle;
            },
            refresh: function () {
                this.spVisual.redraw({ center: this.diagram.modelToLayer(this.connection.sourcePoint()) });
                this.epVisual.redraw({ center: this.diagram.modelToLayer(this.connection.targetPoint()) });
            }
        });
        var ConnectorsAdorner = AdornerBase.extend({
            init: function (diagram, options) {
                var that = this;
                AdornerBase.fn.init.call(that, diagram, options);
                that._refreshHandler = function (e) {
                    if (e.item == that.shape) {
                        that.refresh();
                    }
                };
            },
            show: function (shape) {
                var that = this, len, i, ctr;
                that._visible = true;
                that.shape = shape;
                that.diagram.bind(ITEMBOUNDSCHANGE, that._refreshHandler);
                len = shape.connectors.length;
                that.connectors = [];
                that._clearVisual();
                for (i = 0; i < len; i++) {
                    ctr = new ConnectorVisual(shape.connectors[i]);
                    that.connectors.push(ctr);
                    that.visual.append(ctr.visual);
                }
                that.visual.visible(true);
                that.refresh();
            },
            _clearVisual: function () {
                var that = this;
                if (that.diagram._cachedTouchTarget) {
                    that._keepCachedTouchTarget();
                } else {
                    that.visual.clear();
                }
            },
            _keepCachedTouchTarget: function () {
                var that = this, visualChildren = that.visual.children;
                var childrenCount = visualChildren.length;
                var index = inArray(that.diagram._cachedTouchTarget, visualChildren);
                for (var i = childrenCount - 1; i >= 0; i--) {
                    if (i == index) {
                        continue;
                    }
                    that.visual.remove(visualChildren[i]);
                }
            },
            destroy: function () {
                var that = this;
                that.diagram.unbind(ITEMBOUNDSCHANGE, that._refreshHandler);
                that.shape = undefined;
                that._visible = undefined;
                that.visual.visible(false);
            },
            _hitTest: function (p) {
                var ctr, i;
                for (i = 0; i < this.connectors.length; i++) {
                    ctr = this.connectors[i];
                    if (ctr._hitTest(p)) {
                        ctr._hover(true);
                        this.diagram.toolService._hoveredConnector = ctr;
                        break;
                    }
                }
            },
            refresh: function () {
                if (this.shape) {
                    var bounds = this.shape.bounds();
                    bounds = this.diagram.modelToLayer(bounds);
                    this.visual.position(bounds.topLeft());
                    $.each(this.connectors, function () {
                        this.refresh();
                    });
                }
            }
        });
        function hitToOppositeSide(hit, bounds) {
            var result;
            if (hit.x == -1 && hit.y == -1) {
                result = bounds.bottomRight();
            } else if (hit.x == 1 && hit.y == 1) {
                result = bounds.topLeft();
            } else if (hit.x == -1 && hit.y == 1) {
                result = bounds.topRight();
            } else if (hit.x == 1 && hit.y == -1) {
                result = bounds.bottomLeft();
            } else if (hit.x === 0 && hit.y == -1) {
                result = bounds.bottom();
            } else if (hit.x === 0 && hit.y == 1) {
                result = bounds.top();
            } else if (hit.x == 1 && hit.y === 0) {
                result = bounds.left();
            } else if (hit.x == -1 && hit.y === 0) {
                result = bounds.right();
            }
            return result;
        }
        var ResizingAdorner = AdornerBase.extend({
            init: function (diagram, options) {
                var that = this;
                AdornerBase.fn.init.call(that, diagram, options);
                that._manipulating = false;
                that.map = [];
                that.shapes = [];
                that._initSelection();
                that._createHandles();
                that.redraw();
                that.diagram.bind('select', function (e) {
                    that._initialize(e.selected);
                });
                that._refreshHandler = function () {
                    if (!that._internalChange) {
                        that.refreshBounds();
                        that.refresh();
                    }
                };
                that._rotatedHandler = function () {
                    if (that.shapes.length == 1) {
                        that._angle = that.shapes[0].rotate().angle;
                    }
                    that._refreshHandler();
                };
                that.diagram.bind(ITEMBOUNDSCHANGE, that._refreshHandler).bind(ITEMROTATE, that._rotatedHandler);
                that.refreshBounds();
                that.refresh();
            },
            options: {
                handles: {
                    fill: { color: '#fff' },
                    stroke: { color: '#282828' },
                    height: 7,
                    width: 7,
                    hover: {
                        fill: { color: '#282828' },
                        stroke: { color: '#282828' }
                    }
                },
                selectable: {
                    stroke: {
                        color: '#778899',
                        width: 1,
                        dashType: 'dash'
                    },
                    fill: { color: TRANSPARENT }
                },
                offset: 10
            },
            _initSelection: function () {
                var that = this;
                var diagram = that.diagram;
                var selectable = diagram.options.selectable;
                var options = deepExtend({}, that.options.selectable, selectable);
                that.rect = new Rectangle(options);
                that.visual.append(that.rect);
            },
            _resizable: function () {
                return this.options.editable && this.options.editable.resize !== false;
            },
            _handleOptions: function () {
                return (this.options.editable.resize || {}).handles || this.options.handles;
            },
            _createHandles: function () {
                var handles, item, y, x;
                if (this._resizable()) {
                    handles = this._handleOptions();
                    for (x = -1; x <= 1; x++) {
                        for (y = -1; y <= 1; y++) {
                            if (x !== 0 || y !== 0) {
                                item = new Rectangle(handles);
                                item.drawingElement._hover = proxy(this._hover, this);
                                this.map.push({
                                    x: x,
                                    y: y,
                                    visual: item
                                });
                                this.visual.append(item);
                            }
                        }
                    }
                }
            },
            bounds: function (value) {
                if (value) {
                    this._innerBounds = value.clone();
                    this._bounds = this.diagram.modelToLayer(value).inflate(this.options.offset, this.options.offset);
                } else {
                    return this._bounds;
                }
            },
            _hitTest: function (p) {
                var tp = this.diagram.modelToLayer(p), i, hit, handleBounds, handlesCount = this.map.length, handle;
                if (this._angle) {
                    tp = tp.clone().rotate(this._bounds.center(), this._angle);
                }
                if (this._resizable()) {
                    for (i = 0; i < handlesCount; i++) {
                        handle = this.map[i];
                        hit = new Point(handle.x, handle.y);
                        handleBounds = this._getHandleBounds(hit);
                        handleBounds.offset(this._bounds.x, this._bounds.y);
                        if (handleBounds.contains(tp)) {
                            return hit;
                        }
                    }
                }
                if (this._bounds.contains(tp)) {
                    return new Point(0, 0);
                }
            },
            _getHandleBounds: function (p) {
                if (this._resizable()) {
                    var handles = this._handleOptions(), w = handles.width, h = handles.height, r = new Rect(0, 0, w, h);
                    if (p.x < 0) {
                        r.x = -w / 2;
                    } else if (p.x === 0) {
                        r.x = Math.floor(this._bounds.width / 2) - w / 2;
                    } else if (p.x > 0) {
                        r.x = this._bounds.width + 1 - w / 2;
                    }
                    if (p.y < 0) {
                        r.y = -h / 2;
                    } else if (p.y === 0) {
                        r.y = Math.floor(this._bounds.height / 2) - h / 2;
                    } else if (p.y > 0) {
                        r.y = this._bounds.height + 1 - h / 2;
                    }
                    return r;
                }
            },
            _getCursor: function (point) {
                var hit = this._hitTest(point);
                if (hit && hit.x >= -1 && hit.x <= 1 && hit.y >= -1 && hit.y <= 1 && this._resizable()) {
                    var angle = this._angle;
                    if (angle) {
                        angle = 360 - angle;
                        hit.rotate(new Point(0, 0), angle);
                        hit = new Point(Math.round(hit.x), Math.round(hit.y));
                    }
                    if (hit.x == -1 && hit.y == -1) {
                        return 'nw-resize';
                    }
                    if (hit.x == 1 && hit.y == 1) {
                        return 'se-resize';
                    }
                    if (hit.x == -1 && hit.y == 1) {
                        return 'sw-resize';
                    }
                    if (hit.x == 1 && hit.y == -1) {
                        return 'ne-resize';
                    }
                    if (hit.x === 0 && hit.y == -1) {
                        return 'n-resize';
                    }
                    if (hit.x === 0 && hit.y == 1) {
                        return 's-resize';
                    }
                    if (hit.x == 1 && hit.y === 0) {
                        return 'e-resize';
                    }
                    if (hit.x == -1 && hit.y === 0) {
                        return 'w-resize';
                    }
                }
                return this._manipulating ? Cursors.move : Cursors.select;
            },
            _initialize: function () {
                var that = this, i, item, items = that.diagram.select();
                that.shapes = [];
                for (i = 0; i < items.length; i++) {
                    item = items[i];
                    if (item instanceof diagram.Shape) {
                        that.shapes.push(item);
                        item._rotationOffset = new Point();
                    }
                }
                that._angle = that.shapes.length == 1 ? that.shapes[0].rotate().angle : 0;
                that._startAngle = that._angle;
                that._rotates();
                that._positions();
                that.refreshBounds();
                that.refresh();
                that.redraw();
            },
            _rotates: function () {
                var that = this, i, shape;
                that.initialRotates = [];
                for (i = 0; i < that.shapes.length; i++) {
                    shape = that.shapes[i];
                    that.initialRotates.push(shape.rotate().angle);
                }
            },
            _positions: function () {
                var that = this, i, shape;
                that.initialStates = [];
                for (i = 0; i < that.shapes.length; i++) {
                    shape = that.shapes[i];
                    that.initialStates.push(shape.bounds());
                }
            },
            _hover: function (value, element) {
                if (this._resizable()) {
                    var handleOptions = this._handleOptions(), hover = handleOptions.hover, stroke = handleOptions.stroke, fill = handleOptions.fill;
                    if (value && Utils.isDefined(hover.stroke)) {
                        stroke = deepExtend({}, stroke, hover.stroke);
                    }
                    if (value && Utils.isDefined(hover.fill)) {
                        fill = hover.fill;
                    }
                    element.stroke(stroke.color, stroke.width, stroke.opacity);
                    element.fill(fill.color, fill.opacity);
                }
            },
            start: function (p) {
                this._sp = p;
                this._cp = p;
                this._lp = p;
                this._manipulating = true;
                this._internalChange = true;
                this.shapeStates = [];
                for (var i = 0; i < this.shapes.length; i++) {
                    var shape = this.shapes[i];
                    this.shapeStates.push(shape.bounds());
                }
            },
            redraw: function () {
                var i, handle, visibleHandles = this._resizable();
                for (i = 0; i < this.map.length; i++) {
                    handle = this.map[i];
                    handle.visual.visible(visibleHandles);
                }
            },
            angle: function (value) {
                if (defined(value)) {
                    this._angle = value;
                }
                return this._angle;
            },
            rotate: function () {
                var center = this._innerBounds.center();
                var currentAngle = this.angle();
                this._internalChange = true;
                for (var i = 0; i < this.shapes.length; i++) {
                    var shape = this.shapes[i];
                    currentAngle = (currentAngle + this.initialRotates[i] - this._startAngle) % 360;
                    shape.rotate(currentAngle, center);
                }
                this.refresh();
            },
            move: function (handle, p) {
                var delta, dragging, dtl = new Point(), dbr = new Point(), bounds, center, shape, i, angle, newBounds, changed = 0, staticPoint, scaleX, scaleY;
                if (handle.y === -2 && handle.x === -1) {
                    center = this._innerBounds.center();
                    this._angle = this._truncateAngle(Utils.findAngle(center, p));
                    for (i = 0; i < this.shapes.length; i++) {
                        shape = this.shapes[i];
                        angle = (this._angle + this.initialRotates[i] - this._startAngle) % 360;
                        shape.rotate(angle, center);
                        if (shape.hasOwnProperty('layout')) {
                            shape.layout(shape);
                        }
                        this._rotating = true;
                    }
                    this.refresh();
                } else {
                    if (this.shouldSnap()) {
                        var thr = this._truncateDistance(p.minus(this._lp));
                        if (thr.x === 0 && thr.y === 0) {
                            this._cp = p;
                            return;
                        }
                        delta = thr;
                        this._lp = new Point(this._lp.x + thr.x, this._lp.y + thr.y);
                    } else {
                        delta = p.minus(this._cp);
                    }
                    if (this.isDragHandle(handle)) {
                        dbr = dtl = delta;
                        dragging = true;
                    } else {
                        if (this._angle) {
                            delta.rotate(new Point(0, 0), this._angle);
                        }
                        if (handle.x == -1) {
                            dtl.x = delta.x;
                        } else if (handle.x == 1) {
                            dbr.x = delta.x;
                        }
                        if (handle.y == -1) {
                            dtl.y = delta.y;
                        } else if (handle.y == 1) {
                            dbr.y = delta.y;
                        }
                    }
                    if (!dragging) {
                        staticPoint = hitToOppositeSide(handle, this._innerBounds);
                        scaleX = (this._innerBounds.width + delta.x * handle.x) / this._innerBounds.width;
                        scaleY = (this._innerBounds.height + delta.y * handle.y) / this._innerBounds.height;
                    }
                    for (i = 0; i < this.shapes.length; i++) {
                        shape = this.shapes[i];
                        bounds = shape.bounds();
                        if (dragging) {
                            if (!canDrag(shape)) {
                                continue;
                            }
                            newBounds = this._displaceBounds(bounds, dtl, dbr, dragging);
                        } else {
                            newBounds = bounds.clone();
                            newBounds.scale(scaleX, scaleY, staticPoint, this._innerBounds.center(), shape.rotate().angle);
                            var newCenter = newBounds.center();
                            newCenter.rotate(bounds.center(), -this._angle);
                            newBounds = new Rect(newCenter.x - newBounds.width / 2, newCenter.y - newBounds.height / 2, newBounds.width, newBounds.height);
                        }
                        if (newBounds.width >= shape.options.minWidth && newBounds.height >= shape.options.minHeight) {
                            var oldBounds = bounds;
                            shape.bounds(newBounds);
                            if (shape.hasOwnProperty('layout')) {
                                shape.layout(shape, oldBounds, newBounds);
                            }
                            if (oldBounds.width !== newBounds.width || oldBounds.height !== newBounds.height) {
                                shape.rotate(shape.rotate().angle);
                            }
                            changed += 1;
                        }
                    }
                    if (changed) {
                        if (changed == i) {
                            newBounds = this._displaceBounds(this._innerBounds, dtl, dbr, dragging);
                            this.bounds(newBounds);
                        } else {
                            this.refreshBounds();
                        }
                        this.refresh();
                    }
                    this._positions();
                }
                this._cp = p;
            },
            isDragHandle: function (handle) {
                return handle.x === 0 && handle.y === 0;
            },
            cancel: function () {
                var shapes = this.shapes;
                var states = this.shapeStates;
                for (var idx = 0; idx < shapes.length; idx++) {
                    shapes[idx].bounds(states[idx]);
                }
                this.refreshBounds();
                this.refresh();
                this._manipulating = undefined;
                this._internalChange = undefined;
                this._rotating = undefined;
            },
            _truncatePositionToGuides: function (bounds) {
                if (this.diagram.ruler) {
                    return this.diagram.ruler.truncatePositionToGuides(bounds);
                }
                return bounds;
            },
            _truncateSizeToGuides: function (bounds) {
                if (this.diagram.ruler) {
                    return this.diagram.ruler.truncateSizeToGuides(bounds);
                }
                return bounds;
            },
            _truncateAngle: function (a) {
                var snap = this.snapOptions();
                var snapAngle = Math.max(snap.angle || DEFAULT_SNAP_ANGLE, MIN_SNAP_ANGLE);
                return snap ? Math.floor(a % 360 / snapAngle) * snapAngle : a % 360;
            },
            _truncateDistance: function (d) {
                if (d instanceof diagram.Point) {
                    return new diagram.Point(this._truncateDistance(d.x), this._truncateDistance(d.y));
                } else {
                    var snap = this.snapOptions() || {};
                    var snapSize = Math.max(snap.size || DEFAULT_SNAP_SIZE, MIN_SNAP_SIZE);
                    return snap ? Math.floor(d / snapSize) * snapSize : d;
                }
            },
            snapOptions: function () {
                var editable = this.diagram.options.editable;
                var snap = ((editable || {}).drag || {}).snap || {};
                return snap;
            },
            shouldSnap: function () {
                var editable = this.diagram.options.editable;
                var drag = (editable || {}).drag;
                var snap = (drag || {}).snap;
                return editable !== false && drag !== false && snap !== false;
            },
            _displaceBounds: function (bounds, dtl, dbr, dragging) {
                var tl = bounds.topLeft().plus(dtl), br = bounds.bottomRight().plus(dbr), newBounds = Rect.fromPoints(tl, br), newCenter;
                if (!dragging) {
                    newCenter = newBounds.center();
                    newCenter.rotate(bounds.center(), -this._angle);
                    newBounds = new Rect(newCenter.x - newBounds.width / 2, newCenter.y - newBounds.height / 2, newBounds.width, newBounds.height);
                }
                return newBounds;
            },
            stop: function () {
                var unit, i, shape;
                if (this._cp != this._sp) {
                    if (this._rotating) {
                        unit = new RotateUnit(this, this.shapes, this.initialRotates);
                        this._rotating = false;
                    } else if (this._diffStates()) {
                        if (this.diagram.ruler) {
                            for (i = 0; i < this.shapes.length; i++) {
                                shape = this.shapes[i];
                                var bounds = shape.bounds();
                                bounds = this._truncateSizeToGuides(this._truncatePositionToGuides(bounds));
                                shape.bounds(bounds);
                                this.refreshBounds();
                                this.refresh();
                            }
                        }
                        for (i = 0; i < this.shapes.length; i++) {
                            shape = this.shapes[i];
                            shape.updateModel();
                        }
                        unit = new TransformUnit(this.shapes, this.shapeStates, this);
                        this.diagram._syncShapeChanges();
                    }
                }
                this._manipulating = undefined;
                this._internalChange = undefined;
                this._rotating = undefined;
                return unit;
            },
            _diffStates: function () {
                var shapes = this.shapes;
                var states = this.shapeStates;
                for (var idx = 0; idx < shapes.length; idx++) {
                    if (!shapes[idx].bounds().equals(states[idx])) {
                        return true;
                    }
                }
                return false;
            },
            refreshBounds: function () {
                var bounds = this.shapes.length == 1 ? this.shapes[0].bounds().clone() : this.diagram.boundingBox(this.shapes, true);
                this.bounds(bounds);
            },
            refresh: function () {
                var that = this, b, bounds;
                if (this.shapes.length > 0) {
                    bounds = this.bounds();
                    this.visual.visible(true);
                    this.visual.position(bounds.topLeft());
                    $.each(this.map, function () {
                        b = that._getHandleBounds(new Point(this.x, this.y));
                        this.visual.position(b.topLeft());
                    });
                    this.visual.position(bounds.topLeft());
                    var center = new Point(bounds.width / 2, bounds.height / 2);
                    this.visual.rotate(this._angle, center);
                    this.rect.redraw({
                        width: bounds.width,
                        height: bounds.height
                    });
                    if (this.rotationThumb) {
                        var thumb = this.options.editable.rotate.thumb;
                        this._rotationThumbBounds = new Rect(bounds.center().x, bounds.y + thumb.y, 0, 0).inflate(thumb.width);
                        this.rotationThumb.redraw({ x: bounds.width / 2 - thumb.width / 2 });
                    }
                } else {
                    this.visual.visible(false);
                }
            }
        });
        var Selector = Class.extend({
            init: function (diagram) {
                var selectable = diagram.options.selectable;
                this.options = deepExtend({}, this.options, selectable);
                this.visual = new Rectangle(this.options);
                this.diagram = diagram;
            },
            options: {
                stroke: {
                    color: '#778899',
                    width: 1,
                    dashType: 'dash'
                },
                fill: { color: TRANSPARENT }
            },
            start: function (p) {
                this._sp = this._ep = p;
                this.refresh();
                this.diagram._adorn(this, true);
            },
            end: function () {
                this._sp = this._ep = undefined;
                this.diagram._adorn(this, false);
            },
            bounds: function (value) {
                if (value) {
                    this._bounds = value;
                }
                return this._bounds;
            },
            move: function (p) {
                this._ep = p;
                this.refresh();
            },
            refresh: function () {
                if (this._sp) {
                    var visualBounds = Rect.fromPoints(this.diagram.modelToLayer(this._sp), this.diagram.modelToLayer(this._ep));
                    this.bounds(Rect.fromPoints(this._sp, this._ep));
                    this.visual.position(visualBounds.topLeft());
                    this.visual.redraw({
                        height: visualBounds.height + 1,
                        width: visualBounds.width + 1
                    });
                }
            }
        });
        var ConnectorVisual = Class.extend({
            init: function (connector) {
                this.options = deepExtend({}, connector.options);
                this._c = connector;
                this.visual = new Circle(this.options);
                this.refresh();
            },
            _hover: function (value) {
                var options = this.options, hover = options.hover, stroke = options.stroke, fill = options.fill;
                if (value && Utils.isDefined(hover.stroke)) {
                    stroke = deepExtend({}, stroke, hover.stroke);
                }
                if (value && Utils.isDefined(hover.fill)) {
                    fill = hover.fill;
                }
                this.visual.redraw({
                    stroke: stroke,
                    fill: fill
                });
            },
            refresh: function () {
                var p = this._c.shape.diagram.modelToView(this._c.position()), relative = p.minus(this._c.shape.bounds('transformed').topLeft()), value = new Rect(p.x, p.y, 0, 0);
                value.inflate(this.options.width / 2, this.options.height / 2);
                this._visualBounds = value;
                this.visual.redraw({ center: new Point(relative.x, relative.y) });
            },
            _hitTest: function (p) {
                var tp = this._c.shape.diagram.modelToView(p);
                return this._visualBounds.contains(tp);
            }
        });
        function canDrag(element) {
            var editable = element.options.editable;
            return editable && editable.drag !== false;
        }
        function hitTestShapeConnectors(shape, point) {
            var connector, position, rect;
            for (var idx = 0; idx < shape.connectors.length; idx++) {
                connector = shape.connectors[idx];
                position = connector.position();
                rect = new Rect(position.x, position.y);
                rect.inflate(HIT_TEST_DISTANCE, HIT_TEST_DISTANCE);
                if (rect.contains(point)) {
                    return connector;
                }
            }
        }
        function noMeta(meta) {
            return meta.ctrlKey === false && meta.altKey === false && meta.shiftKey === false;
        }
        deepExtend(diagram, {
            CompositeUnit: CompositeUnit,
            TransformUnit: TransformUnit,
            PanUndoUnit: PanUndoUnit,
            AddShapeUnit: AddShapeUnit,
            AddConnectionUnit: AddConnectionUnit,
            DeleteShapeUnit: DeleteShapeUnit,
            DeleteConnectionUnit: DeleteConnectionUnit,
            ConnectionEditAdorner: ConnectionEditAdorner,
            ConnectionTool: ConnectionTool,
            ConnectorVisual: ConnectorVisual,
            UndoRedoService: UndoRedoService,
            ResizingAdorner: ResizingAdorner,
            Selector: Selector,
            ToolService: ToolService,
            ConnectorsAdorner: ConnectorsAdorner,
            LayoutUndoUnit: LayoutUndoUnit,
            ConnectionEditUnit: ConnectionEditUnit,
            ToFrontUnit: ToFrontUnit,
            ToBackUnit: ToBackUnit,
            ConnectionRouterBase: ConnectionRouterBase,
            PolylineRouter: PolylineRouter,
            CascadingRouter: CascadingRouter,
            SelectionTool: SelectionTool,
            ScrollerTool: ScrollerTool,
            PointerTool: PointerTool,
            ConnectionEditTool: ConnectionEditTool,
            RotateUnit: RotateUnit
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/diagram/layout', ['dataviz/diagram/math'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, diagram = kendo.dataviz.diagram, Graph = diagram.Graph, Node = diagram.Node, Link = diagram.Link, deepExtend = kendo.deepExtend, Size = diagram.Size, Rect = diagram.Rect, Dictionary = diagram.Dictionary, Set = diagram.Set, HyperTree = diagram.Graph, Utils = diagram.Utils, Point = diagram.Point, EPSILON = 0.000001, DEG_TO_RAD = Math.PI / 180, contains = Utils.contains, grep = $.grep;
        var LayoutBase = kendo.Class.extend({
            defaultOptions: {
                type: 'Tree',
                subtype: 'Down',
                roots: null,
                animate: false,
                limitToView: false,
                friction: 0.9,
                nodeDistance: 50,
                iterations: 300,
                horizontalSeparation: 90,
                verticalSeparation: 50,
                underneathVerticalTopOffset: 15,
                underneathHorizontalOffset: 15,
                underneathVerticalSeparation: 15,
                grid: {
                    width: 1500,
                    offsetX: 50,
                    offsetY: 50,
                    componentSpacingX: 20,
                    componentSpacingY: 20
                },
                layerSeparation: 50,
                layeredIterations: 2,
                startRadialAngle: 0,
                endRadialAngle: 360,
                radialSeparation: 150,
                radialFirstLevelSeparation: 200,
                keepComponentsInOneRadialLayout: false,
                ignoreContainers: true,
                layoutContainerChildren: false,
                ignoreInvisible: true,
                animateTransitions: false
            },
            init: function () {
            },
            gridLayoutComponents: function (components) {
                if (!components) {
                    throw 'No components supplied.';
                }
                Utils.forEach(components, function (c) {
                    c.calcBounds();
                });
                components.sort(function (a, b) {
                    return b.bounds.width - a.bounds.width;
                });
                var maxWidth = this.options.grid.width, offsetX = this.options.grid.componentSpacingX, offsetY = this.options.grid.componentSpacingY, height = 0, startX = this.options.grid.offsetX, startY = this.options.grid.offsetY, x = startX, y = startY, i, resultLinkSet = [], resultNodeSet = [];
                while (components.length > 0) {
                    if (x >= maxWidth) {
                        x = startX;
                        y += height + offsetY;
                        height = 0;
                    }
                    var component = components.pop();
                    this.moveToOffset(component, new Point(x, y));
                    for (i = 0; i < component.nodes.length; i++) {
                        resultNodeSet.push(component.nodes[i]);
                    }
                    for (i = 0; i < component.links.length; i++) {
                        resultLinkSet.push(component.links[i]);
                    }
                    var boundingRect = component.bounds;
                    var currentHeight = boundingRect.height;
                    if (currentHeight <= 0 || isNaN(currentHeight)) {
                        currentHeight = 0;
                    }
                    var currentWidth = boundingRect.width;
                    if (currentWidth <= 0 || isNaN(currentWidth)) {
                        currentWidth = 0;
                    }
                    if (currentHeight >= height) {
                        height = currentHeight;
                    }
                    x += currentWidth + offsetX;
                }
                return {
                    nodes: resultNodeSet,
                    links: resultLinkSet
                };
            },
            moveToOffset: function (component, p) {
                var i, j, bounds = component.bounds, deltax = p.x - bounds.x, deltay = p.y - bounds.y;
                for (i = 0; i < component.nodes.length; i++) {
                    var node = component.nodes[i];
                    var nodeBounds = node.bounds();
                    if (nodeBounds.width === 0 && nodeBounds.height === 0 && nodeBounds.x === 0 && nodeBounds.y === 0) {
                        nodeBounds = new Rect(0, 0, 0, 0);
                    }
                    nodeBounds.x += deltax;
                    nodeBounds.y += deltay;
                    node.bounds(nodeBounds);
                }
                for (i = 0; i < component.links.length; i++) {
                    var link = component.links[i];
                    if (link.points) {
                        var newpoints = [];
                        var points = link.points;
                        for (j = 0; j < points.length; j++) {
                            var pt = points[j];
                            pt.x += deltax;
                            pt.y += deltay;
                            newpoints.push(pt);
                        }
                        link.points = newpoints;
                    }
                }
                this.currentHorizontalOffset += bounds.width + this.options.grid.offsetX;
                return new Point(deltax, deltay);
            },
            transferOptions: function (options) {
                this.options = kendo.deepExtend({}, this.defaultOptions);
                if (Utils.isUndefined(options)) {
                    return;
                }
                this.options = kendo.deepExtend(this.options, options || {});
            }
        });
        var DiagramToHyperTreeAdapter = kendo.Class.extend({
            init: function (diagram) {
                this.nodeMap = new Dictionary();
                this.shapeMap = new Dictionary();
                this.nodes = [];
                this.edges = [];
                this.edgeMap = new Dictionary();
                this.finalNodes = [];
                this.finalLinks = [];
                this.ignoredConnections = [];
                this.ignoredShapes = [];
                this.hyperMap = new Dictionary();
                this.hyperTree = new Graph();
                this.finalGraph = null;
                this.diagram = diagram;
            },
            convert: function (options) {
                if (Utils.isUndefined(this.diagram)) {
                    throw 'No diagram to convert.';
                }
                this.options = kendo.deepExtend({
                    ignoreInvisible: true,
                    ignoreContainers: true,
                    layoutContainerChildren: false
                }, options || {});
                this.clear();
                this._renormalizeShapes();
                this._renormalizeConnections();
                this.finalNodes = new Dictionary(this.nodes);
                this.finalLinks = new Dictionary(this.edges);
                this.finalGraph = new Graph();
                this.finalNodes.forEach(function (n) {
                    this.finalGraph.addNode(n);
                }, this);
                this.finalLinks.forEach(function (l) {
                    this.finalGraph.addExistingLink(l);
                }, this);
                return this.finalGraph;
            },
            mapConnection: function (connection) {
                return this.edgeMap.get(connection.id);
            },
            mapShape: function (shape) {
                return this.nodeMap.get(shape.id);
            },
            getEdge: function (a, b) {
                return Utils.first(a.links, function (link) {
                    return link.getComplement(a) === b;
                });
            },
            clear: function () {
                this.finalGraph = null;
                this.hyperTree = !this.options.ignoreContainers && this.options.layoutContainerChildren ? new HyperTree() : null;
                this.hyperMap = !this.options.ignoreContainers && this.options.layoutContainerChildren ? new Dictionary() : null;
                this.nodeMap = new Dictionary();
                this.shapeMap = new Dictionary();
                this.nodes = [];
                this.edges = [];
                this.edgeMap = new Dictionary();
                this.ignoredConnections = [];
                this.ignoredShapes = [];
                this.finalNodes = [];
                this.finalLinks = [];
            },
            listToRoot: function (containerGraph) {
                var list = [];
                var s = containerGraph.container;
                if (!s) {
                    return list;
                }
                list.push(s);
                while (s.parentContainer) {
                    s = s.parentContainer;
                    list.push(s);
                }
                list.reverse();
                return list;
            },
            firstNonIgnorableContainer: function (shape) {
                if (shape.isContainer && !this._isIgnorableItem(shape)) {
                    return shape;
                }
                return !shape.parentContainer ? null : this.firstNonIgnorableContainer(shape.parentContainer);
            },
            isContainerConnection: function (a, b) {
                if (a.isContainer && this.isDescendantOf(a, b)) {
                    return true;
                }
                return b.isContainer && this.isDescendantOf(b, a);
            },
            isDescendantOf: function (scope, a) {
                if (!scope.isContainer) {
                    throw 'Expecting a container.';
                }
                if (scope === a) {
                    return false;
                }
                if (contains(scope.children, a)) {
                    return true;
                }
                var containers = [];
                for (var i = 0, len = scope.children.length; i < len; i++) {
                    var c = scope.children[i];
                    if (c.isContainer && this.isDescendantOf(c, a)) {
                        containers.push(c);
                    }
                }
                return containers.length > 0;
            },
            isIgnorableItem: function (shape) {
                if (this.options.ignoreInvisible) {
                    if (shape.isCollapsed && this._isVisible(shape)) {
                        return false;
                    }
                    if (!shape.isCollapsed && this._isVisible(shape)) {
                        return false;
                    }
                    return true;
                } else {
                    return shape.isCollapsed && !this._isTop(shape);
                }
            },
            isShapeMapped: function (shape) {
                return shape.isCollapsed && !this._isVisible(shape) && !this._isTop(shape);
            },
            leastCommonAncestor: function (a, b) {
                if (!a) {
                    throw 'Parameter should not be null.';
                }
                if (!b) {
                    throw 'Parameter should not be null.';
                }
                if (!this.hyperTree) {
                    throw 'No hypertree available.';
                }
                var al = this.listToRoot(a);
                var bl = this.listToRoot(b);
                var found = null;
                if (Utils.isEmpty(al) || Utils.isEmpty(bl)) {
                    return this.hyperTree.root.data;
                }
                var xa = al[0];
                var xb = bl[0];
                var i = 0;
                while (xa === xb) {
                    found = al[i];
                    i++;
                    if (i >= al.length || i >= bl.length) {
                        break;
                    }
                    xa = al[i];
                    xb = bl[i];
                }
                if (!found) {
                    return this.hyperTree.root.data;
                } else {
                    return grep(this.hyperTree.nodes, function (n) {
                        return n.data.container === found;
                    });
                }
            },
            _isTop: function (item) {
                return !item.parentContainer;
            },
            _isVisible: function (shape) {
                if (!shape.visible()) {
                    return false;
                }
                return !shape.parentContainer ? shape.visible() : this._isVisible(shape.parentContainer);
            },
            _isCollapsed: function (shape) {
                if (shape.isContainer && shape.isCollapsed) {
                    return true;
                }
                return shape.parentContainer && this._isCollapsed(shape.parentContainer);
            },
            _renormalizeShapes: function () {
                if (this.options.ignoreContainers) {
                    for (var i = 0, len = this.diagram.shapes.length; i < len; i++) {
                        var shape = this.diagram.shapes[i];
                        if (this.options.ignoreInvisible && !this._isVisible(shape) || shape.isContainer) {
                            this.ignoredShapes.push(shape);
                            continue;
                        }
                        var node = new Node(shape.id, shape);
                        node.isVirtual = false;
                        this.nodeMap.add(shape.id, node);
                        this.nodes.push(node);
                    }
                } else {
                    throw 'Containers are not supported yet, but stay tuned.';
                }
            },
            _renormalizeConnections: function () {
                if (this.diagram.connections.length === 0) {
                    return;
                }
                for (var i = 0, len = this.diagram.connections.length; i < len; i++) {
                    var conn = this.diagram.connections[i];
                    if (this.isIgnorableItem(conn)) {
                        this.ignoredConnections.push(conn);
                        continue;
                    }
                    var source = !conn.sourceConnector ? null : conn.sourceConnector.shape;
                    var sink = !conn.targetConnector ? null : conn.targetConnector.shape;
                    if (!source || !sink) {
                        this.ignoredConnections.push(conn);
                        continue;
                    }
                    if (contains(this.ignoredShapes, source) && !this.shapeMap.containsKey(source)) {
                        this.ignoredConnections.push(conn);
                        continue;
                    }
                    if (contains(this.ignoredShapes, sink) && !this.shapeMap.containsKey(sink)) {
                        this.ignoredConnections.push(conn);
                        continue;
                    }
                    if (this.shapeMap.containsKey(source)) {
                        source = this.shapeMap[source];
                    }
                    if (this.shapeMap.containsKey(sink)) {
                        sink = this.shapeMap[sink];
                    }
                    var sourceNode = this.mapShape(source);
                    var sinkNode = this.mapShape(sink);
                    if (sourceNode === sinkNode || this.areConnectedAlready(sourceNode, sinkNode)) {
                        this.ignoredConnections.push(conn);
                        continue;
                    }
                    if (sourceNode === null || sinkNode === null) {
                        throw 'A shape was not mapped to a node.';
                    }
                    if (this.options.ignoreContainers) {
                        if (sourceNode.isVirtual || sinkNode.isVirtual) {
                            this.ignoredConnections.push(conn);
                            continue;
                        }
                        var newEdge = new Link(sourceNode, sinkNode, conn.id, conn);
                        this.edgeMap.add(conn.id, newEdge);
                        this.edges.push(newEdge);
                    } else {
                        throw 'Containers are not supported yet, but stay tuned.';
                    }
                }
            },
            areConnectedAlready: function (n, m) {
                return Utils.any(this.edges, function (l) {
                    return l.source === n && l.target === m || l.source === m && l.target === n;
                });
            }
        });
        var SpringLayout = LayoutBase.extend({
            init: function (diagram) {
                var that = this;
                LayoutBase.fn.init.call(that);
                if (Utils.isUndefined(diagram)) {
                    throw 'Diagram is not specified.';
                }
                this.diagram = diagram;
            },
            layout: function (options) {
                this.transferOptions(options);
                var adapter = new DiagramToHyperTreeAdapter(this.diagram);
                var graph = adapter.convert(options);
                if (graph.isEmpty()) {
                    return;
                }
                var components = graph.getConnectedComponents();
                if (Utils.isEmpty(components)) {
                    return;
                }
                for (var i = 0; i < components.length; i++) {
                    var component = components[i];
                    this.layoutGraph(component, options);
                }
                var finalNodeSet = this.gridLayoutComponents(components);
                return new diagram.LayoutState(this.diagram, finalNodeSet);
            },
            layoutGraph: function (graph, options) {
                if (Utils.isDefined(options)) {
                    this.transferOptions(options);
                }
                this.graph = graph;
                var initialTemperature = this.options.nodeDistance * 9;
                this.temperature = initialTemperature;
                var guessBounds = this._expectedBounds();
                this.width = guessBounds.width;
                this.height = guessBounds.height;
                for (var step = 0; step < this.options.iterations; step++) {
                    this.refineStage = step >= this.options.iterations * 5 / 6;
                    this.tick();
                    this.temperature = this.refineStage ? initialTemperature / 30 : initialTemperature * (1 - step / (2 * this.options.iterations));
                }
            },
            tick: function () {
                var i;
                for (i = 0; i < this.graph.nodes.length; i++) {
                    this._repulsion(this.graph.nodes[i]);
                }
                for (i = 0; i < this.graph.links.length; i++) {
                    this._attraction(this.graph.links[i]);
                }
                for (i = 0; i < this.graph.nodes.length; i++) {
                    var node = this.graph.nodes[i];
                    var offset = Math.sqrt(node.dx * node.dx + node.dy * node.dy);
                    if (offset === 0) {
                        return;
                    }
                    node.x += Math.min(offset, this.temperature) * node.dx / offset;
                    node.y += Math.min(offset, this.temperature) * node.dy / offset;
                    if (this.options.limitToView) {
                        node.x = Math.min(this.width, Math.max(node.width / 2, node.x));
                        node.y = Math.min(this.height, Math.max(node.height / 2, node.y));
                    }
                }
            },
            _shake: function (node) {
                var rho = Math.random() * this.options.nodeDistance / 4;
                var alpha = Math.random() * 2 * Math.PI;
                node.x += rho * Math.cos(alpha);
                node.y -= rho * Math.sin(alpha);
            },
            _InverseSquareForce: function (d, n, m) {
                var force;
                if (!this.refineStage) {
                    force = Math.pow(d, 2) / Math.pow(this.options.nodeDistance, 2);
                } else {
                    var deltax = n.x - m.x;
                    var deltay = n.y - m.y;
                    var wn = n.width / 2;
                    var hn = n.height / 2;
                    var wm = m.width / 2;
                    var hm = m.height / 2;
                    force = Math.pow(deltax, 2) / Math.pow(wn + wm + this.options.nodeDistance, 2) + Math.pow(deltay, 2) / Math.pow(hn + hm + this.options.nodeDistance, 2);
                }
                return force * 4 / 3;
            },
            _SquareForce: function (d, n, m) {
                return 1 / this._InverseSquareForce(d, n, m);
            },
            _repulsion: function (n) {
                n.dx = 0;
                n.dy = 0;
                Utils.forEach(this.graph.nodes, function (m) {
                    if (m === n) {
                        return;
                    }
                    while (n.x === m.x && n.y === m.y) {
                        this._shake(m);
                    }
                    var vx = n.x - m.x;
                    var vy = n.y - m.y;
                    var distance = Math.sqrt(vx * vx + vy * vy);
                    var r = this._SquareForce(distance, n, m) * 2;
                    n.dx += vx / distance * r;
                    n.dy += vy / distance * r;
                }, this);
            },
            _attraction: function (link) {
                var t = link.target;
                var s = link.source;
                if (s === t) {
                    return;
                }
                while (s.x === t.x && s.y === t.y) {
                    this._shake(t);
                }
                var vx = s.x - t.x;
                var vy = s.y - t.y;
                var distance = Math.sqrt(vx * vx + vy * vy);
                var a = this._InverseSquareForce(distance, s, t) * 5;
                var dx = vx / distance * a;
                var dy = vy / distance * a;
                t.dx += dx;
                t.dy += dy;
                s.dx -= dx;
                s.dy -= dy;
            },
            _expectedBounds: function () {
                var size, N = this.graph.nodes.length, ratio = 1.5, multiplier = 4;
                if (N === 0) {
                    return size;
                }
                size = Utils.fold(this.graph.nodes, function (s, node) {
                    var area = node.width * node.height;
                    if (area > 0) {
                        s += Math.sqrt(area);
                        return s;
                    }
                    return 0;
                }, 0, this);
                var av = size / N;
                var squareSize = av * Math.ceil(Math.sqrt(N));
                var width = squareSize * Math.sqrt(ratio);
                var height = squareSize / Math.sqrt(ratio);
                return {
                    width: width * multiplier,
                    height: height * multiplier
                };
            }
        });
        var TreeLayoutProcessor = kendo.Class.extend({
            init: function (options) {
                this.center = null;
                this.options = options;
            },
            layout: function (treeGraph, root) {
                this.graph = treeGraph;
                if (!this.graph.nodes || this.graph.nodes.length === 0) {
                    return;
                }
                if (!contains(this.graph.nodes, root)) {
                    throw 'The given root is not in the graph.';
                }
                this.center = root;
                this.graph.cacheRelationships();
                this.layoutSwitch();
            },
            layoutLeft: function (left) {
                this.setChildrenDirection(this.center, 'Left', false);
                this.setChildrenLayout(this.center, 'Default', false);
                var h = 0, w = 0, y, i, node;
                for (i = 0; i < left.length; i++) {
                    node = left[i];
                    node.TreeDirection = 'Left';
                    var s = this.measure(node, Size.Empty);
                    w = Math.max(w, s.Width);
                    h += s.height + this.options.verticalSeparation;
                }
                h -= this.options.verticalSeparation;
                var x = this.center.x - this.options.horizontalSeparation;
                y = this.center.y + (this.center.height - h) / 2;
                for (i = 0; i < left.length; i++) {
                    node = left[i];
                    var p = new Point(x - node.Size.width, y);
                    this.arrange(node, p);
                    y += node.Size.height + this.options.verticalSeparation;
                }
            },
            layoutRight: function (right) {
                this.setChildrenDirection(this.center, 'Right', false);
                this.setChildrenLayout(this.center, 'Default', false);
                var h = 0, w = 0, y, i, node;
                for (i = 0; i < right.length; i++) {
                    node = right[i];
                    node.TreeDirection = 'Right';
                    var s = this.measure(node, Size.Empty);
                    w = Math.max(w, s.Width);
                    h += s.height + this.options.verticalSeparation;
                }
                h -= this.options.verticalSeparation;
                var x = this.center.x + this.options.horizontalSeparation + this.center.width;
                y = this.center.y + (this.center.height - h) / 2;
                for (i = 0; i < right.length; i++) {
                    node = right[i];
                    var p = new Point(x, y);
                    this.arrange(node, p);
                    y += node.Size.height + this.options.verticalSeparation;
                }
            },
            layoutUp: function (up) {
                this.setChildrenDirection(this.center, 'Up', false);
                this.setChildrenLayout(this.center, 'Default', false);
                var w = 0, y, node, i;
                for (i = 0; i < up.length; i++) {
                    node = up[i];
                    node.TreeDirection = 'Up';
                    var s = this.measure(node, Size.Empty);
                    w += s.width + this.options.horizontalSeparation;
                }
                w -= this.options.horizontalSeparation;
                var x = this.center.x + this.center.width / 2 - w / 2;
                for (i = 0; i < up.length; i++) {
                    node = up[i];
                    y = this.center.y - this.options.verticalSeparation - node.Size.height;
                    var p = new Point(x, y);
                    this.arrange(node, p);
                    x += node.Size.width + this.options.horizontalSeparation;
                }
            },
            layoutDown: function (down) {
                var node, i;
                this.setChildrenDirection(this.center, 'Down', false);
                this.setChildrenLayout(this.center, 'Default', false);
                var w = 0, y;
                for (i = 0; i < down.length; i++) {
                    node = down[i];
                    node.treeDirection = 'Down';
                    var s = this.measure(node, Size.Empty);
                    w += s.width + this.options.horizontalSeparation;
                }
                w -= this.options.horizontalSeparation;
                var x = this.center.x + this.center.width / 2 - w / 2;
                y = this.center.y + this.options.verticalSeparation + this.center.height;
                for (i = 0; i < down.length; i++) {
                    node = down[i];
                    var p = new Point(x, y);
                    this.arrange(node, p);
                    x += node.Size.width + this.options.horizontalSeparation;
                }
            },
            layoutRadialTree: function () {
                this.setChildrenDirection(this.center, 'Radial', false);
                this.setChildrenLayout(this.center, 'Default', false);
                this.previousRoot = null;
                var startAngle = this.options.startRadialAngle * DEG_TO_RAD;
                var endAngle = this.options.endRadialAngle * DEG_TO_RAD;
                if (endAngle <= startAngle) {
                    throw 'Final angle should not be less than the start angle.';
                }
                this.maxDepth = 0;
                this.origin = new Point(this.center.x, this.center.y);
                this.calculateAngularWidth(this.center, 0);
                if (this.maxDepth > 0) {
                    this.radialLayout(this.center, this.options.radialFirstLevelSeparation, startAngle, endAngle);
                }
                this.center.Angle = endAngle - startAngle;
            },
            tipOverTree: function (down, startFromLevel) {
                if (Utils.isUndefined(startFromLevel)) {
                    startFromLevel = 0;
                }
                this.setChildrenDirection(this.center, 'Down', false);
                this.setChildrenLayout(this.center, 'Default', false);
                this.setChildrenLayout(this.center, 'Underneath', false, startFromLevel);
                var w = 0, y, node, i;
                for (i = 0; i < down.length; i++) {
                    node = down[i];
                    node.TreeDirection = 'Down';
                    var s = this.measure(node, Size.Empty);
                    w += s.width + this.options.horizontalSeparation;
                }
                w -= this.options.horizontalSeparation;
                w -= down[down.length - 1].width;
                w += down[down.length - 1].associatedShape.bounds().width;
                var x = this.center.x + this.center.width / 2 - w / 2;
                y = this.center.y + this.options.verticalSeparation + this.center.height;
                for (i = 0; i < down.length; i++) {
                    node = down[i];
                    var p = new Point(x, y);
                    this.arrange(node, p);
                    x += node.Size.width + this.options.horizontalSeparation;
                }
            },
            calculateAngularWidth: function (n, d) {
                if (d > this.maxDepth) {
                    this.maxDepth = d;
                }
                var aw = 0, w = 1000, h = 1000, diameter = d === 0 ? 0 : Math.sqrt(w * w + h * h) / d;
                if (n.children.length > 0) {
                    for (var i = 0, len = n.children.length; i < len; i++) {
                        var child = n.children[i];
                        aw += this.calculateAngularWidth(child, d + 1);
                    }
                    aw = Math.max(diameter, aw);
                } else {
                    aw = diameter;
                }
                n.sectorAngle = aw;
                return aw;
            },
            sortChildren: function (n) {
                var basevalue = 0, i;
                if (n.parents.length > 1) {
                    throw 'Node is not part of a tree.';
                }
                var p = n.parents[0];
                if (p) {
                    var pl = new Point(p.x, p.y);
                    var nl = new Point(n.x, n.y);
                    basevalue = this.normalizeAngle(Math.atan2(pl.y - nl.y, pl.x - nl.x));
                }
                var count = n.children.length;
                if (count === 0) {
                    return null;
                }
                var angle = [];
                var idx = [];
                for (i = 0; i < count; ++i) {
                    var c = n.children[i];
                    var l = new Point(c.x, c.y);
                    idx[i] = i;
                    angle[i] = this.normalizeAngle(-basevalue + Math.atan2(l.y - l.y, l.x - l.x));
                }
                Utils.bisort(angle, idx);
                var col = [];
                var children = n.children;
                for (i = 0; i < count; ++i) {
                    col.push(children[idx[i]]);
                }
                return col;
            },
            normalizeAngle: function (angle) {
                while (angle > Math.PI * 2) {
                    angle -= 2 * Math.PI;
                }
                while (angle < 0) {
                    angle += Math.PI * 2;
                }
                return angle;
            },
            radialLayout: function (node, radius, startAngle, endAngle) {
                var deltaTheta = endAngle - startAngle;
                var deltaThetaHalf = deltaTheta / 2;
                var parentSector = node.sectorAngle;
                var fraction = 0;
                var sorted = this.sortChildren(node);
                for (var i = 0, len = sorted.length; i < len; i++) {
                    var childNode = sorted[i];
                    var cp = childNode;
                    var childAngleFraction = cp.sectorAngle / parentSector;
                    if (childNode.children.length > 0) {
                        this.radialLayout(childNode, radius + this.options.radialSeparation, startAngle + fraction * deltaTheta, startAngle + (fraction + childAngleFraction) * deltaTheta);
                    }
                    this.setPolarLocation(childNode, radius, startAngle + fraction * deltaTheta + childAngleFraction * deltaThetaHalf);
                    cp.angle = childAngleFraction * deltaTheta;
                    fraction += childAngleFraction;
                }
            },
            setPolarLocation: function (node, radius, angle) {
                node.x = this.origin.x + radius * Math.cos(angle);
                node.y = this.origin.y + radius * Math.sin(angle);
                node.BoundingRectangle = new Rect(node.x, node.y, node.width, node.height);
            },
            setChildrenDirection: function (node, direction, includeStart) {
                var rootDirection = node.treeDirection;
                this.graph.depthFirstTraversal(node, function (n) {
                    n.treeDirection = direction;
                });
                if (!includeStart) {
                    node.treeDirection = rootDirection;
                }
            },
            setChildrenLayout: function (node, layout, includeStart, startFromLevel) {
                if (Utils.isUndefined(startFromLevel)) {
                    startFromLevel = 0;
                }
                var rootLayout = node.childrenLayout;
                if (startFromLevel > 0) {
                    this.graph.assignLevels(node);
                    this.graph.depthFirstTraversal(node, function (s) {
                        if (s.level >= startFromLevel + 1) {
                            s.childrenLayout = layout;
                        }
                    });
                } else {
                    this.graph.depthFirstTraversal(node, function (s) {
                        s.childrenLayout = layout;
                    });
                    if (!includeStart) {
                        node.childrenLayout = rootLayout;
                    }
                }
            },
            measure: function (node, givenSize) {
                var w = 0, h = 0, s;
                var result = new Size(0, 0);
                if (!node) {
                    throw '';
                }
                var b = node.associatedShape.bounds();
                var shapeWidth = b.width;
                var shapeHeight = b.height;
                if (node.parents.length !== 1) {
                    throw 'Node not in a spanning tree.';
                }
                var parent = node.parents[0];
                if (node.treeDirection === 'Undefined') {
                    node.treeDirection = parent.treeDirection;
                }
                if (Utils.isEmpty(node.children)) {
                    result = new Size(Math.abs(shapeWidth) < EPSILON ? 50 : shapeWidth, Math.abs(shapeHeight) < EPSILON ? 25 : shapeHeight);
                } else if (node.children.length === 1) {
                    switch (node.treeDirection) {
                    case 'Radial':
                        s = this.measure(node.children[0], givenSize);
                        w = shapeWidth + this.options.radialSeparation * Math.cos(node.AngleToParent) + s.width;
                        h = shapeHeight + Math.abs(this.options.radialSeparation * Math.sin(node.AngleToParent)) + s.height;
                        break;
                    case 'Left':
                    case 'Right':
                        switch (node.childrenLayout) {
                        case 'TopAlignedWithParent':
                            break;
                        case 'BottomAlignedWithParent':
                            break;
                        case 'Underneath':
                            s = this.measure(node.children[0], givenSize);
                            w = shapeWidth + s.width + this.options.underneathHorizontalOffset;
                            h = shapeHeight + this.options.underneathVerticalTopOffset + s.height;
                            break;
                        case 'Default':
                            s = this.measure(node.children[0], givenSize);
                            w = shapeWidth + this.options.horizontalSeparation + s.width;
                            h = Math.max(shapeHeight, s.height);
                            break;
                        default:
                            throw 'Unhandled TreeDirection in the Radial layout measuring.';
                        }
                        break;
                    case 'Up':
                    case 'Down':
                        switch (node.childrenLayout) {
                        case 'TopAlignedWithParent':
                        case 'BottomAlignedWithParent':
                            break;
                        case 'Underneath':
                            s = this.measure(node.children[0], givenSize);
                            w = Math.max(shapeWidth, s.width + this.options.underneathHorizontalOffset);
                            h = shapeHeight + this.options.underneathVerticalTopOffset + s.height;
                            break;
                        case 'Default':
                            s = this.measure(node.children[0], givenSize);
                            h = shapeHeight + this.options.verticalSeparation + s.height;
                            w = Math.max(shapeWidth, s.width);
                            break;
                        default:
                            throw 'Unhandled TreeDirection in the Down layout measuring.';
                        }
                        break;
                    default:
                        throw 'Unhandled TreeDirection in the layout measuring.';
                    }
                    result = new Size(w, h);
                } else {
                    var i, childNode;
                    switch (node.treeDirection) {
                    case 'Left':
                    case 'Right':
                        switch (node.childrenLayout) {
                        case 'TopAlignedWithParent':
                        case 'BottomAlignedWithParent':
                            break;
                        case 'Underneath':
                            w = shapeWidth;
                            h = shapeHeight + this.options.underneathVerticalTopOffset;
                            for (i = 0; i < node.children.length; i++) {
                                childNode = node.children[i];
                                s = this.measure(childNode, givenSize);
                                w = Math.max(w, s.width + this.options.underneathHorizontalOffset);
                                h += s.height + this.options.underneathVerticalSeparation;
                            }
                            h -= this.options.underneathVerticalSeparation;
                            break;
                        case 'Default':
                            w = shapeWidth;
                            h = 0;
                            for (i = 0; i < node.children.length; i++) {
                                childNode = node.children[i];
                                s = this.measure(childNode, givenSize);
                                w = Math.max(w, shapeWidth + this.options.horizontalSeparation + s.width);
                                h += s.height + this.options.verticalSeparation;
                            }
                            h -= this.options.verticalSeparation;
                            break;
                        default:
                            throw 'Unhandled TreeDirection in the Right layout measuring.';
                        }
                        break;
                    case 'Up':
                    case 'Down':
                        switch (node.childrenLayout) {
                        case 'TopAlignedWithParent':
                        case 'BottomAlignedWithParent':
                            break;
                        case 'Underneath':
                            w = shapeWidth;
                            h = shapeHeight + this.options.underneathVerticalTopOffset;
                            for (i = 0; i < node.children.length; i++) {
                                childNode = node.children[i];
                                s = this.measure(childNode, givenSize);
                                w = Math.max(w, s.width + this.options.underneathHorizontalOffset);
                                h += s.height + this.options.underneathVerticalSeparation;
                            }
                            h -= this.options.underneathVerticalSeparation;
                            break;
                        case 'Default':
                            w = 0;
                            h = 0;
                            for (i = 0; i < node.children.length; i++) {
                                childNode = node.children[i];
                                s = this.measure(childNode, givenSize);
                                w += s.width + this.options.horizontalSeparation;
                                h = Math.max(h, s.height + this.options.verticalSeparation + shapeHeight);
                            }
                            w -= this.options.horizontalSeparation;
                            break;
                        default:
                            throw 'Unhandled TreeDirection in the Down layout measuring.';
                        }
                        break;
                    default:
                        throw 'Unhandled TreeDirection in the layout measuring.';
                    }
                    result = new Size(w, h);
                }
                node.SectorAngle = Math.sqrt(w * w / 4 + h * h / 4);
                node.Size = result;
                return result;
            },
            arrange: function (n, p) {
                var i, pp, child, node, childrenwidth, b = n.associatedShape.bounds();
                var shapeWidth = b.width;
                var shapeHeight = b.height;
                if (Utils.isEmpty(n.children)) {
                    n.x = p.x;
                    n.y = p.y;
                    n.BoundingRectangle = new Rect(p.x, p.y, shapeWidth, shapeHeight);
                } else {
                    var x, y;
                    var selfLocation;
                    switch (n.treeDirection) {
                    case 'Left':
                        switch (n.childrenLayout) {
                        case 'TopAlignedWithParent':
                        case 'BottomAlignedWithParent':
                            break;
                        case 'Underneath':
                            selfLocation = p;
                            n.x = selfLocation.x;
                            n.y = selfLocation.y;
                            n.BoundingRectangle = new Rect(n.x, n.y, n.width, n.height);
                            y = p.y + shapeHeight + this.options.underneathVerticalTopOffset;
                            for (i = 0; i < node.children.length; i++) {
                                node = node.children[i];
                                x = selfLocation.x - node.associatedShape.width - this.options.underneathHorizontalOffset;
                                pp = new Point(x, y);
                                this.arrange(node, pp);
                                y += node.Size.height + this.options.underneathVerticalSeparation;
                            }
                            break;
                        case 'Default':
                            selfLocation = new Point(p.x + n.Size.width - shapeWidth, p.y + (n.Size.height - shapeHeight) / 2);
                            n.x = selfLocation.x;
                            n.y = selfLocation.y;
                            n.BoundingRectangle = new Rect(n.x, n.y, n.width, n.height);
                            x = selfLocation.x - this.options.horizontalSeparation;
                            y = p.y;
                            for (i = 0; i < n.children.length; i++) {
                                node = n.children[i];
                                pp = new Point(x - node.Size.width, y);
                                this.arrange(node, pp);
                                y += node.Size.height + this.options.verticalSeparation;
                            }
                            break;
                        default:
                            throw 'Unsupported TreeDirection';
                        }
                        break;
                    case 'Right':
                        switch (n.childrenLayout) {
                        case 'TopAlignedWithParent':
                        case 'BottomAlignedWithParent':
                            break;
                        case 'Underneath':
                            selfLocation = p;
                            n.x = selfLocation.x;
                            n.y = selfLocation.y;
                            n.BoundingRectangle = new Rect(n.x, n.y, n.width, n.height);
                            x = p.x + shapeWidth + this.options.underneathHorizontalOffset;
                            y = p.y + shapeHeight + this.options.underneathVerticalTopOffset;
                            for (i = 0; i < n.children.length; i++) {
                                node = n.children[i];
                                pp = new Point(x, y);
                                this.arrange(node, pp);
                                y += node.Size.height + this.options.underneathVerticalSeparation;
                            }
                            break;
                        case 'Default':
                            selfLocation = new Point(p.x, p.y + (n.Size.height - shapeHeight) / 2);
                            n.x = selfLocation.x;
                            n.y = selfLocation.y;
                            n.BoundingRectangle = new Rect(n.x, n.y, n.width, n.height);
                            x = p.x + shapeWidth + this.options.horizontalSeparation;
                            y = p.y;
                            for (i = 0; i < n.children.length; i++) {
                                node = n.children[i];
                                pp = new Point(x, y);
                                this.arrange(node, pp);
                                y += node.Size.height + this.options.verticalSeparation;
                            }
                            break;
                        default:
                            throw 'Unsupported TreeDirection';
                        }
                        break;
                    case 'Up':
                        selfLocation = new Point(p.x + (n.Size.width - shapeWidth) / 2, p.y + n.Size.height - shapeHeight);
                        n.x = selfLocation.x;
                        n.y = selfLocation.y;
                        n.BoundingRectangle = new Rect(n.x, n.y, n.width, n.height);
                        if (Math.abs(selfLocation.x - p.x) < EPSILON) {
                            childrenwidth = 0;
                            for (i = 0; i < n.children.length; i++) {
                                child = n.children[i];
                                childrenwidth += child.Size.width + this.options.horizontalSeparation;
                            }
                            childrenwidth -= this.options.horizontalSeparation;
                            x = p.x + (shapeWidth - childrenwidth) / 2;
                        } else {
                            x = p.x;
                        }
                        for (i = 0; i < n.children.length; i++) {
                            node = n.children[i];
                            y = selfLocation.y - this.options.verticalSeparation - node.Size.height;
                            pp = new Point(x, y);
                            this.arrange(node, pp);
                            x += node.Size.width + this.options.horizontalSeparation;
                        }
                        break;
                    case 'Down':
                        switch (n.childrenLayout) {
                        case 'TopAlignedWithParent':
                        case 'BottomAlignedWithParent':
                            break;
                        case 'Underneath':
                            selfLocation = p;
                            n.x = selfLocation.x;
                            n.y = selfLocation.y;
                            n.BoundingRectangle = new Rect(n.x, n.y, n.width, n.height);
                            x = p.x + this.options.underneathHorizontalOffset;
                            y = p.y + shapeHeight + this.options.underneathVerticalTopOffset;
                            for (i = 0; i < n.children.length; i++) {
                                node = n.children[i];
                                pp = new Point(x, y);
                                this.arrange(node, pp);
                                y += node.Size.height + this.options.underneathVerticalSeparation;
                            }
                            break;
                        case 'Default':
                            selfLocation = new Point(p.x + (n.Size.width - shapeWidth) / 2, p.y);
                            n.x = selfLocation.x;
                            n.y = selfLocation.y;
                            n.BoundingRectangle = new Rect(n.x, n.y, n.width, n.height);
                            if (Math.abs(selfLocation.x - p.x) < EPSILON) {
                                childrenwidth = 0;
                                for (i = 0; i < n.children.length; i++) {
                                    child = n.children[i];
                                    childrenwidth += child.Size.width + this.options.horizontalSeparation;
                                }
                                childrenwidth -= this.options.horizontalSeparation;
                                x = p.x + (shapeWidth - childrenwidth) / 2;
                            } else {
                                x = p.x;
                            }
                            for (i = 0; i < n.children.length; i++) {
                                node = n.children[i];
                                y = selfLocation.y + this.options.verticalSeparation + shapeHeight;
                                pp = new Point(x, y);
                                this.arrange(node, pp);
                                x += node.Size.width + this.options.horizontalSeparation;
                            }
                            break;
                        default:
                            throw 'Unsupported TreeDirection';
                        }
                        break;
                    case 'None':
                        break;
                    default:
                        throw 'Unsupported TreeDirection';
                    }
                }
            },
            layoutSwitch: function () {
                if (!this.center) {
                    return;
                }
                if (Utils.isEmpty(this.center.children)) {
                    return;
                }
                var type = this.options.subtype;
                if (Utils.isUndefined(type)) {
                    type = 'Down';
                }
                var single, male, female, leftcount;
                var children = this.center.children;
                switch (type.toLowerCase()) {
                case 'radial':
                case 'radialtree':
                    this.layoutRadialTree();
                    break;
                case 'mindmaphorizontal':
                case 'mindmap':
                    single = this.center.children;
                    if (this.center.children.length === 1) {
                        this.layoutRight(single);
                    } else {
                        leftcount = children.length / 2;
                        male = grep(this.center.children, function (n) {
                            return Utils.indexOf(children, n) < leftcount;
                        });
                        female = grep(this.center.children, function (n) {
                            return Utils.indexOf(children, n) >= leftcount;
                        });
                        this.layoutLeft(male);
                        this.layoutRight(female);
                    }
                    break;
                case 'mindmapvertical':
                    single = this.center.children;
                    if (this.center.children.length === 1) {
                        this.layoutDown(single);
                    } else {
                        leftcount = children.length / 2;
                        male = grep(this.center.children, function (n) {
                            return Utils.indexOf(children, n) < leftcount;
                        });
                        female = grep(this.center.children, function (n) {
                            return Utils.indexOf(children, n) >= leftcount;
                        });
                        this.layoutUp(male);
                        this.layoutDown(female);
                    }
                    break;
                case 'right':
                    this.layoutRight(this.center.children);
                    break;
                case 'left':
                    this.layoutLeft(this.center.children);
                    break;
                case 'up':
                case 'bottom':
                    this.layoutUp(this.center.children);
                    break;
                case 'down':
                case 'top':
                    this.layoutDown(this.center.children);
                    break;
                case 'tipover':
                case 'tipovertree':
                    if (this.options.tipOverTreeStartLevel < 0) {
                        throw 'The tip-over level should be a positive integer.';
                    }
                    this.tipOverTree(this.center.children, this.options.tipOverTreeStartLevel);
                    break;
                case 'undefined':
                case 'none':
                    break;
                }
            }
        });
        var TreeLayout = LayoutBase.extend({
            init: function (diagram) {
                var that = this;
                LayoutBase.fn.init.call(that);
                if (Utils.isUndefined(diagram)) {
                    throw 'No diagram specified.';
                }
                this.diagram = diagram;
            },
            layout: function (options) {
                this.transferOptions(options);
                var adapter = new DiagramToHyperTreeAdapter(this.diagram);
                this.graph = adapter.convert();
                var finalNodeSet = this.layoutComponents();
                return new diagram.LayoutState(this.diagram, finalNodeSet);
            },
            layoutComponents: function () {
                if (this.graph.isEmpty()) {
                    return;
                }
                var components = this.graph.getConnectedComponents();
                if (Utils.isEmpty(components)) {
                    return;
                }
                var layout = new TreeLayoutProcessor(this.options);
                var trees = [];
                for (var i = 0; i < components.length; i++) {
                    var component = components[i];
                    var treeGraph = this.getTree(component);
                    if (!treeGraph) {
                        throw 'Failed to find a spanning tree for the component.';
                    }
                    var root = treeGraph.root;
                    var tree = treeGraph.tree;
                    layout.layout(tree, root);
                    trees.push(tree);
                }
                return this.gridLayoutComponents(trees);
            },
            getTree: function (graph) {
                var root = null;
                if (this.options.roots && this.options.roots.length > 0) {
                    for (var i = 0, len = graph.nodes.length; i < len; i++) {
                        var node = graph.nodes[i];
                        for (var j = 0; j < this.options.roots.length; j++) {
                            var givenRootShape = this.options.roots[j];
                            if (givenRootShape === node.associatedShape) {
                                root = node;
                                break;
                            }
                        }
                    }
                }
                if (!root) {
                    root = graph.root();
                    if (!root) {
                        throw 'Unable to find a root for the tree.';
                    }
                }
                return this.getTreeForRoot(graph, root);
            },
            getTreeForRoot: function (graph, root) {
                var tree = graph.getSpanningTree(root);
                if (Utils.isUndefined(tree) || tree.isEmpty()) {
                    return null;
                }
                return {
                    tree: tree,
                    root: tree.root
                };
            }
        });
        var LayeredLayout = LayoutBase.extend({
            init: function (diagram) {
                var that = this;
                LayoutBase.fn.init.call(that);
                if (Utils.isUndefined(diagram)) {
                    throw 'Diagram is not specified.';
                }
                this.diagram = diagram;
            },
            layout: function (options) {
                this.transferOptions(options);
                var adapter = new DiagramToHyperTreeAdapter(this.diagram);
                var graph = adapter.convert(options);
                if (graph.isEmpty()) {
                    return;
                }
                var components = graph.getConnectedComponents();
                if (Utils.isEmpty(components)) {
                    return;
                }
                for (var i = 0; i < components.length; i++) {
                    var component = components[i];
                    this.layoutGraph(component, options);
                }
                var finalNodeSet = this.gridLayoutComponents(components);
                return new diagram.LayoutState(this.diagram, finalNodeSet);
            },
            _initRuntimeProperties: function () {
                for (var k = 0; k < this.graph.nodes.length; k++) {
                    var node = this.graph.nodes[k];
                    node.layer = -1;
                    node.downstreamLinkCount = 0;
                    node.upstreamLinkCount = 0;
                    node.isVirtual = false;
                    node.uBaryCenter = 0;
                    node.dBaryCenter = 0;
                    node.upstreamPriority = 0;
                    node.downstreamPriority = 0;
                    node.gridPosition = 0;
                }
            },
            _prepare: function (graph) {
                var current = [], i, l, link;
                var layerMap = new Dictionary();
                var layerCount = 0;
                var targetLayer, next, target;
                Utils.forEach(graph.nodes, function (node) {
                    if (node.incoming.length === 0) {
                        layerMap.set(node, 0);
                        current.push(node);
                    }
                });
                while (current.length > 0) {
                    next = current.shift();
                    for (i = 0; i < next.outgoing.length; i++) {
                        link = next.outgoing[i];
                        target = link.target;
                        if (layerMap.containsKey(target)) {
                            targetLayer = Math.max(layerMap.get(next) + 1, layerMap.get(target));
                        } else {
                            targetLayer = layerMap.get(next) + 1;
                        }
                        layerMap.set(target, targetLayer);
                        if (targetLayer > layerCount) {
                            layerCount = targetLayer;
                        }
                        if (!contains(current, target)) {
                            current.push(target);
                        }
                    }
                }
                var sortedNodes = layerMap.keys();
                sortedNodes.sort(function (o1, o2) {
                    var o1layer = layerMap.get(o1);
                    var o2layer = layerMap.get(o2);
                    return Utils.sign(o2layer - o1layer);
                });
                for (var n = 0; n < sortedNodes.length; ++n) {
                    var node = sortedNodes[n];
                    var minLayer = Number.MAX_VALUE;
                    if (node.outgoing.length === 0) {
                        continue;
                    }
                    for (l = 0; l < node.outgoing.length; ++l) {
                        link = node.outgoing[l];
                        minLayer = Math.min(minLayer, layerMap.get(link.target));
                    }
                    if (minLayer > 1) {
                        layerMap.set(node, minLayer - 1);
                    }
                }
                this.layers = [];
                var layer;
                for (i = 0; i < layerCount + 1; i++) {
                    layer = [];
                    layer.linksTo = {};
                    this.layers.push(layer);
                }
                layerMap.forEach(function (node, layer) {
                    node.layer = layer;
                    this.layers[layer].push(node);
                }, this);
                for (l = 0; l < this.layers.length; l++) {
                    layer = this.layers[l];
                    for (i = 0; i < layer.length; i++) {
                        layer[i].gridPosition = i;
                    }
                }
            },
            layoutGraph: function (graph, options) {
                if (Utils.isUndefined(graph)) {
                    throw 'No graph given or graph analysis of the diagram failed.';
                }
                if (Utils.isDefined(options)) {
                    this.transferOptions(options);
                }
                this.graph = graph;
                graph.setItemIndices();
                var reversedEdges = graph.makeAcyclic();
                this._initRuntimeProperties();
                this._prepare(graph, options);
                this._dummify();
                this._optimizeCrossings();
                this._swapPairs();
                this.arrangeNodes();
                this._moveThingsAround();
                this._dedummify();
                Utils.forEach(reversedEdges, function (e) {
                    if (e.points) {
                        e.points.reverse();
                    }
                });
            },
            setMinDist: function (m, n, minDist) {
                var l = m.layer;
                var i = m.layerIndex;
                this.minDistances[l][i] = minDist;
            },
            getMinDist: function (m, n) {
                var dist = 0, i1 = m.layerIndex, i2 = n.layerIndex, l = m.layer, min = Math.min(i1, i2), max = Math.max(i1, i2);
                for (var k = min; k < max; ++k) {
                    dist += this.minDistances[l][k];
                }
                return dist;
            },
            placeLeftToRight: function (leftClasses) {
                var leftPos = new Dictionary(), n, node;
                for (var c = 0; c < this.layers.length; ++c) {
                    var classNodes = leftClasses[c];
                    if (!classNodes) {
                        continue;
                    }
                    for (n = 0; n < classNodes.length; n++) {
                        node = classNodes[n];
                        if (!leftPos.containsKey(node)) {
                            this.placeLeft(node, leftPos, c);
                        }
                    }
                    var d = Number.POSITIVE_INFINITY;
                    for (n = 0; n < classNodes.length; n++) {
                        node = classNodes[n];
                        var rightSibling = this.rightSibling(node);
                        if (rightSibling && this.nodeLeftClass.get(rightSibling) !== c) {
                            d = Math.min(d, leftPos.get(rightSibling) - leftPos.get(node) - this.getMinDist(node, rightSibling));
                        }
                    }
                    if (d === Number.POSITIVE_INFINITY) {
                        var D = [];
                        for (n = 0; n < classNodes.length; n++) {
                            node = classNodes[n];
                            var neighbors = [];
                            Utils.addRange(neighbors, this.upNodes.get(node));
                            Utils.addRange(neighbors, this.downNodes.get(node));
                            for (var e = 0; e < neighbors.length; e++) {
                                var neighbor = neighbors[e];
                                if (this.nodeLeftClass.get(neighbor) < c) {
                                    D.push(leftPos.get(neighbor) - leftPos.get(node));
                                }
                            }
                        }
                        D.sort();
                        if (D.length === 0) {
                            d = 0;
                        } else if (D.length % 2 === 1) {
                            d = D[this.intDiv(D.length, 2)];
                        } else {
                            d = (D[this.intDiv(D.length, 2) - 1] + D[this.intDiv(D.length, 2)]) / 2;
                        }
                    }
                    for (n = 0; n < classNodes.length; n++) {
                        node = classNodes[n];
                        leftPos.set(node, leftPos.get(node) + d);
                    }
                }
                return leftPos;
            },
            placeRightToLeft: function (rightClasses) {
                var rightPos = new Dictionary(), n, node;
                for (var c = 0; c < this.layers.length; ++c) {
                    var classNodes = rightClasses[c];
                    if (!classNodes) {
                        continue;
                    }
                    for (n = 0; n < classNodes.length; n++) {
                        node = classNodes[n];
                        if (!rightPos.containsKey(node)) {
                            this.placeRight(node, rightPos, c);
                        }
                    }
                    var d = Number.NEGATIVE_INFINITY;
                    for (n = 0; n < classNodes.length; n++) {
                        node = classNodes[n];
                        var leftSibling = this.leftSibling(node);
                        if (leftSibling && this.nodeRightClass.get(leftSibling) !== c) {
                            d = Math.max(d, rightPos.get(leftSibling) - rightPos.get(node) + this.getMinDist(leftSibling, node));
                        }
                    }
                    if (d === Number.NEGATIVE_INFINITY) {
                        var D = [];
                        for (n = 0; n < classNodes.length; n++) {
                            node = classNodes[n];
                            var neighbors = [];
                            Utils.addRange(neighbors, this.upNodes.get(node));
                            Utils.addRange(neighbors, this.downNodes.get(node));
                            for (var e = 0; e < neighbors.length; e++) {
                                var neighbor = neighbors[e];
                                if (this.nodeRightClass.get(neighbor) < c) {
                                    D.push(rightPos.get(node) - rightPos.get(neighbor));
                                }
                            }
                        }
                        D.sort();
                        if (D.length === 0) {
                            d = 0;
                        } else if (D.length % 2 === 1) {
                            d = D[this.intDiv(D.length, 2)];
                        } else {
                            d = (D[this.intDiv(D.length, 2) - 1] + D[this.intDiv(D.length, 2)]) / 2;
                        }
                    }
                    for (n = 0; n < classNodes.length; n++) {
                        node = classNodes[n];
                        rightPos.set(node, rightPos.get(node) + d);
                    }
                }
                return rightPos;
            },
            _getLeftWing: function () {
                var leftWing = { value: null };
                var result = this.computeClasses(leftWing, 1);
                this.nodeLeftClass = leftWing.value;
                return result;
            },
            _getRightWing: function () {
                var rightWing = { value: null };
                var result = this.computeClasses(rightWing, -1);
                this.nodeRightClass = rightWing.value;
                return result;
            },
            computeClasses: function (wingPair, d) {
                var currentWing = 0, wing = wingPair.value = new Dictionary();
                for (var l = 0; l < this.layers.length; ++l) {
                    currentWing = l;
                    var layer = this.layers[l];
                    for (var n = d === 1 ? 0 : layer.length - 1; 0 <= n && n < layer.length; n += d) {
                        var node = layer[n];
                        if (!wing.containsKey(node)) {
                            wing.set(node, currentWing);
                            if (node.isVirtual) {
                                var ndsinl = this._nodesInLink(node);
                                for (var kk = 0; kk < ndsinl.length; kk++) {
                                    var vnode = ndsinl[kk];
                                    wing.set(vnode, currentWing);
                                }
                            }
                        } else {
                            currentWing = wing.get(node);
                        }
                    }
                }
                var wings = [];
                for (var i = 0; i < this.layers.length; i++) {
                    wings.push(null);
                }
                wing.forEach(function (node, classIndex) {
                    if (wings[classIndex] === null) {
                        wings[classIndex] = [];
                    }
                    wings[classIndex].push(node);
                });
                return wings;
            },
            _isVerticalLayout: function () {
                return this.options.subtype.toLowerCase() === 'up' || this.options.subtype.toLowerCase() === 'down' || this.options.subtype.toLowerCase() === 'vertical';
            },
            _isHorizontalLayout: function () {
                return this.options.subtype.toLowerCase() === 'right' || this.options.subtype.toLowerCase() === 'left' || this.options.subtype.toLowerCase() === 'horizontal';
            },
            _isIncreasingLayout: function () {
                return this.options.subtype.toLowerCase() === 'right' || this.options.subtype.toLowerCase() === 'down';
            },
            _moveThingsAround: function () {
                var i, l, node, layer, n, w;
                for (l = 0; l < this.layers.length; ++l) {
                    layer = this.layers[l];
                    layer.sort(this._gridPositionComparer);
                }
                this.minDistances = [];
                for (l = 0; l < this.layers.length; ++l) {
                    layer = this.layers[l];
                    this.minDistances[l] = [];
                    for (n = 0; n < layer.length; ++n) {
                        node = layer[n];
                        node.layerIndex = n;
                        this.minDistances[l][n] = this.options.nodeDistance;
                        if (n < layer.length - 1) {
                            if (this._isVerticalLayout()) {
                                this.minDistances[l][n] += (node.width + layer[n + 1].width) / 2;
                            } else {
                                this.minDistances[l][n] += (node.height + layer[n + 1].height) / 2;
                            }
                        }
                    }
                }
                this.downNodes = new Dictionary();
                this.upNodes = new Dictionary();
                Utils.forEach(this.graph.nodes, function (node) {
                    this.downNodes.set(node, []);
                    this.upNodes.set(node, []);
                }, this);
                Utils.forEach(this.graph.links, function (link) {
                    var origin = link.source;
                    var dest = link.target;
                    var down = null, up = null;
                    if (origin.layer > dest.layer) {
                        down = link.source;
                        up = link.target;
                    } else {
                        up = link.source;
                        down = link.target;
                    }
                    this.downNodes.get(up).push(down);
                    this.upNodes.get(down).push(up);
                }, this);
                this.downNodes.forEachValue(function (list) {
                    list.sort(this._gridPositionComparer);
                }, this);
                this.upNodes.forEachValue(function (list) {
                    list.sort(this._gridPositionComparer);
                }, this);
                for (l = 0; l < this.layers.length - 1; ++l) {
                    layer = this.layers[l];
                    for (w = 0; w < layer.length - 1; w++) {
                        var currentNode = layer[w];
                        if (!currentNode.isVirtual) {
                            continue;
                        }
                        var currDown = this.downNodes.get(currentNode)[0];
                        if (!currDown.isVirtual) {
                            continue;
                        }
                        for (n = w + 1; n < layer.length; ++n) {
                            node = layer[n];
                            if (!node.isVirtual) {
                                continue;
                            }
                            var downNode = this.downNodes.get(node)[0];
                            if (!downNode.isVirtual) {
                                continue;
                            }
                            if (currDown.gridPosition > downNode.gridPosition) {
                                var pos = currDown.gridPosition;
                                currDown.gridPosition = downNode.gridPosition;
                                downNode.gridPosition = pos;
                                var i1 = currDown.layerIndex;
                                var i2 = downNode.layerIndex;
                                this.layers[l + 1][i1] = downNode;
                                this.layers[l + 1][i2] = currDown;
                                currDown.layerIndex = i2;
                                downNode.layerIndex = i1;
                            }
                        }
                    }
                }
                var leftClasses = this._getLeftWing();
                var rightClasses = this._getRightWing();
                var leftPos = this.placeLeftToRight(leftClasses);
                var rightPos = this.placeRightToLeft(rightClasses);
                var x = new Dictionary();
                Utils.forEach(this.graph.nodes, function (node) {
                    x.set(node, (leftPos.get(node) + rightPos.get(node)) / 2);
                });
                var order = new Dictionary();
                var placed = new Dictionary();
                for (l = 0; l < this.layers.length; ++l) {
                    layer = this.layers[l];
                    var sequenceStart = -1, sequenceEnd = -1;
                    for (n = 0; n < layer.length; ++n) {
                        node = layer[n];
                        order.set(node, 0);
                        placed.set(node, false);
                        if (node.isVirtual) {
                            if (sequenceStart === -1) {
                                sequenceStart = n;
                            } else if (sequenceStart === n - 1) {
                                sequenceStart = n;
                            } else {
                                sequenceEnd = n;
                                order.set(layer[sequenceStart], 0);
                                if (x.get(node) - x.get(layer[sequenceStart]) === this.getMinDist(layer[sequenceStart], node)) {
                                    placed.set(layer[sequenceStart], true);
                                } else {
                                    placed.set(layer[sequenceStart], false);
                                }
                                sequenceStart = n;
                            }
                        }
                    }
                }
                var directions = [
                    1,
                    -1
                ];
                Utils.forEach(directions, function (d) {
                    var start = d === 1 ? 0 : this.layers.length - 1;
                    for (var l = start; 0 <= l && l < this.layers.length; l += d) {
                        var layer = this.layers[l];
                        var virtualStartIndex = this._firstVirtualNode(layer);
                        var virtualStart = null;
                        var sequence = null;
                        if (virtualStartIndex !== -1) {
                            virtualStart = layer[virtualStartIndex];
                            sequence = [];
                            for (i = 0; i < virtualStartIndex; i++) {
                                sequence.push(layer[i]);
                            }
                        } else {
                            virtualStart = null;
                            sequence = layer;
                        }
                        if (sequence.length > 0) {
                            this._sequencer(x, null, virtualStart, d, sequence);
                            for (i = 0; i < sequence.length - 1; ++i) {
                                this.setMinDist(sequence[i], sequence[i + 1], x.get(sequence[i + 1]) - x.get(sequence[i]));
                            }
                            if (virtualStart) {
                                this.setMinDist(sequence[sequence.length - 1], virtualStart, x.get(virtualStart) - x.get(sequence[sequence.length - 1]));
                            }
                        }
                        while (virtualStart) {
                            var virtualEnd = this.nextVirtualNode(layer, virtualStart);
                            if (!virtualEnd) {
                                virtualStartIndex = virtualStart.layerIndex;
                                sequence = [];
                                for (i = virtualStartIndex + 1; i < layer.length; i++) {
                                    sequence.push(layer[i]);
                                }
                                if (sequence.length > 0) {
                                    this._sequencer(x, virtualStart, null, d, sequence);
                                    for (i = 0; i < sequence.length - 1; ++i) {
                                        this.setMinDist(sequence[i], sequence[i + 1], x.get(sequence[i + 1]) - x.get(sequence[i]));
                                    }
                                    this.setMinDist(virtualStart, sequence[0], x.get(sequence[0]) - x.get(virtualStart));
                                }
                            } else if (order.get(virtualStart) === d) {
                                virtualStartIndex = virtualStart.layerIndex;
                                var virtualEndIndex = virtualEnd.layerIndex;
                                sequence = [];
                                for (i = virtualStartIndex + 1; i < virtualEndIndex; i++) {
                                    sequence.push(layer[i]);
                                }
                                if (sequence.length > 0) {
                                    this._sequencer(x, virtualStart, virtualEnd, d, sequence);
                                }
                                placed.set(virtualStart, true);
                            }
                            virtualStart = virtualEnd;
                        }
                        this.adjustDirections(l, d, order, placed);
                    }
                }, this);
                var fromLayerIndex = this._isIncreasingLayout() ? 0 : this.layers.length - 1;
                var reachedFinalLayerIndex = function (k, ctx) {
                    if (ctx._isIncreasingLayout()) {
                        return k < ctx.layers.length;
                    } else {
                        return k >= 0;
                    }
                };
                var layerIncrement = this._isIncreasingLayout() ? +1 : -1, offset = 0;
                function maximumHeight(layer, ctx) {
                    var height = Number.MIN_VALUE;
                    for (var n = 0; n < layer.length; ++n) {
                        var node = layer[n];
                        if (ctx._isVerticalLayout()) {
                            height = Math.max(height, node.height);
                        } else {
                            height = Math.max(height, node.width);
                        }
                    }
                    return height;
                }
                for (i = fromLayerIndex; reachedFinalLayerIndex(i, this); i += layerIncrement) {
                    layer = this.layers[i];
                    var height = maximumHeight(layer, this);
                    for (n = 0; n < layer.length; ++n) {
                        node = layer[n];
                        if (this._isVerticalLayout()) {
                            node.x = x.get(node);
                            node.y = offset + height / 2;
                        } else {
                            node.x = offset + height / 2;
                            node.y = x.get(node);
                        }
                    }
                    offset += this.options.layerSeparation + height;
                }
            },
            adjustDirections: function (l, d, order, placed) {
                if (l + d < 0 || l + d >= this.layers.length) {
                    return;
                }
                var prevBridge = null, prevBridgeTarget = null;
                var layer = this.layers[l + d];
                for (var n = 0; n < layer.length; ++n) {
                    var nextBridge = layer[n];
                    if (nextBridge.isVirtual) {
                        var nextBridgeTarget = this.getNeighborOnLayer(nextBridge, l);
                        if (nextBridgeTarget.isVirtual) {
                            if (prevBridge) {
                                var p = placed.get(prevBridgeTarget);
                                var clayer = this.layers[l];
                                var i1 = prevBridgeTarget.layerIndex;
                                var i2 = nextBridgeTarget.layerIndex;
                                for (var i = i1 + 1; i < i2; ++i) {
                                    if (clayer[i].isVirtual) {
                                        p = p && placed.get(clayer[i]);
                                    }
                                }
                                if (p) {
                                    order.set(prevBridge, d);
                                    var j1 = prevBridge.layerIndex;
                                    var j2 = nextBridge.layerIndex;
                                    for (var j = j1 + 1; j < j2; ++j) {
                                        if (layer[j].isVirtual) {
                                            order.set(layer[j], d);
                                        }
                                    }
                                }
                            }
                            prevBridge = nextBridge;
                            prevBridgeTarget = nextBridgeTarget;
                        }
                    }
                }
            },
            getNeighborOnLayer: function (node, l) {
                var neighbor = this.upNodes.get(node)[0];
                if (neighbor.layer === l) {
                    return neighbor;
                }
                neighbor = this.downNodes.get(node)[0];
                if (neighbor.layer === l) {
                    return neighbor;
                }
                return null;
            },
            _sequencer: function (x, virtualStart, virtualEnd, dir, sequence) {
                if (sequence.length === 1) {
                    this._sequenceSingle(x, virtualStart, virtualEnd, dir, sequence[0]);
                }
                if (sequence.length > 1) {
                    var r = sequence.length, t = this.intDiv(r, 2);
                    this._sequencer(x, virtualStart, virtualEnd, dir, sequence.slice(0, t));
                    this._sequencer(x, virtualStart, virtualEnd, dir, sequence.slice(t));
                    this.combineSequences(x, virtualStart, virtualEnd, dir, sequence);
                }
            },
            _sequenceSingle: function (x, virtualStart, virtualEnd, dir, node) {
                var neighbors = dir === -1 ? this.downNodes.get(node) : this.upNodes.get(node);
                var n = neighbors.length;
                if (n !== 0) {
                    if (n % 2 === 1) {
                        x.set(node, x.get(neighbors[this.intDiv(n, 2)]));
                    } else {
                        x.set(node, (x.get(neighbors[this.intDiv(n, 2) - 1]) + x.get(neighbors[this.intDiv(n, 2)])) / 2);
                    }
                    if (virtualStart) {
                        x.set(node, Math.max(x.get(node), x.get(virtualStart) + this.getMinDist(virtualStart, node)));
                    }
                    if (virtualEnd) {
                        x.set(node, Math.min(x.get(node), x.get(virtualEnd) - this.getMinDist(node, virtualEnd)));
                    }
                }
            },
            combineSequences: function (x, virtualStart, virtualEnd, dir, sequence) {
                var r = sequence.length, t = this.intDiv(r, 2);
                var leftHeap = [], i, c, n, neighbors, neighbor, pair;
                for (i = 0; i < t; ++i) {
                    c = 0;
                    neighbors = dir === -1 ? this.downNodes.get(sequence[i]) : this.upNodes.get(sequence[i]);
                    for (n = 0; n < neighbors.length; ++n) {
                        neighbor = neighbors[n];
                        if (x.get(neighbor) >= x.get(sequence[i])) {
                            c++;
                        } else {
                            c--;
                            leftHeap.push({
                                k: x.get(neighbor) + this.getMinDist(sequence[i], sequence[t - 1]),
                                v: 2
                            });
                        }
                    }
                    leftHeap.push({
                        k: x.get(sequence[i]) + this.getMinDist(sequence[i], sequence[t - 1]),
                        v: c
                    });
                }
                if (virtualStart) {
                    leftHeap.push({
                        k: x.get(virtualStart) + this.getMinDist(virtualStart, sequence[t - 1]),
                        v: Number.MAX_VALUE
                    });
                }
                leftHeap.sort(this._positionDescendingComparer);
                var rightHeap = [];
                for (i = t; i < r; ++i) {
                    c = 0;
                    neighbors = dir === -1 ? this.downNodes.get(sequence[i]) : this.upNodes.get(sequence[i]);
                    for (n = 0; n < neighbors.length; ++n) {
                        neighbor = neighbors[n];
                        if (x.get(neighbor) <= x.get(sequence[i])) {
                            c++;
                        } else {
                            c--;
                            rightHeap.push({
                                k: x.get(neighbor) - this.getMinDist(sequence[i], sequence[t]),
                                v: 2
                            });
                        }
                    }
                    rightHeap.push({
                        k: x.get(sequence[i]) - this.getMinDist(sequence[i], sequence[t]),
                        v: c
                    });
                }
                if (virtualEnd) {
                    rightHeap.push({
                        k: x.get(virtualEnd) - this.getMinDist(virtualEnd, sequence[t]),
                        v: Number.MAX_VALUE
                    });
                }
                rightHeap.sort(this._positionAscendingComparer);
                var leftRes = 0, rightRes = 0;
                var m = this.getMinDist(sequence[t - 1], sequence[t]);
                while (x.get(sequence[t]) - x.get(sequence[t - 1]) < m) {
                    if (leftRes < rightRes) {
                        if (leftHeap.length === 0) {
                            x.set(sequence[t - 1], x.get(sequence[t]) - m);
                            break;
                        } else {
                            pair = leftHeap.shift();
                            leftRes = leftRes + pair.v;
                            x.set(sequence[t - 1], pair.k);
                            x.set(sequence[t - 1], Math.max(x.get(sequence[t - 1]), x.get(sequence[t]) - m));
                        }
                    } else {
                        if (rightHeap.length === 0) {
                            x.set(sequence[t], x.get(sequence[t - 1]) + m);
                            break;
                        } else {
                            pair = rightHeap.shift();
                            rightRes = rightRes + pair.v;
                            x.set(sequence[t], pair.k);
                            x.set(sequence[t], Math.min(x.get(sequence[t]), x.get(sequence[t - 1]) + m));
                        }
                    }
                }
                for (i = t - 2; i >= 0; i--) {
                    x.set(sequence[i], Math.min(x.get(sequence[i]), x.get(sequence[t - 1]) - this.getMinDist(sequence[i], sequence[t - 1])));
                }
                for (i = t + 1; i < r; i++) {
                    x.set(sequence[i], Math.max(x.get(sequence[i]), x.get(sequence[t]) + this.getMinDist(sequence[i], sequence[t])));
                }
            },
            placeLeft: function (node, leftPos, leftClass) {
                var pos = Number.NEGATIVE_INFINITY;
                Utils.forEach(this._getComposite(node), function (v) {
                    var leftSibling = this.leftSibling(v);
                    if (leftSibling && this.nodeLeftClass.get(leftSibling) === this.nodeLeftClass.get(v)) {
                        if (!leftPos.containsKey(leftSibling)) {
                            this.placeLeft(leftSibling, leftPos, leftClass);
                        }
                        pos = Math.max(pos, leftPos.get(leftSibling) + this.getMinDist(leftSibling, v));
                    }
                }, this);
                if (pos === Number.NEGATIVE_INFINITY) {
                    pos = 0;
                }
                Utils.forEach(this._getComposite(node), function (v) {
                    leftPos.set(v, pos);
                });
            },
            placeRight: function (node, rightPos, rightClass) {
                var pos = Number.POSITIVE_INFINITY;
                Utils.forEach(this._getComposite(node), function (v) {
                    var rightSibling = this.rightSibling(v);
                    if (rightSibling && this.nodeRightClass.get(rightSibling) === this.nodeRightClass.get(v)) {
                        if (!rightPos.containsKey(rightSibling)) {
                            this.placeRight(rightSibling, rightPos, rightClass);
                        }
                        pos = Math.min(pos, rightPos.get(rightSibling) - this.getMinDist(v, rightSibling));
                    }
                }, this);
                if (pos === Number.POSITIVE_INFINITY) {
                    pos = 0;
                }
                Utils.forEach(this._getComposite(node), function (v) {
                    rightPos.set(v, pos);
                });
            },
            leftSibling: function (node) {
                var layer = this.layers[node.layer], layerIndex = node.layerIndex;
                return layerIndex === 0 ? null : layer[layerIndex - 1];
            },
            rightSibling: function (node) {
                var layer = this.layers[node.layer];
                var layerIndex = node.layerIndex;
                return layerIndex === layer.length - 1 ? null : layer[layerIndex + 1];
            },
            _getComposite: function (node) {
                return node.isVirtual ? this._nodesInLink(node) : [node];
            },
            arrangeNodes: function () {
                var i, l, ni, layer, node;
                for (l = 0; l < this.layers.length; l++) {
                    layer = this.layers[l];
                    for (ni = 0; ni < layer.length; ni++) {
                        node = layer[ni];
                        node.upstreamPriority = node.upstreamLinkCount;
                        node.downstreamPriority = node.downstreamLinkCount;
                    }
                }
                var maxLayoutIterations = 2;
                for (var it = 0; it < maxLayoutIterations; it++) {
                    for (i = this.layers.length - 1; i >= 1; i--) {
                        this.layoutLayer(false, i);
                    }
                    for (i = 0; i < this.layers.length - 1; i++) {
                        this.layoutLayer(true, i);
                    }
                }
                var gridPos = Number.MAX_VALUE;
                for (l = 0; l < this.layers.length; l++) {
                    layer = this.layers[l];
                    for (ni = 0; ni < layer.length; ni++) {
                        node = layer[ni];
                        gridPos = Math.min(gridPos, node.gridPosition);
                    }
                }
                if (gridPos < 0) {
                    for (l = 0; l < this.layers.length; l++) {
                        layer = this.layers[l];
                        for (ni = 0; ni < layer.length; ni++) {
                            node = layer[ni];
                            node.gridPosition = node.gridPosition - gridPos;
                        }
                    }
                }
            },
            layoutLayer: function (down, layer) {
                var iconsidered;
                var considered;
                if (down) {
                    considered = this.layers[iconsidered = layer + 1];
                } else {
                    considered = this.layers[iconsidered = layer - 1];
                }
                var sorted = [];
                for (var n = 0; n < considered.length; n++) {
                    sorted.push(considered[n]);
                }
                sorted.sort(function (n1, n2) {
                    var n1Priority = (n1.upstreamPriority + n1.downstreamPriority) / 2;
                    var n2Priority = (n2.upstreamPriority + n2.downstreamPriority) / 2;
                    if (Math.abs(n1Priority - n2Priority) < 0.0001) {
                        return 0;
                    }
                    if (n1Priority < n2Priority) {
                        return 1;
                    }
                    return -1;
                });
                Utils.forEach(sorted, function (node) {
                    var nodeGridPos = node.gridPosition;
                    var nodeBaryCenter = this.calcBaryCenter(node);
                    var nodePriority = (node.upstreamPriority + node.downstreamPriority) / 2;
                    if (Math.abs(nodeGridPos - nodeBaryCenter) < 0.0001) {
                        return;
                    }
                    if (Math.abs(nodeGridPos - nodeBaryCenter) < 0.25 + 0.0001) {
                        return;
                    }
                    if (nodeGridPos < nodeBaryCenter) {
                        while (nodeGridPos < nodeBaryCenter) {
                            if (!this.moveRight(node, considered, nodePriority)) {
                                break;
                            }
                            nodeGridPos = node.gridPosition;
                        }
                    } else {
                        while (nodeGridPos > nodeBaryCenter) {
                            if (!this.moveLeft(node, considered, nodePriority)) {
                                break;
                            }
                            nodeGridPos = node.gridPosition;
                        }
                    }
                }, this);
                if (iconsidered > 0) {
                    this.calcDownData(iconsidered - 1);
                }
                if (iconsidered < this.layers.length - 1) {
                    this.calcUpData(iconsidered + 1);
                }
            },
            moveRight: function (node, layer, priority) {
                var index = Utils.indexOf(layer, node);
                if (index === layer.length - 1) {
                    node.gridPosition = node.gridPosition + 0.5;
                    return true;
                }
                var rightNode = layer[index + 1];
                var rightNodePriority = (rightNode.upstreamPriority + rightNode.downstreamPriority) / 2;
                if (rightNode.gridPosition > node.gridPosition + 1) {
                    node.gridPosition = node.gridPosition + 0.5;
                    return true;
                }
                if (rightNodePriority > priority || Math.abs(rightNodePriority - priority) < 0.0001) {
                    return false;
                }
                if (this.moveRight(rightNode, layer, priority)) {
                    node.gridPosition = node.gridPosition + 0.5;
                    return true;
                }
                return false;
            },
            moveLeft: function (node, layer, priority) {
                var index = Utils.indexOf(layer, node);
                if (index === 0) {
                    node.gridPosition = node.gridPosition - 0.5;
                    return true;
                }
                var leftNode = layer[index - 1];
                var leftNodePriority = (leftNode.upstreamPriority + leftNode.downstreamPriority) / 2;
                if (leftNode.gridPosition < node.gridPosition - 1) {
                    node.gridPosition = node.gridPosition - 0.5;
                    return true;
                }
                if (leftNodePriority > priority || Math.abs(leftNodePriority - priority) < 0.0001) {
                    return false;
                }
                if (this.moveLeft(leftNode, layer, priority)) {
                    node.gridPosition = node.gridPosition - 0.5;
                    return true;
                }
                return false;
            },
            mapVirtualNode: function (node, link) {
                this.nodeToLinkMap.set(node, link);
                if (!this.linkToNodeMap.containsKey(link)) {
                    this.linkToNodeMap.set(link, []);
                }
                this.linkToNodeMap.get(link).push(node);
            },
            _nodesInLink: function (node) {
                return this.linkToNodeMap.get(this.nodeToLinkMap.get(node));
            },
            _dummify: function () {
                this.linkToNodeMap = new Dictionary();
                this.nodeToLinkMap = new Dictionary();
                var layer, pos, newNode, node, r, newLink, i, l, links = this.graph.links.slice(0);
                var layers = this.layers;
                var addLinkBetweenLayers = function (upLayer, downLayer, link) {
                    layers[upLayer].linksTo[downLayer] = layers[upLayer].linksTo[downLayer] || [];
                    layers[upLayer].linksTo[downLayer].push(link);
                };
                for (l = 0; l < links.length; l++) {
                    var link = links[l];
                    var o = link.source;
                    var d = link.target;
                    var oLayer = o.layer;
                    var dLayer = d.layer;
                    var oPos = o.gridPosition;
                    var dPos = d.gridPosition;
                    var step = (dPos - oPos) / Math.abs(dLayer - oLayer);
                    var p = o;
                    if (oLayer - dLayer > 1) {
                        for (i = oLayer - 1; i > dLayer; i--) {
                            newNode = new Node();
                            newNode.x = o.x;
                            newNode.y = o.y;
                            newNode.width = o.width / 100;
                            newNode.height = o.height / 100;
                            layer = layers[i];
                            pos = (i - dLayer) * step + oPos;
                            if (pos > layer.length) {
                                pos = layer.length;
                            }
                            if (oPos >= layers[oLayer].length - 1 && dPos >= layers[dLayer].length - 1) {
                                pos = layer.length;
                            } else if (oPos === 0 && dPos === 0) {
                                pos = 0;
                            }
                            newNode.layer = i;
                            newNode.uBaryCenter = 0;
                            newNode.dBaryCenter = 0;
                            newNode.upstreamLinkCount = 0;
                            newNode.downstreamLinkCount = 0;
                            newNode.gridPosition = pos;
                            newNode.isVirtual = true;
                            Utils.insert(layer, newNode, pos);
                            for (r = pos + 1; r < layer.length; r++) {
                                node = layer[r];
                                node.gridPosition = node.gridPosition + 1;
                            }
                            newLink = new Link(p, newNode);
                            newLink.depthOfDumminess = 0;
                            addLinkBetweenLayers(i - 1, i, newLink);
                            p = newNode;
                            this.graph._addNode(newNode);
                            this.graph.addLink(newLink);
                            newNode.index = this.graph.nodes.length - 1;
                            this.mapVirtualNode(newNode, link);
                        }
                        addLinkBetweenLayers(dLayer - 1, dLayer, newLink);
                        link.changeSource(p);
                        link.depthOfDumminess = oLayer - dLayer - 1;
                    } else if (oLayer - dLayer < -1) {
                        for (i = oLayer + 1; i < dLayer; i++) {
                            newNode = new Node();
                            newNode.x = o.x;
                            newNode.y = o.y;
                            newNode.width = o.width / 100;
                            newNode.height = o.height / 100;
                            layer = layers[i];
                            pos = (i - oLayer) * step + oPos;
                            if (pos > layer.length) {
                                pos = layer.length;
                            }
                            if (oPos >= layers[oLayer].length - 1 && dPos >= layers[dLayer].length - 1) {
                                pos = layer.length;
                            } else if (oPos === 0 && dPos === 0) {
                                pos = 0;
                            }
                            newNode.layer = i;
                            newNode.uBaryCenter = 0;
                            newNode.dBaryCenter = 0;
                            newNode.upstreamLinkCount = 0;
                            newNode.downstreamLinkCount = 0;
                            newNode.gridPosition = pos;
                            newNode.isVirtual = true;
                            pos &= pos;
                            Utils.insert(layer, newNode, pos);
                            for (r = pos + 1; r < layer.length; r++) {
                                node = layer[r];
                                node.gridPosition = node.gridPosition + 1;
                            }
                            newLink = new Link(p, newNode);
                            newLink.depthOfDumminess = 0;
                            addLinkBetweenLayers(i - 1, i, newLink);
                            p = newNode;
                            this.graph._addNode(newNode);
                            this.graph.addLink(newLink);
                            newNode.index = this.graph.nodes.length - 1;
                            this.mapVirtualNode(newNode, link);
                        }
                        addLinkBetweenLayers(dLayer - 1, dLayer, link);
                        link.changeSource(p);
                        link.depthOfDumminess = dLayer - oLayer - 1;
                    } else {
                        addLinkBetweenLayers(oLayer, dLayer, link);
                    }
                }
            },
            _dedummify: function () {
                var dedum = true;
                while (dedum) {
                    dedum = false;
                    for (var l = 0; l < this.graph.links.length; l++) {
                        var link = this.graph.links[l];
                        if (!link.depthOfDumminess) {
                            continue;
                        }
                        var points = [];
                        points.unshift({
                            x: link.target.x,
                            y: link.target.y
                        });
                        points.unshift({
                            x: link.source.x,
                            y: link.source.y
                        });
                        var temp = link;
                        var depthOfDumminess = link.depthOfDumminess;
                        for (var d = 0; d < depthOfDumminess; d++) {
                            var node = temp.source;
                            var prevLink = node.incoming[0];
                            points.unshift({
                                x: prevLink.source.x,
                                y: prevLink.source.y
                            });
                            temp = prevLink;
                        }
                        link.changeSource(temp.source);
                        link.depthOfDumminess = 0;
                        if (points.length > 2) {
                            points.splice(0, 1);
                            points.splice(points.length - 1);
                            link.points = points;
                        } else {
                            link.points = [];
                        }
                        dedum = true;
                        break;
                    }
                }
            },
            _optimizeCrossings: function () {
                var moves = -1, i;
                var maxIterations = 3;
                var iter = 0;
                while (moves !== 0) {
                    if (iter++ > maxIterations) {
                        break;
                    }
                    moves = 0;
                    for (i = this.layers.length - 1; i >= 1; i--) {
                        moves += this.optimizeLayerCrossings(false, i);
                    }
                    for (i = 0; i < this.layers.length - 1; i++) {
                        moves += this.optimizeLayerCrossings(true, i);
                    }
                }
            },
            calcUpData: function (layer) {
                if (layer === 0) {
                    return;
                }
                var considered = this.layers[layer], i, l, link;
                var upLayer = new Set();
                var temp = this.layers[layer - 1];
                for (i = 0; i < temp.length; i++) {
                    upLayer.add(temp[i]);
                }
                for (i = 0; i < considered.length; i++) {
                    var node = considered[i];
                    var sum = 0;
                    var total = 0;
                    for (l = 0; l < node.incoming.length; l++) {
                        link = node.incoming[l];
                        if (upLayer.contains(link.source)) {
                            total++;
                            sum += link.source.gridPosition;
                        }
                    }
                    for (l = 0; l < node.outgoing.length; l++) {
                        link = node.outgoing[l];
                        if (upLayer.contains(link.target)) {
                            total++;
                            sum += link.target.gridPosition;
                        }
                    }
                    if (total > 0) {
                        node.uBaryCenter = sum / total;
                        node.upstreamLinkCount = total;
                    } else {
                        node.uBaryCenter = i;
                        node.upstreamLinkCount = 0;
                    }
                }
            },
            calcDownData: function (layer) {
                if (layer === this.layers.length - 1) {
                    return;
                }
                var considered = this.layers[layer], i, l, link;
                var downLayer = new Set();
                var temp = this.layers[layer + 1];
                for (i = 0; i < temp.length; i++) {
                    downLayer.add(temp[i]);
                }
                for (i = 0; i < considered.length; i++) {
                    var node = considered[i];
                    var sum = 0;
                    var total = 0;
                    for (l = 0; l < node.incoming.length; l++) {
                        link = node.incoming[l];
                        if (downLayer.contains(link.source)) {
                            total++;
                            sum += link.source.gridPosition;
                        }
                    }
                    for (l = 0; l < node.outgoing.length; l++) {
                        link = node.outgoing[l];
                        if (downLayer.contains(link.target)) {
                            total++;
                            sum += link.target.gridPosition;
                        }
                    }
                    if (total > 0) {
                        node.dBaryCenter = sum / total;
                        node.downstreamLinkCount = total;
                    } else {
                        node.dBaryCenter = i;
                        node.downstreamLinkCount = 0;
                    }
                }
            },
            optimizeLayerCrossings: function (down, layer) {
                var iconsidered;
                var considered;
                if (down) {
                    considered = this.layers[iconsidered = layer + 1];
                } else {
                    considered = this.layers[iconsidered = layer - 1];
                }
                var presorted = considered.slice(0);
                if (down) {
                    this.calcUpData(iconsidered);
                } else {
                    this.calcDownData(iconsidered);
                }
                var that = this;
                considered.sort(function (n1, n2) {
                    var n1BaryCenter = that.calcBaryCenter(n1), n2BaryCenter = that.calcBaryCenter(n2);
                    if (Math.abs(n1BaryCenter - n2BaryCenter) < 0.0001) {
                        if (n1.degree() === n2.degree()) {
                            return that.compareByIndex(n1, n2);
                        } else if (n1.degree() < n2.degree()) {
                            return 1;
                        }
                        return -1;
                    }
                    var compareValue = (n2BaryCenter - n1BaryCenter) * 1000;
                    if (compareValue > 0) {
                        return -1;
                    } else if (compareValue < 0) {
                        return 1;
                    }
                    return that.compareByIndex(n1, n2);
                });
                var i, moves = 0;
                for (i = 0; i < considered.length; i++) {
                    if (considered[i] !== presorted[i]) {
                        moves++;
                    }
                }
                if (moves > 0) {
                    var inode = 0;
                    for (i = 0; i < considered.length; i++) {
                        var node = considered[i];
                        node.gridPosition = inode++;
                    }
                }
                return moves;
            },
            _swapPairs: function () {
                var maxIterations = this.options.layeredIterations;
                var iter = 0;
                while (true) {
                    if (iter++ > maxIterations) {
                        break;
                    }
                    var downwards = iter % 4 <= 1;
                    var secondPass = iter % 4 === 1;
                    for (var l = downwards ? 0 : this.layers.length - 1; downwards ? l <= this.layers.length - 1 : l >= 0; l += downwards ? 1 : -1) {
                        var layer = this.layers[l];
                        var hasSwapped = false;
                        var calcCrossings = true;
                        var memCrossings = 0;
                        for (var n = 0; n < layer.length - 1; n++) {
                            var up = 0;
                            var down = 0;
                            var crossBefore = 0;
                            if (calcCrossings) {
                                if (l !== 0) {
                                    up = this.countLinksCrossingBetweenTwoLayers(l - 1, l);
                                }
                                if (l !== this.layers.length - 1) {
                                    down = this.countLinksCrossingBetweenTwoLayers(l, l + 1);
                                }
                                if (downwards) {
                                    up *= 2;
                                } else {
                                    down *= 2;
                                }
                                crossBefore = up + down;
                            } else {
                                crossBefore = memCrossings;
                            }
                            if (crossBefore === 0) {
                                continue;
                            }
                            var node1 = layer[n];
                            var node2 = layer[n + 1];
                            var node1GridPos = node1.gridPosition;
                            var node2GridPos = node2.gridPosition;
                            layer[n] = node2;
                            layer[n + 1] = node1;
                            node1.gridPosition = node2GridPos;
                            node2.gridPosition = node1GridPos;
                            up = 0;
                            if (l !== 0) {
                                up = this.countLinksCrossingBetweenTwoLayers(l - 1, l);
                            }
                            down = 0;
                            if (l !== this.layers.length - 1) {
                                down = this.countLinksCrossingBetweenTwoLayers(l, l + 1);
                            }
                            if (downwards) {
                                up *= 2;
                            } else {
                                down *= 2;
                            }
                            var crossAfter = up + down;
                            var revert = false;
                            if (secondPass) {
                                revert = crossAfter >= crossBefore;
                            } else {
                                revert = crossAfter > crossBefore;
                            }
                            if (revert) {
                                node1 = layer[n];
                                node2 = layer[n + 1];
                                node1GridPos = node1.gridPosition;
                                node2GridPos = node2.gridPosition;
                                layer[n] = node2;
                                layer[n + 1] = node1;
                                node1.gridPosition = node2GridPos;
                                node2.gridPosition = node1GridPos;
                                memCrossings = crossBefore;
                                calcCrossings = false;
                            } else {
                                hasSwapped = true;
                                calcCrossings = true;
                            }
                        }
                        if (hasSwapped) {
                            if (l !== this.layers.length - 1) {
                                this.calcUpData(l + 1);
                            }
                            if (l !== 0) {
                                this.calcDownData(l - 1);
                            }
                        }
                    }
                }
            },
            countLinksCrossingBetweenTwoLayers: function (ulayer, dlayer) {
                var links = this.layers[ulayer].linksTo[dlayer];
                var link1, link2, n11, n12, n21, n22, l1, l2;
                var crossings = 0;
                var length = links.length;
                for (l1 = 0; l1 < length; l1++) {
                    link1 = links[l1];
                    for (l2 = l1 + 1; l2 < length; l2++) {
                        link2 = links[l2];
                        if (link1.target.layer === dlayer) {
                            n11 = link1.source;
                            n12 = link1.target;
                        } else {
                            n11 = link1.target;
                            n12 = link1.source;
                        }
                        if (link2.target.layer === dlayer) {
                            n21 = link2.source;
                            n22 = link2.target;
                        } else {
                            n21 = link2.target;
                            n22 = link2.source;
                        }
                        var n11gp = n11.gridPosition;
                        var n12gp = n12.gridPosition;
                        var n21gp = n21.gridPosition;
                        var n22gp = n22.gridPosition;
                        if ((n11gp - n21gp) * (n12gp - n22gp) < 0) {
                            crossings++;
                        }
                    }
                }
                return crossings;
            },
            calcBaryCenter: function (node) {
                var upstreamLinkCount = node.upstreamLinkCount;
                var downstreamLinkCount = node.downstreamLinkCount;
                var uBaryCenter = node.uBaryCenter;
                var dBaryCenter = node.dBaryCenter;
                if (upstreamLinkCount > 0 && downstreamLinkCount > 0) {
                    return (uBaryCenter + dBaryCenter) / 2;
                }
                if (upstreamLinkCount > 0) {
                    return uBaryCenter;
                }
                if (downstreamLinkCount > 0) {
                    return dBaryCenter;
                }
                return 0;
            },
            _gridPositionComparer: function (x, y) {
                if (x.gridPosition < y.gridPosition) {
                    return -1;
                }
                if (x.gridPosition > y.gridPosition) {
                    return 1;
                }
                return 0;
            },
            _positionAscendingComparer: function (x, y) {
                return x.k < y.k ? -1 : x.k > y.k ? 1 : 0;
            },
            _positionDescendingComparer: function (x, y) {
                return x.k < y.k ? 1 : x.k > y.k ? -1 : 0;
            },
            _firstVirtualNode: function (layer) {
                for (var c = 0; c < layer.length; c++) {
                    if (layer[c].isVirtual) {
                        return c;
                    }
                }
                return -1;
            },
            compareByIndex: function (o1, o2) {
                var i1 = o1.index;
                var i2 = o2.index;
                if (i1 < i2) {
                    return 1;
                }
                if (i1 > i2) {
                    return -1;
                }
                return 0;
            },
            intDiv: function (numerator, denominator) {
                return (numerator - numerator % denominator) / denominator;
            },
            nextVirtualNode: function (layer, node) {
                var nodeIndex = node.layerIndex;
                for (var i = nodeIndex + 1; i < layer.length; ++i) {
                    if (layer[i].isVirtual) {
                        return layer[i];
                    }
                }
                return null;
            }
        });
        var LayoutState = kendo.Class.extend({
            init: function (diagram, graphOrNodes) {
                if (Utils.isUndefined(diagram)) {
                    throw 'No diagram given';
                }
                this.diagram = diagram;
                this.nodeMap = new Dictionary();
                this.linkMap = new Dictionary();
                this.capture(graphOrNodes ? graphOrNodes : diagram);
            },
            capture: function (diagramOrGraphOrNodes) {
                var node, nodes, shape, i, conn, link, links;
                if (diagramOrGraphOrNodes instanceof diagram.Graph) {
                    for (i = 0; i < diagramOrGraphOrNodes.nodes.length; i++) {
                        node = diagramOrGraphOrNodes.nodes[i];
                        shape = node.associatedShape;
                        this.nodeMap.set(shape.visual.id, new Rect(node.x, node.y, node.width, node.height));
                    }
                    for (i = 0; i < diagramOrGraphOrNodes.links.length; i++) {
                        link = diagramOrGraphOrNodes.links[i];
                        conn = link.associatedConnection;
                        this.linkMap.set(conn.visual.id, link.points());
                    }
                } else if (diagramOrGraphOrNodes instanceof Array) {
                    nodes = diagramOrGraphOrNodes;
                    for (i = 0; i < nodes.length; i++) {
                        node = nodes[i];
                        shape = node.associatedShape;
                        if (shape) {
                            this.nodeMap.set(shape.visual.id, new Rect(node.x, node.y, node.width, node.height));
                        }
                    }
                } else if (diagramOrGraphOrNodes.hasOwnProperty('links') && diagramOrGraphOrNodes.hasOwnProperty('nodes')) {
                    nodes = diagramOrGraphOrNodes.nodes;
                    links = diagramOrGraphOrNodes.links;
                    for (i = 0; i < nodes.length; i++) {
                        node = nodes[i];
                        shape = node.associatedShape;
                        if (shape) {
                            this.nodeMap.set(shape.visual.id, new Rect(node.x, node.y, node.width, node.height));
                        }
                    }
                    for (i = 0; i < links.length; i++) {
                        link = links[i];
                        conn = link.associatedConnection;
                        if (conn) {
                            this.linkMap.set(conn.visual.id, link.points);
                        }
                    }
                } else {
                    var shapes = this.diagram.shapes;
                    var connections = this.diagram.connections;
                    for (i = 0; i < shapes.length; i++) {
                        shape = shapes[i];
                        this.nodeMap.set(shape.visual.id, shape.bounds());
                    }
                    for (i = 0; i < connections.length; i++) {
                        conn = connections[i];
                        this.linkMap.set(conn.visual.id, conn.points());
                    }
                }
            }
        });
        deepExtend(diagram, {
            init: function (element) {
                kendo.init(element, diagram.ui);
            },
            SpringLayout: SpringLayout,
            TreeLayout: TreeLayout,
            GraphAdapter: DiagramToHyperTreeAdapter,
            LayeredLayout: LayeredLayout,
            LayoutBase: LayoutBase,
            LayoutState: LayoutState
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('dataviz/diagram/dom', [
        'kendo.data',
        'kendo.draganddrop',
        'kendo.toolbar',
        'kendo.editable',
        'kendo.window',
        'kendo.dropdownlist',
        'kendo.dataviz.core',
        'kendo.dataviz.themes',
        'dataviz/diagram/svg',
        'dataviz/diagram/services',
        'dataviz/diagram/layout'
    ], f);
}(function () {
    (function ($, undefined) {
        var dataviz = kendo.dataviz, draw = kendo.drawing, geom = kendo.geometry, diagram = dataviz.diagram, Widget = kendo.ui.Widget, Class = kendo.Class, proxy = $.proxy, deepExtend = kendo.deepExtend, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, extend = $.extend, HierarchicalDataSource = kendo.data.HierarchicalDataSource, Canvas = diagram.Canvas, Group = diagram.Group, Rectangle = diagram.Rectangle, Circle = diagram.Circle, CompositeTransform = diagram.CompositeTransform, Rect = diagram.Rect, Path = diagram.Path, DeleteShapeUnit = diagram.DeleteShapeUnit, DeleteConnectionUnit = diagram.DeleteConnectionUnit, TextBlock = diagram.TextBlock, Image = diagram.Image, Point = diagram.Point, Intersect = diagram.Intersect, ConnectionEditAdorner = diagram.ConnectionEditAdorner, UndoRedoService = diagram.UndoRedoService, ToolService = diagram.ToolService, Selector = diagram.Selector, ResizingAdorner = diagram.ResizingAdorner, ConnectorsAdorner = diagram.ConnectorsAdorner, Cursors = diagram.Cursors, Utils = diagram.Utils, Observable = kendo.Observable, ToBackUnit = diagram.ToBackUnit, ToFrontUnit = diagram.ToFrontUnit, PolylineRouter = diagram.PolylineRouter, CascadingRouter = diagram.CascadingRouter, isUndefined = Utils.isUndefined, isDefined = Utils.isDefined, defined = draw.util.defined, isArray = $.isArray, isFunction = kendo.isFunction, isString = Utils.isString, isPlainObject = $.isPlainObject, math = Math;
        var NS = '.kendoDiagram', CASCADING = 'cascading', ITEMBOUNDSCHANGE = 'itemBoundsChange', CHANGE = 'change', CLICK = 'click', DRAG = 'drag', DRAG_END = 'dragEnd', DRAG_START = 'dragStart', MOUSE_ENTER = 'mouseEnter', MOUSE_LEAVE = 'mouseLeave', ERROR = 'error', AUTO = 'Auto', TOP = 'Top', RIGHT = 'Right', LEFT = 'Left', BOTTOM = 'Bottom', MAXINT = 9007199254740992, SELECT = 'select', ITEMROTATE = 'itemRotate', PAN = 'pan', ZOOM_START = 'zoomStart', ZOOM_END = 'zoomEnd', NONE = 'none', DEFAULT_CANVAS_WIDTH = 600, DEFAULT_CANVAS_HEIGHT = 600, DEFAULT_SHAPE_TYPE = 'rectangle', DEFAULT_SHAPE_WIDTH = 100, DEFAULT_SHAPE_HEIGHT = 100, DEFAULT_SHAPE_MINWIDTH = 20, DEFAULT_SHAPE_MINHEIGHT = 20, DEFAULT_SHAPE_POSITION = 0, DEFAULT_CONNECTION_BACKGROUND = 'Yellow', MAX_VALUE = Number.MAX_VALUE, MIN_VALUE = -Number.MAX_VALUE, ABSOLUTE = 'absolute', TRANSFORMED = 'transformed', ROTATED = 'rotated', TRANSPARENT = 'transparent', WIDTH = 'width', HEIGHT = 'height', X = 'x', Y = 'y', MOUSEWHEEL_NS = 'DOMMouseScroll' + NS + ' mousewheel' + NS, MOBILE_ZOOM_RATE = 0.05, MOBILE_PAN_DISTANCE = 5, BUTTON_TEMPLATE = '<a class="k-button k-button-icontext #=className#" href="\\#"><span class="#=iconClass# #=imageClass#"></span>#=text#</a>', CONNECTION_CONTENT_OFFSET = 5;
        diagram.DefaultConnectors = [
            { name: TOP },
            { name: BOTTOM },
            { name: LEFT },
            { name: RIGHT },
            {
                name: AUTO,
                position: function (shape) {
                    return shape.getPosition('center');
                }
            }
        ];
        var defaultButtons = {
            cancel: {
                text: 'Cancel',
                imageClass: 'k-i-cancel',
                className: 'k-diagram-cancel',
                iconClass: 'k-icon'
            },
            update: {
                text: 'Update',
                imageClass: 'k-i-checkmark',
                className: 'k-diagram-update',
                iconClass: 'k-icon'
            }
        };
        diagram.shapeDefaults = function (extra) {
            var defaults = {
                type: DEFAULT_SHAPE_TYPE,
                path: '',
                autoSize: true,
                visual: null,
                x: DEFAULT_SHAPE_POSITION,
                y: DEFAULT_SHAPE_POSITION,
                minWidth: DEFAULT_SHAPE_MINWIDTH,
                minHeight: DEFAULT_SHAPE_MINHEIGHT,
                width: DEFAULT_SHAPE_WIDTH,
                height: DEFAULT_SHAPE_HEIGHT,
                hover: {},
                editable: {
                    connect: true,
                    tools: []
                },
                connectors: diagram.DefaultConnectors,
                rotation: { angle: 0 }
            };
            Utils.simpleExtend(defaults, extra);
            return defaults;
        };
        function mwDelta(e) {
            var origEvent = e.originalEvent, delta = 0;
            if (origEvent.wheelDelta) {
                delta = -origEvent.wheelDelta / 40;
                delta = delta > 0 ? math.ceil(delta) : math.floor(delta);
            } else if (origEvent.detail) {
                delta = origEvent.detail;
            }
            return delta;
        }
        function isAutoConnector(connector) {
            return connector.options.name.toLowerCase() === AUTO.toLowerCase();
        }
        function closestConnector(point, connectors) {
            var minimumDistance = MAXINT, resCtr, connector;
            for (var i = 0; i < connectors.length; i++) {
                connector = connectors[i];
                if (!isAutoConnector(connector)) {
                    var dist = point.distanceTo(connector.position());
                    if (dist < minimumDistance) {
                        minimumDistance = dist;
                        resCtr = connector;
                    }
                }
            }
            return resCtr;
        }
        function indicesOfItems(group, visuals) {
            var i, indices = [], visual;
            var children = group.drawingContainer().children;
            var length = children.length;
            for (i = 0; i < visuals.length; i++) {
                visual = visuals[i];
                for (var j = 0; j < length; j++) {
                    if (children[j] == visual.drawingContainer()) {
                        indices.push(j);
                        break;
                    }
                }
            }
            return indices;
        }
        var DiagramElement = Observable.extend({
            init: function (options) {
                var that = this;
                that.dataItem = (options || {}).dataItem;
                Observable.fn.init.call(that);
                that.options = deepExtend({ id: diagram.randomId() }, that.options, options);
                that.isSelected = false;
                that.visual = new Group({
                    id: that.options.id,
                    autoSize: that.options.autoSize
                });
                that.id = that.options.id;
                that._template();
            },
            options: {
                hover: {},
                cursor: Cursors.grip,
                content: { align: 'center middle' },
                selectable: true,
                serializable: true,
                enable: true
            },
            _getCursor: function (point) {
                if (this.adorner) {
                    return this.adorner._getCursor(point);
                }
                return this.options.cursor;
            },
            visible: function (value) {
                if (isUndefined(value)) {
                    return this.visual.visible();
                } else {
                    this.visual.visible(value);
                }
            },
            bounds: function () {
            },
            refresh: function () {
                this.visual.redraw();
            },
            position: function (point) {
                this.options.x = point.x;
                this.options.y = point.y;
                this.visual.position(point);
            },
            toString: function () {
                return this.options.id;
            },
            serialize: function () {
                var json = deepExtend({}, { options: this.options });
                if (this.dataItem) {
                    json.dataItem = this.dataItem.toString();
                }
                return json;
            },
            _content: function (content) {
                if (content !== undefined) {
                    var options = this.options;
                    if (diagram.Utils.isString(content)) {
                        options.content.text = content;
                    } else {
                        deepExtend(options.content, content);
                    }
                    var contentOptions = options.content;
                    var contentVisual = this._contentVisual;
                    if (!contentVisual) {
                        this._createContentVisual(contentOptions);
                    } else {
                        this._updateContentVisual(contentOptions);
                    }
                }
                return this.options.content.text;
            },
            _createContentVisual: function (options) {
                if (options.text) {
                    this._contentVisual = new TextBlock(options);
                    this._contentVisual._includeInBBox = false;
                    this.visual.append(this._contentVisual);
                }
            },
            _updateContentVisual: function (options) {
                this._contentVisual.redraw(options);
            },
            _hitTest: function (point) {
                var bounds = this.bounds();
                return this.visible() && bounds.contains(point) && this.options.enable;
            },
            _template: function () {
                var that = this;
                if (that.options.content.template) {
                    var data = that.dataItem || {}, elementTemplate = kendo.template(that.options.content.template, { paramName: 'dataItem' });
                    that.options.content.text = elementTemplate(data);
                }
            },
            _canSelect: function () {
                return this.options.selectable !== false;
            },
            toJSON: function () {
                return { id: this.options.id };
            }
        });
        var Connector = Class.extend({
            init: function (shape, options) {
                this.options = deepExtend({}, this.options, options);
                this.connections = [];
                this.shape = shape;
            },
            options: {
                width: 7,
                height: 7,
                fill: { color: DEFAULT_CONNECTION_BACKGROUND },
                hover: {}
            },
            position: function () {
                if (this.options.position) {
                    return this.options.position(this.shape);
                } else {
                    return this.shape.getPosition(this.options.name);
                }
            },
            toJSON: function () {
                return {
                    shapeId: this.shape.toString(),
                    connector: this.options.name
                };
            }
        });
        Connector.parse = function (diagram, str) {
            var tempStr = str.split(':'), id = tempStr[0], name = tempStr[1] || AUTO;
            for (var i = 0; i < diagram.shapes.length; i++) {
                var shape = diagram.shapes[i];
                if (shape.options.id == id) {
                    return shape.getConnector(name.trim());
                }
            }
        };
        var Shape = DiagramElement.extend({
            init: function (options, diagram) {
                var that = this;
                DiagramElement.fn.init.call(that, options);
                this.diagram = diagram;
                this.updateOptionsFromModel();
                options = that.options;
                that.connectors = [];
                that.type = options.type;
                that.createShapeVisual();
                that.updateBounds();
                that.content(that.content());
                that._createConnectors();
            },
            options: diagram.shapeDefaults(),
            _setOptionsFromModel: function (model) {
                var modelOptions = filterShapeDataItem(model || this.dataItem);
                this.options = deepExtend({}, this.options, modelOptions);
                this.redrawVisual();
            },
            updateOptionsFromModel: function (model, field) {
                if (this.diagram && this.diagram._isEditable) {
                    var modelOptions = filterShapeDataItem(model || this.dataItem);
                    if (model && field) {
                        if (!dataviz.inArray(field, [
                                'x',
                                'y',
                                'width',
                                'height'
                            ])) {
                            if (this.options.visual) {
                                this._redrawVisual();
                            } else if (modelOptions.type) {
                                this.options = deepExtend({}, this.options, modelOptions);
                                this._redrawVisual();
                            }
                            if (this.options.content) {
                                this._template();
                                this.content(this.options.content);
                            }
                        } else {
                            var bounds = this.bounds();
                            bounds[field] = model[field];
                            this.bounds(bounds);
                        }
                    } else {
                        this.options = deepExtend({}, this.options, modelOptions);
                    }
                }
            },
            _redrawVisual: function () {
                this.visual.clear();
                this._contentVisual = null;
                this.options.dataItem = this.dataItem;
                this.createShapeVisual();
                this.updateBounds();
            },
            redrawVisual: function () {
                this._redrawVisual();
                if (this.options.content) {
                    this._template();
                    this.content(this.options.content);
                }
            },
            updateModel: function (syncChanges) {
                var diagram = this.diagram;
                if (diagram && diagram._isEditable) {
                    var bounds = this._bounds;
                    var model = this.dataItem;
                    if (model) {
                        diagram._suspendModelRefresh();
                        if (defined(model.x) && bounds.x !== model.x) {
                            model.set('x', bounds.x);
                        }
                        if (defined(model.y) && bounds.y !== model.y) {
                            model.set('y', bounds.y);
                        }
                        if (defined(model.width) && bounds.width !== model.width) {
                            model.set('width', bounds.width);
                        }
                        if (defined(model.height) && bounds.height !== model.height) {
                            model.set('height', bounds.height);
                        }
                        this.dataItem = model;
                        diagram._resumeModelRefresh();
                        if (syncChanges) {
                            diagram._syncShapeChanges();
                        }
                    }
                }
            },
            updateBounds: function () {
                var bounds = this.visual._measure(true);
                var options = this.options;
                this.bounds(new Rect(options.x, options.y, bounds.width, bounds.height));
                this._rotate();
                this._alignContent();
            },
            content: function (content) {
                var result = this._content(content);
                this._alignContent();
                return result;
            },
            _alignContent: function () {
                var contentOptions = this.options.content || {};
                var contentVisual = this._contentVisual;
                if (contentVisual && contentOptions.align) {
                    var containerRect = this.visual._measure();
                    var aligner = new diagram.RectAlign(containerRect);
                    var contentBounds = contentVisual.drawingElement.bbox(null);
                    var contentRect = new Rect(0, 0, contentBounds.width(), contentBounds.height());
                    var alignedBounds = aligner.align(contentRect, contentOptions.align);
                    contentVisual.position(alignedBounds.topLeft());
                }
            },
            _createConnectors: function () {
                var options = this.options, length = options.connectors.length, connectorDefaults = options.connectorDefaults, connector, i;
                for (i = 0; i < length; i++) {
                    connector = new Connector(this, deepExtend({}, connectorDefaults, options.connectors[i]));
                    this.connectors.push(connector);
                }
            },
            bounds: function (value) {
                var bounds;
                if (value) {
                    if (isString(value)) {
                        switch (value) {
                        case TRANSFORMED:
                            bounds = this._transformedBounds();
                            break;
                        case ABSOLUTE:
                            bounds = this._transformedBounds();
                            var pan = this.diagram._pan;
                            bounds.x += pan.x;
                            bounds.y += pan.y;
                            break;
                        case ROTATED:
                            bounds = this._rotatedBounds();
                            break;
                        default:
                            bounds = this._bounds;
                        }
                    } else {
                        this._setBounds(value);
                        this._triggerBoundsChange();
                        if (!(this.diagram && this.diagram._layouting)) {
                            this.refreshConnections();
                        }
                    }
                } else {
                    bounds = this._bounds;
                }
                return bounds;
            },
            _setBounds: function (rect) {
                var options = this.options;
                var topLeft = rect.topLeft();
                var x = options.x = topLeft.x;
                var y = options.y = topLeft.y;
                var width = options.width = math.max(rect.width, options.minWidth);
                var height = options.height = math.max(rect.height, options.minHeight);
                this._bounds = new Rect(x, y, width, height);
                this.visual.redraw({
                    x: x,
                    y: y,
                    width: width,
                    height: height
                });
            },
            position: function (point) {
                if (point) {
                    this.bounds(new Rect(point.x, point.y, this._bounds.width, this._bounds.height));
                } else {
                    return this._bounds.topLeft();
                }
            },
            clone: function () {
                var json = this.serialize();
                json.options.id = diagram.randomId();
                if (this.diagram && this.diagram._isEditable && defined(this.dataItem)) {
                    json.options.dataItem = cloneDataItem(this.dataItem);
                }
                return new Shape(json.options);
            },
            select: function (value) {
                var diagram = this.diagram, selected, deselected;
                if (isUndefined(value)) {
                    value = true;
                }
                if (this._canSelect()) {
                    if (this.isSelected != value) {
                        selected = [];
                        deselected = [];
                        this.isSelected = value;
                        if (this.isSelected) {
                            diagram._selectedItems.push(this);
                            selected.push(this);
                        } else {
                            Utils.remove(diagram._selectedItems, this);
                            deselected.push(this);
                        }
                        if (!diagram._internalSelection) {
                            diagram._selectionChanged(selected, deselected);
                        }
                        return true;
                    }
                }
            },
            rotate: function (angle, center, undoable) {
                var rotate = this.visual.rotate();
                if (angle !== undefined) {
                    if (undoable !== false && this.diagram && this.diagram.undoRedoService && angle !== rotate.angle) {
                        this.diagram.undoRedoService.add(new diagram.RotateUnit(this.diagram._resizingAdorner, [this], [rotate.angle]), false);
                    }
                    var b = this.bounds(), sc = new Point(b.width / 2, b.height / 2), deltaAngle, newPosition;
                    if (center) {
                        deltaAngle = angle - rotate.angle;
                        newPosition = b.center().rotate(center, 360 - deltaAngle).minus(sc);
                        this._rotationOffset = this._rotationOffset.plus(newPosition.minus(b.topLeft()));
                        this.position(newPosition);
                    }
                    this.visual.rotate(angle, sc);
                    this.options.rotation.angle = angle;
                    if (this.diagram && this.diagram._connectorsAdorner) {
                        this.diagram._connectorsAdorner.refresh();
                    }
                    this.refreshConnections();
                    if (this.diagram) {
                        this.diagram.trigger(ITEMROTATE, { item: this });
                    }
                }
                return rotate;
            },
            connections: function (type) {
                var result = [], i, j, con, cons, ctr;
                for (i = 0; i < this.connectors.length; i++) {
                    ctr = this.connectors[i];
                    cons = ctr.connections;
                    for (j = 0, cons; j < cons.length; j++) {
                        con = cons[j];
                        if (type == 'out') {
                            var source = con.source();
                            if (source.shape && source.shape == this) {
                                result.push(con);
                            }
                        } else if (type == 'in') {
                            var target = con.target();
                            if (target.shape && target.shape == this) {
                                result.push(con);
                            }
                        } else {
                            result.push(con);
                        }
                    }
                }
                return result;
            },
            refreshConnections: function () {
                $.each(this.connections(), function () {
                    this.refresh();
                });
            },
            getConnector: function (nameOrPoint) {
                var i, ctr;
                if (isString(nameOrPoint)) {
                    nameOrPoint = nameOrPoint.toLocaleLowerCase();
                    for (i = 0; i < this.connectors.length; i++) {
                        ctr = this.connectors[i];
                        if (ctr.options.name.toLocaleLowerCase() == nameOrPoint) {
                            return ctr;
                        }
                    }
                } else if (nameOrPoint instanceof Point) {
                    return closestConnector(nameOrPoint, this.connectors);
                } else {
                    return this.connectors.length ? this.connectors[0] : null;
                }
            },
            getPosition: function (side) {
                var b = this.bounds(), fnName = side.charAt(0).toLowerCase() + side.slice(1);
                if (isFunction(b[fnName])) {
                    return this._transformPoint(b[fnName]());
                }
                return b.center();
            },
            redraw: function (options) {
                if (options) {
                    var shapeOptions = this.options;
                    var boundsChange;
                    this.shapeVisual.redraw(this._visualOptions(options));
                    if (this._diffNumericOptions(options, [
                            WIDTH,
                            HEIGHT,
                            X,
                            Y
                        ])) {
                        this.bounds(new Rect(shapeOptions.x, shapeOptions.y, shapeOptions.width, shapeOptions.height));
                        boundsChange = true;
                    }
                    if (options.connectors) {
                        shapeOptions.connectors = options.connectors;
                        this._updateConnectors();
                    }
                    shapeOptions = deepExtend(shapeOptions, options);
                    if (options.rotation || boundsChange) {
                        this._rotate();
                    }
                    if (shapeOptions.content) {
                        this.content(shapeOptions.content);
                    }
                }
            },
            _updateConnectors: function () {
                var connections = this.connections();
                this.connectors = [];
                this._createConnectors();
                var connection;
                var source;
                var target;
                for (var idx = 0; idx < connections.length; idx++) {
                    connection = connections[idx];
                    source = connection.source();
                    target = connection.target();
                    if (source.shape && source.shape === this) {
                        connection.source(this.getConnector(source.options.name) || null);
                    } else if (target.shape && target.shape === this) {
                        connection.target(this.getConnector(target.options.name) || null);
                    }
                    connection.updateModel();
                }
            },
            _diffNumericOptions: diagram.diffNumericOptions,
            _visualOptions: function (options) {
                return {
                    data: options.path,
                    source: options.source,
                    hover: options.hover,
                    fill: options.fill,
                    stroke: options.stroke
                };
            },
            _triggerBoundsChange: function () {
                if (this.diagram) {
                    this.diagram.trigger(ITEMBOUNDSCHANGE, {
                        item: this,
                        bounds: this._bounds.clone()
                    });
                }
            },
            _transformPoint: function (point) {
                var rotate = this.rotate(), bounds = this.bounds(), tl = bounds.topLeft();
                if (rotate.angle) {
                    point.rotate(rotate.center().plus(tl), 360 - rotate.angle);
                }
                return point;
            },
            _transformedBounds: function () {
                var bounds = this.bounds(), tl = bounds.topLeft(), br = bounds.bottomRight();
                return Rect.fromPoints(this.diagram.modelToView(tl), this.diagram.modelToView(br));
            },
            _rotatedBounds: function () {
                var bounds = this.bounds().rotatedBounds(this.rotate().angle), tl = bounds.topLeft(), br = bounds.bottomRight();
                return Rect.fromPoints(tl, br);
            },
            _rotate: function () {
                var rotation = this.options.rotation;
                if (rotation && rotation.angle) {
                    this.rotate(rotation.angle);
                }
                this._rotationOffset = new Point();
            },
            _hover: function (value) {
                var options = this.options, hover = options.hover, stroke = options.stroke, fill = options.fill;
                if (value && isDefined(hover.stroke)) {
                    stroke = deepExtend({}, stroke, hover.stroke);
                }
                if (value && isDefined(hover.fill)) {
                    fill = hover.fill;
                }
                this.shapeVisual.redraw({
                    stroke: stroke,
                    fill: fill
                });
                if (options.editable && options.editable.connect) {
                    this.diagram._showConnectors(this, value);
                }
            },
            _hitTest: function (value) {
                if (this.visible()) {
                    var bounds = this.bounds(), rotatedPoint, angle = this.rotate().angle;
                    if (value.isEmpty && !value.isEmpty()) {
                        return Intersect.rects(value, bounds, angle ? angle : 0);
                    } else {
                        rotatedPoint = value.clone().rotate(bounds.center(), angle);
                        if (bounds.contains(rotatedPoint)) {
                            return this;
                        }
                    }
                }
            },
            toJSON: function () {
                return { shapeId: this.options.id };
            },
            createShapeVisual: function () {
                var options = this.options;
                var visualOptions = this._visualOptions(options);
                var visualTemplate = options.visual;
                var type = (options.type + '').toLocaleLowerCase();
                var shapeVisual;
                visualOptions.width = options.width;
                visualOptions.height = options.height;
                if (isFunction(visualTemplate)) {
                    shapeVisual = visualTemplate.call(this, options);
                } else if (visualOptions.data) {
                    shapeVisual = new Path(visualOptions);
                    translateToOrigin(shapeVisual);
                } else if (type == 'rectangle') {
                    shapeVisual = new Rectangle(visualOptions);
                } else if (type == 'circle') {
                    shapeVisual = new Circle(visualOptions);
                } else if (type == 'text') {
                    shapeVisual = new TextBlock(visualOptions);
                } else if (type == 'image') {
                    shapeVisual = new Image(visualOptions);
                } else {
                    shapeVisual = new Path(visualOptions);
                }
                this.shapeVisual = shapeVisual;
                this.visual.append(this.shapeVisual);
            }
        });
        var Connection = DiagramElement.extend({
            init: function (from, to, options) {
                var that = this;
                DiagramElement.fn.init.call(that, options);
                this.updateOptionsFromModel();
                this._initRouter();
                that.path = new diagram.Polyline(that.options);
                that.path.fill(TRANSPARENT);
                that.visual.append(that.path);
                that._sourcePoint = that._targetPoint = new Point();
                that._setSource(from);
                that._setTarget(to);
                that.content(that.options.content);
                that.definers = [];
                if (defined(options) && options.points) {
                    that.points(options.points);
                }
            },
            options: {
                hover: { stroke: {} },
                startCap: NONE,
                endCap: NONE,
                points: [],
                selectable: true,
                fromConnector: AUTO,
                toConnector: AUTO
            },
            _setOptionsFromModel: function (model) {
                this.updateOptionsFromModel(model || this.dataItem);
            },
            updateOptionsFromModel: function (model) {
                if (this.diagram && this.diagram._isEditable) {
                    var dataMap = this.diagram._dataMap;
                    var options = filterConnectionDataItem(model || this.dataItem);
                    if (model) {
                        if (defined(options.from)) {
                            var from = dataMap[options.from];
                            if (from && defined(options.fromConnector)) {
                                from = from.getConnector(options.fromConnector);
                            }
                            this.source(from);
                        } else if (defined(options.fromX) && defined(options.fromY)) {
                            this.source(new Point(options.fromX, options.fromY));
                        }
                        if (defined(options.to)) {
                            var to = dataMap[options.to];
                            if (to && defined(options.toConnector)) {
                                to = to.getConnector(options.toConnector);
                            }
                            this.target(to);
                        } else if (defined(options.toX) && defined(options.toY)) {
                            this.target(new Point(options.toX, options.toY));
                        }
                        if (defined(options.type) && this.type() !== options.type) {
                            this.points([]);
                            this.type(options.type);
                        }
                        this.dataItem = model;
                        this._template();
                        this.redraw(this.options);
                    } else {
                        this.options = deepExtend({}, options, this.options);
                    }
                }
            },
            updateModel: function (syncChanges) {
                if (this.diagram && this.diagram._isEditable) {
                    if (this.diagram.connectionsDataSource) {
                        var model = this.diagram.connectionsDataSource.getByUid(this.dataItem.uid);
                        if (model) {
                            this.diagram._suspendModelRefresh();
                            if (defined(this.options.fromX) && this.options.fromX !== null) {
                                clearField('from', model);
                                clearField('fromConnector', model);
                                model.set('fromX', this.options.fromX);
                                model.set('fromY', this.options.fromY);
                            } else {
                                model.set('from', this.options.from);
                                if (defined(model.fromConnector)) {
                                    model.set('fromConnector', this.sourceConnector ? this.sourceConnector.options.name : null);
                                }
                                clearField('fromX', model);
                                clearField('fromY', model);
                            }
                            if (defined(this.options.toX) && this.options.toX !== null) {
                                clearField('to', model);
                                clearField('toConnector', model);
                                model.set('toX', this.options.toX);
                                model.set('toY', this.options.toY);
                            } else {
                                model.set('to', this.options.to);
                                if (defined(model.toConnector)) {
                                    model.set('toConnector', this.targetConnector ? this.targetConnector.options.name : null);
                                }
                                clearField('toX', model);
                                clearField('toY', model);
                            }
                            if (defined(this.options.type) && defined(model.type)) {
                                model.set('type', this.options.type);
                            }
                            this.dataItem = model;
                            this.diagram._resumeModelRefresh();
                            if (syncChanges) {
                                this.diagram._syncConnectionChanges();
                            }
                        }
                    }
                }
            },
            sourcePoint: function () {
                return this._resolvedSourceConnector ? this._resolvedSourceConnector.position() : this._sourcePoint;
            },
            _setSource: function (source) {
                var shapeSource = source instanceof Shape;
                var defaultConnector = this.options.fromConnector || AUTO;
                var dataItem;
                if (shapeSource && !source.getConnector(defaultConnector)) {
                    return;
                }
                if (source !== undefined) {
                    this.from = source;
                }
                this._removeFromSourceConnector();
                if (source === null) {
                    if (this.sourceConnector) {
                        this._sourcePoint = (this._resolvedSourceConnector || this.sourceConnector).position();
                        this._clearSourceConnector();
                        this._setFromOptions(null, this._sourcePoint);
                    }
                } else if (source instanceof Connector) {
                    dataItem = source.shape.dataItem;
                    if (dataItem) {
                        this._setFromOptions(dataItem.id);
                    }
                    this.sourceConnector = source;
                    this.sourceConnector.connections.push(this);
                } else if (source instanceof Point) {
                    this._setFromOptions(null, source);
                    this._sourcePoint = source;
                    if (this.sourceConnector) {
                        this._clearSourceConnector();
                    }
                } else if (shapeSource) {
                    dataItem = source.dataItem;
                    if (dataItem) {
                        this._setFromOptions(dataItem.id);
                    }
                    this.sourceConnector = source.getConnector(defaultConnector);
                    this.sourceConnector.connections.push(this);
                }
            },
            source: function (source, undoable) {
                if (isDefined(source)) {
                    if (undoable && this.diagram) {
                        this.diagram.undoRedoService.addCompositeItem(new diagram.ConnectionEditUnit(this, source));
                    }
                    this._setSource(source);
                    this.refresh();
                }
                return this.sourceConnector ? this.sourceConnector : this._sourcePoint;
            },
            _setFromOptions: function (from, fromPoint) {
                this.options.from = from;
                if (fromPoint) {
                    this.options.fromX = fromPoint.x;
                    this.options.fromY = fromPoint.y;
                } else {
                    this.options.fromX = null;
                    this.options.fromY = null;
                }
            },
            sourceDefiner: function (value) {
                if (value) {
                    if (value instanceof diagram.PathDefiner) {
                        value.left = null;
                        this._sourceDefiner = value;
                        this.source(value.point);
                    } else {
                        throw 'The sourceDefiner needs to be a PathDefiner.';
                    }
                } else {
                    if (!this._sourceDefiner) {
                        this._sourceDefiner = new diagram.PathDefiner(this.sourcePoint(), null, null);
                    }
                    return this._sourceDefiner;
                }
            },
            targetPoint: function () {
                return this._resolvedTargetConnector ? this._resolvedTargetConnector.position() : this._targetPoint;
            },
            _setTarget: function (target) {
                var shapeTarget = target instanceof Shape;
                var defaultConnector = this.options.toConnector || AUTO;
                var dataItem;
                if (shapeTarget && !target.getConnector(defaultConnector)) {
                    return;
                }
                if (target !== undefined) {
                    this.to = target;
                }
                this._removeFromTargetConnector();
                if (target === null) {
                    if (this.targetConnector) {
                        this._targetPoint = (this._resolvedTargetConnector || this.targetConnector).position();
                        this._clearTargetConnector();
                        this._setToOptions(null, this._targetPoint);
                    }
                } else if (target instanceof Connector) {
                    dataItem = target.shape.dataItem;
                    if (dataItem) {
                        this._setToOptions(dataItem.id);
                    }
                    this.targetConnector = target;
                    this.targetConnector.connections.push(this);
                } else if (target instanceof Point) {
                    this._setToOptions(null, target);
                    this._targetPoint = target;
                    if (this.targetConnector) {
                        this._clearTargetConnector();
                    }
                } else if (shapeTarget) {
                    dataItem = target.dataItem;
                    if (dataItem) {
                        this._setToOptions(dataItem.id);
                    }
                    this.targetConnector = target.getConnector(defaultConnector);
                    this.targetConnector.connections.push(this);
                }
            },
            target: function (target, undoable) {
                if (isDefined(target)) {
                    if (undoable && this.diagram) {
                        this.diagram.undoRedoService.addCompositeItem(new diagram.ConnectionEditUnit(this, undefined, target));
                    }
                    this._setTarget(target);
                    this.refresh();
                }
                return this.targetConnector ? this.targetConnector : this._targetPoint;
            },
            _setToOptions: function (to, toPoint) {
                this.options.to = to;
                if (toPoint) {
                    this.options.toX = toPoint.x;
                    this.options.toY = toPoint.y;
                } else {
                    this.options.toX = null;
                    this.options.toY = null;
                }
            },
            targetDefiner: function (value) {
                if (value) {
                    if (value instanceof diagram.PathDefiner) {
                        value.right = null;
                        this._targetDefiner = value;
                        this.target(value.point);
                    } else {
                        throw 'The sourceDefiner needs to be a PathDefiner.';
                    }
                } else {
                    if (!this._targetDefiner) {
                        this._targetDefiner = new diagram.PathDefiner(this.targetPoint(), null, null);
                    }
                    return this._targetDefiner;
                }
            },
            _updateConnectors: function () {
                this._updateConnector(this.source(), 'source');
                this._updateConnector(this.target(), 'target');
            },
            _updateConnector: function (instance, name) {
                var that = this;
                var diagram = that.diagram;
                if (instance instanceof Connector && !diagram.getShapeById(instance.shape.id)) {
                    var dataItem = instance.shape.dataItem;
                    var connectorName = instance.options.name;
                    var setNewTarget = function () {
                        var shape = diagram._dataMap[dataItem.id];
                        instance = shape.getConnector(connectorName);
                        that[name](instance, false);
                        that.updateModel();
                    };
                    if (diagram._dataMap[dataItem.id]) {
                        setNewTarget();
                    } else {
                        var inactiveItem = diagram._inactiveShapeItems.getByUid(dataItem.uid);
                        if (inactiveItem) {
                            diagram._deferredConnectionUpdates.push(inactiveItem.onActivate(setNewTarget));
                        }
                    }
                } else {
                    that[name](instance, false);
                }
            },
            content: function (content) {
                var result = this._content(content);
                if (defined(content)) {
                    this._alignContent();
                }
                return result;
            },
            _createContentVisual: function (options) {
                var visual;
                if (isFunction(options.visual)) {
                    visual = options.visual.call(this, options);
                } else if (options.text) {
                    visual = new TextBlock(options);
                }
                if (visual) {
                    this._contentVisual = visual;
                    visual._includeInBBox = false;
                    this.visual.append(visual);
                }
                return visual;
            },
            _updateContentVisual: function (options) {
                if (isFunction(options.visual)) {
                    this.visual.remove(this._contentVisual);
                    this._createContentVisual(options);
                } else {
                    this._contentVisual.redraw(options);
                }
            },
            _alignContent: function () {
                if (this._contentVisual) {
                    var offset = CONNECTION_CONTENT_OFFSET;
                    var points = this.allPoints();
                    var endIdx = math.floor(points.length / 2);
                    var startIdx = endIdx - 1;
                    while (startIdx > 0 && points[startIdx].equals(points[endIdx])) {
                        startIdx--;
                        endIdx++;
                    }
                    var endPoint = points[endIdx];
                    var startPoint = points[startIdx];
                    var boundingBox = this._contentVisual._measure();
                    var width = boundingBox.width;
                    var height = boundingBox.height;
                    var alignToPath = points.length % 2 === 0;
                    var distance = startPoint.distanceTo(endPoint);
                    if (alignToPath && points.length > 2 && distance > 0 && (startPoint.y === endPoint.y && distance < width || startPoint.x === endPoint.x && distance < height)) {
                        alignToPath = false;
                        offset = 0;
                    }
                    var point;
                    if (alignToPath) {
                        var angle = draw.util.deg(math.atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x));
                        point = new Point((endPoint.x - startPoint.x) / 2 + startPoint.x, (endPoint.y - startPoint.y) / 2 + startPoint.y);
                        if (math.abs(angle) === 90) {
                            point.x += offset;
                            point.y -= height / 2;
                        } else if (angle % 180 === 0) {
                            point.x -= width / 2;
                            point.y -= height + offset;
                        } else if (angle < -90 || 0 < angle && angle < 90) {
                            point.y -= height;
                        } else if (angle < 0 || angle > 90) {
                            point.x -= width;
                            point.y -= height;
                        }
                    } else {
                        var midIdx = math.floor(points.length / 2);
                        point = points[midIdx].clone();
                        startPoint = points[midIdx - 1];
                        endPoint = points[midIdx + 1];
                        var offsetX = startPoint.x <= point.x && endPoint.x <= point.x ? offset : -boundingBox.width - offset;
                        var offsetY = startPoint.y <= point.y && endPoint.y <= point.y ? offset : -boundingBox.height - offset;
                        point.x += offsetX;
                        point.y += offsetY;
                    }
                    this._contentVisual.position(point);
                }
            },
            select: function (value) {
                var diagram = this.diagram, selected, deselected;
                if (this._canSelect()) {
                    if (this.isSelected !== value) {
                        this.isSelected = value;
                        selected = [];
                        deselected = [];
                        if (this.isSelected) {
                            this.adorner = new ConnectionEditAdorner(this, this.options.selection);
                            diagram._adorn(this.adorner, true);
                            diagram._selectedItems.push(this);
                            selected.push(this);
                        } else {
                            if (this.adorner) {
                                diagram._adorn(this.adorner, false);
                                Utils.remove(diagram._selectedItems, this);
                                this.adorner = undefined;
                                deselected.push(this);
                            }
                        }
                        if (this.adorner) {
                            this.adorner.refresh();
                        }
                        if (!diagram._internalSelection) {
                            diagram._selectionChanged(selected, deselected);
                        }
                        return true;
                    }
                }
            },
            bounds: function (value) {
                if (value && !isString(value)) {
                    this._bounds = value;
                } else {
                    return this._bounds;
                }
            },
            type: function (value) {
                var options = this.options;
                if (value) {
                    if (value !== options.type) {
                        options.type = value;
                        this._initRouter();
                        this.refresh();
                    }
                } else {
                    return options.type;
                }
            },
            _initRouter: function () {
                var type = (this.options.type || '').toLowerCase();
                if (type == CASCADING) {
                    this._router = new CascadingRouter(this);
                } else {
                    this._router = new PolylineRouter(this);
                }
            },
            points: function (value) {
                if (value) {
                    this.definers = [];
                    for (var i = 0; i < value.length; i++) {
                        var definition = value[i];
                        if (definition instanceof diagram.Point) {
                            this.definers.push(new diagram.PathDefiner(definition));
                        } else if (definition.hasOwnProperty('x') && definition.hasOwnProperty('y')) {
                            this.definers.push(new diagram.PathDefiner(new Point(definition.x, definition.y)));
                        } else {
                            throw 'A Connection point needs to be a Point or an object with x and y properties.';
                        }
                    }
                } else {
                    var pts = [];
                    if (isDefined(this.definers)) {
                        for (var k = 0; k < this.definers.length; k++) {
                            pts.push(this.definers[k].point);
                        }
                    }
                    return pts;
                }
            },
            allPoints: function () {
                var pts = [this.sourcePoint()];
                if (this.definers) {
                    for (var k = 0; k < this.definers.length; k++) {
                        pts.push(this.definers[k].point);
                    }
                }
                pts.push(this.targetPoint());
                return pts;
            },
            refresh: function () {
                this._resolveConnectors();
                this._refreshPath();
                this._alignContent();
                if (this.adorner) {
                    this.adorner.refresh();
                }
            },
            _resolveConnectors: function () {
                var connection = this, sourcePoint, targetPoint, sourceConnectors, targetConnectors, source = connection.source(), target = connection.target();
                if (source instanceof Point) {
                    sourcePoint = source;
                } else if (source instanceof Connector) {
                    if (isAutoConnector(source)) {
                        sourceConnectors = source.shape.connectors;
                    } else {
                        sourceConnectors = [source];
                    }
                }
                if (target instanceof Point) {
                    targetPoint = target;
                } else if (target instanceof Connector) {
                    if (isAutoConnector(target)) {
                        targetConnectors = target.shape.connectors;
                    } else {
                        targetConnectors = [target];
                    }
                }
                if (sourcePoint) {
                    if (targetConnectors) {
                        connection._resolvedTargetConnector = closestConnector(sourcePoint, targetConnectors);
                    }
                } else if (sourceConnectors) {
                    if (targetPoint) {
                        connection._resolvedSourceConnector = closestConnector(targetPoint, sourceConnectors);
                    } else if (targetConnectors) {
                        this._resolveAutoConnectors(sourceConnectors, targetConnectors);
                    }
                }
            },
            _resolveAutoConnectors: function (sourceConnectors, targetConnectors) {
                var minNonConflict = MAXINT;
                var minDist = MAXINT;
                var minNonConflictSource, minNonConflictTarget;
                var sourcePoint, targetPoint;
                var minSource, minTarget;
                var sourceConnector, targetConnector;
                var sourceIdx, targetIdx;
                var dist;
                for (sourceIdx = 0; sourceIdx < sourceConnectors.length; sourceIdx++) {
                    sourceConnector = sourceConnectors[sourceIdx];
                    if (!isAutoConnector(sourceConnector)) {
                        sourcePoint = sourceConnector.position();
                        for (targetIdx = 0; targetIdx < targetConnectors.length; targetIdx++) {
                            targetConnector = targetConnectors[targetIdx];
                            if (!isAutoConnector(targetConnector)) {
                                targetPoint = targetConnector.position();
                                dist = math.round(sourcePoint.distanceTo(targetPoint));
                                if (dist < minNonConflict && this.diagram && this._testRoutePoints(sourcePoint, targetPoint, sourceConnector, targetConnector)) {
                                    minNonConflict = dist;
                                    minNonConflictSource = sourceConnector;
                                    minNonConflictTarget = targetConnector;
                                }
                                if (dist < minDist) {
                                    minSource = sourceConnector;
                                    minTarget = targetConnector;
                                    minDist = dist;
                                }
                            }
                        }
                    }
                }
                if (minNonConflictSource) {
                    minSource = minNonConflictSource;
                    minTarget = minNonConflictTarget;
                }
                this._resolvedSourceConnector = minSource;
                this._resolvedTargetConnector = minTarget;
            },
            _testRoutePoints: function (sourcePoint, targetPoint, sourceConnector, targetConnector) {
                var router = this._router;
                var passRoute = true;
                if (router instanceof CascadingRouter) {
                    var points = router.routePoints(sourcePoint, targetPoint, sourceConnector, targetConnector), start, end, rect, exclude;
                    exclude = this._getRouteExclude(sourcePoint, targetPoint, sourceConnector.shape, targetConnector.shape);
                    points.unshift(sourcePoint);
                    points.push(targetPoint);
                    for (var idx = 1; idx < points.length; idx++) {
                        start = points[idx - 1];
                        end = points[idx];
                        rect = new Rect(math.min(start.x, end.x), math.min(start.y, end.y), math.abs(start.x - end.x), math.abs(start.y - end.y));
                        if (rect.width > 0) {
                            rect.x++;
                            rect.width -= 2;
                        }
                        if (rect.height > 0) {
                            rect.y++;
                            rect.height -= 2;
                        }
                        if (!rect.isEmpty() && this.diagram._shapesQuadTree.hitTestRect(rect, exclude)) {
                            passRoute = false;
                            break;
                        }
                    }
                }
                return passRoute;
            },
            _getRouteExclude: function (sourcePoint, targetPoint, sourceShape, targetShape) {
                var exclude = [];
                if (this._isPointInsideShape(sourcePoint, sourceShape)) {
                    exclude.push(sourceShape);
                }
                if (this._isPointInsideShape(targetPoint, targetShape)) {
                    exclude.push(targetShape);
                }
                return exclude;
            },
            _isPointInsideShape: function (point, shape) {
                var bounds = shape.bounds(), rotatedPoint, angle = shape.rotate().angle, pointX, pointY, boundsX = bounds.x, boundsY = bounds.y;
                rotatedPoint = point.clone().rotate(bounds.center(), angle);
                pointX = rotatedPoint.x;
                pointY = rotatedPoint.y;
                return pointX > boundsX && pointX < boundsX + bounds.width && pointY > boundsY && pointY < boundsY + bounds.height;
            },
            redraw: function (options) {
                if (options) {
                    this.options = deepExtend({}, this.options, options);
                    var points = this.options.points;
                    if (defined(points) && points.length > 0) {
                        this.points(points);
                        this._refreshPath();
                    }
                    if (options && options.content || options.text) {
                        this.content(options.content);
                    }
                    this.path.redraw({
                        fill: options.fill,
                        stroke: options.stroke,
                        startCap: options.startCap,
                        endCap: options.endCap
                    });
                }
            },
            clone: function () {
                var json = this.serialize();
                if (this.diagram && this.diagram._isEditable && defined(this.dataItem)) {
                    json.options.dataItem = cloneDataItem(this.dataItem);
                }
                return new Connection(this.from, this.to, json.options);
            },
            serialize: function () {
                var from = this.from.toJSON ? this.from.toJSON : this.from.toString(), to = this.to.toJSON ? this.to.toJSON : this.to.toString();
                var json = deepExtend({}, {
                    options: this.options,
                    from: from,
                    to: to
                });
                if (defined(this.dataItem)) {
                    json.dataItem = this.dataItem.toString();
                }
                json.options.points = this.points();
                return json;
            },
            _hitTest: function (value) {
                if (this.visible()) {
                    var p = new Point(value.x, value.y), from = this.sourcePoint(), to = this.targetPoint();
                    if (value.isEmpty && !value.isEmpty() && value.contains(from) && value.contains(to)) {
                        return this;
                    }
                    if (this._router.hitTest(p)) {
                        return this;
                    }
                }
            },
            _hover: function (value) {
                var color = (this.options.stroke || {}).color;
                if (value && isDefined(this.options.hover.stroke.color)) {
                    color = this.options.hover.stroke.color;
                }
                this.path.redraw({ stroke: { color: color } });
            },
            _refreshPath: function () {
                if (!defined(this.path)) {
                    return;
                }
                this._drawPath();
                this.bounds(this._router.getBounds());
            },
            _drawPath: function () {
                if (this._router) {
                    this._router.route();
                }
                var source = this.sourcePoint();
                var target = this.targetPoint();
                var points = this.points();
                this.path.redraw({ points: [source].concat(points, [target]) });
            },
            _clearSourceConnector: function () {
                this.sourceConnector = undefined;
                this._resolvedSourceConnector = undefined;
            },
            _clearTargetConnector: function () {
                this.targetConnector = undefined;
                this._resolvedTargetConnector = undefined;
            },
            _removeFromSourceConnector: function () {
                if (this.sourceConnector) {
                    Utils.remove(this.sourceConnector.connections, this);
                }
            },
            _removeFromTargetConnector: function () {
                if (this.targetConnector) {
                    Utils.remove(this.targetConnector.connections, this);
                }
            },
            toJSON: function () {
                var connection = this;
                var from, to, point;
                if (connection.from && connection.from.toJSON) {
                    from = connection.from.toJSON();
                } else {
                    point = connection._sourcePoint;
                    from = {
                        x: point.x,
                        y: point.y
                    };
                }
                if (connection.to && connection.to.toJSON) {
                    to = connection.to.toJSON();
                } else {
                    point = connection._targetPoint;
                    to = {
                        x: point.x,
                        y: point.y
                    };
                }
                return {
                    from: from,
                    to: to
                };
            }
        });
        var Diagram = Widget.extend({
            init: function (element, userOptions) {
                var that = this;
                kendo.destroy(element);
                Widget.fn.init.call(that, element, userOptions);
                that._initTheme();
                that._initElements();
                that._extendLayoutOptions(that.options);
                that._initDefaults(userOptions);
                that._interactionDefaults();
                that._initCanvas();
                that.mainLayer = new Group({ id: 'main-layer' });
                that.canvas.append(that.mainLayer);
                that._shapesQuadTree = new ShapesQuadTree(that);
                that._pan = new Point();
                that._adorners = [];
                that.adornerLayer = new Group({ id: 'adorner-layer' });
                that.canvas.append(that.adornerLayer);
                that._createHandlers();
                that._initialize();
                that._resizingAdorner = new ResizingAdorner(that, { editable: that.options.editable });
                that._connectorsAdorner = new ConnectorsAdorner(that);
                that._adorn(that._resizingAdorner, true);
                that._adorn(that._connectorsAdorner, true);
                that.selector = new Selector(that);
                that._clipboard = [];
                that.pauseMouseHandlers = false;
                that._fetchFreshData();
                that._createGlobalToolBar();
                that._createOptionElements();
                that.zoom(that.options.zoom);
                that.canvas.draw();
            },
            options: {
                name: 'Diagram',
                theme: 'default',
                layout: '',
                zoomRate: 0.1,
                zoom: 1,
                zoomMin: 0,
                zoomMax: 2,
                dataSource: {},
                draggable: true,
                template: '',
                autoBind: true,
                editable: {
                    rotate: {},
                    resize: {},
                    text: true,
                    tools: [],
                    drag: {
                        snap: {
                            size: 10,
                            angle: 10
                        }
                    },
                    remove: true
                },
                pannable: {},
                selectable: { key: 'none' },
                tooltip: {
                    enabled: true,
                    format: '{0}'
                },
                copy: {
                    enabled: true,
                    offsetX: 20,
                    offsetY: 20
                },
                shapeDefaults: diagram.shapeDefaults({ undoable: true }),
                connectionDefaults: {
                    editable: { tools: [] },
                    type: CASCADING
                },
                shapes: [],
                connections: []
            },
            events: [
                ZOOM_END,
                ZOOM_START,
                PAN,
                SELECT,
                ITEMROTATE,
                ITEMBOUNDSCHANGE,
                CHANGE,
                CLICK,
                MOUSE_ENTER,
                MOUSE_LEAVE,
                'toolBarClick',
                'save',
                'cancel',
                'edit',
                'remove',
                'add',
                'dataBound',
                DRAG_START,
                DRAG,
                DRAG_END
            ],
            items: function () {
                return $();
            },
            _createGlobalToolBar: function () {
                var editable = this.options.editable;
                if (editable) {
                    var tools = editable.tools;
                    if (this._isEditable && tools !== false && (!tools || tools.length === 0)) {
                        tools = [
                            'createShape',
                            'undo',
                            'redo',
                            'rotateClockwise',
                            'rotateAnticlockwise'
                        ];
                    }
                    if (tools && tools.length) {
                        this.toolBar = new DiagramToolBar(this, {
                            tools: tools || {},
                            click: proxy(this._toolBarClick, this),
                            modal: false
                        });
                        this.toolBar.element.css({ textAlign: 'left' });
                        this.element.prepend(this.toolBar.element);
                        this._resize();
                    }
                }
            },
            createShape: function () {
                if (this.editor && this.editor.end() || !this.editor) {
                    var dataSource = this.dataSource;
                    var view = dataSource.view() || [];
                    var index = view.length;
                    var model = createModel(dataSource, {});
                    var shape = this._createShape(model, {});
                    if (!this.trigger('add', { shape: shape })) {
                        dataSource.insert(index, model);
                        var inactiveItem = this._inactiveShapeItems.getByUid(model.uid);
                        inactiveItem.element = shape;
                        this.edit(shape);
                    }
                }
            },
            _createShape: function (dataItem, options) {
                options = deepExtend({}, this.options.shapeDefaults, options);
                options.dataItem = dataItem;
                var shape = new Shape(options, this);
                return shape;
            },
            createConnection: function () {
                if (this.editor && this.editor.end() || !this.editor) {
                    var connectionsDataSource = this.connectionsDataSource;
                    var view = connectionsDataSource.view() || [];
                    var index = view.length;
                    var model = createModel(connectionsDataSource, {});
                    var connection = this._createConnection(model);
                    if (!this.trigger('add', { connection: connection })) {
                        this._connectionsDataMap[model.uid] = connection;
                        connectionsDataSource.insert(index, model);
                        this.addConnection(connection, false);
                        this.edit(connection);
                    }
                }
            },
            _createConnection: function (dataItem, source, target) {
                var options = deepExtend({}, this.options.connectionDefaults);
                options.dataItem = dataItem;
                var connection = new Connection(source || new Point(), target || new Point(), options);
                return connection;
            },
            editModel: function (dataItem, editorType) {
                this.cancelEdit();
                var editors, template;
                var editable = this.options.editable;
                if (editorType == 'shape') {
                    editors = editable.shapeEditors;
                    template = editable.shapeTemplate;
                } else if (editorType == 'connection') {
                    var connectionSelectorHandler = proxy(connectionSelector, this);
                    editors = deepExtend({}, {
                        from: connectionSelectorHandler,
                        to: connectionSelectorHandler
                    }, editable.connectionEditors);
                    template = editable.connectionTemplate;
                } else {
                    return;
                }
                this.editor = new PopupEditor(this.element, {
                    update: proxy(this._update, this),
                    cancel: proxy(this._cancel, this),
                    model: dataItem,
                    type: editorType,
                    target: this,
                    editors: editors,
                    template: template
                });
                this.trigger('edit', this._editArgs());
            },
            edit: function (item) {
                if (item.dataItem) {
                    var editorType = item instanceof Shape ? 'shape' : 'connection';
                    this.editModel(item.dataItem, editorType);
                }
            },
            cancelEdit: function () {
                if (this.editor) {
                    this._getEditDataSource().cancelChanges(this.editor.model);
                    this._destroyEditor();
                }
            },
            saveEdit: function () {
                if (this.editor && this.editor.end() && !this.trigger('save', this._editArgs())) {
                    this._getEditDataSource().sync();
                }
            },
            _update: function () {
                if (this.editor && this.editor.end() && !this.trigger('save', this._editArgs())) {
                    this._getEditDataSource().sync();
                    this._destroyEditor();
                }
            },
            _cancel: function () {
                if (this.editor && !this.trigger('cancel', this._editArgs())) {
                    var model = this.editor.model;
                    this._getEditDataSource().cancelChanges(model);
                    var element = this._connectionsDataMap[model.uid] || this._dataMap[model.id];
                    if (element) {
                        element._setOptionsFromModel(model);
                    }
                    this._destroyEditor();
                }
            },
            _getEditDataSource: function () {
                return this.editor.options.type === 'shape' ? this.dataSource : this.connectionsDataSource;
            },
            _editArgs: function () {
                var result = { container: this.editor.wrapper };
                result[this.editor.options.type] = this.editor.model;
                return result;
            },
            _destroyEditor: function () {
                if (this.editor) {
                    this.editor.close();
                    this.editor = null;
                }
            },
            _initElements: function () {
                this.wrapper = this.element.empty().css('position', 'relative').attr('tabindex', 0).addClass('k-widget k-diagram');
                this.scrollable = $('<div />').appendTo(this.element);
            },
            _initDefaults: function (userOptions) {
                var options = this.options;
                var editable = options.editable;
                var shapeDefaults = options.shapeDefaults;
                var connectionDefaults = options.connectionDefaults;
                var userShapeDefaults = (userOptions || {}).shapeDefaults;
                if (editable === false) {
                    shapeDefaults.editable = false;
                    connectionDefaults.editable = false;
                } else {
                    copyDefaultOptions(editable, shapeDefaults.editable, [
                        'drag',
                        'remove',
                        'connect'
                    ]);
                    copyDefaultOptions(editable, connectionDefaults.editable, [
                        'drag',
                        'remove'
                    ]);
                }
                if (userShapeDefaults && userShapeDefaults.connectors) {
                    options.shapeDefaults.connectors = userShapeDefaults.connectors;
                }
            },
            _interactionDefaults: function () {
                var options = this.options;
                var selectable = options.selectable;
                var pannable = options.pannable;
                var mobile = kendo.support.mobileOS;
                if (selectable && !defined(selectable.multiple)) {
                    options.selectable = deepExtend({ multiple: mobile ? false : true }, options.selectable);
                }
                if (pannable && !defined(pannable.key)) {
                    options.pannable = deepExtend({ key: mobile ? 'none' : 'ctrl' }, options.pannable);
                }
            },
            _initCanvas: function () {
                var canvasContainer = $('<div class=\'k-layer\'></div>').appendTo(this.scrollable)[0];
                var viewPort = this.viewport();
                this.canvas = new Canvas(canvasContainer, {
                    width: viewPort.width || DEFAULT_CANVAS_WIDTH,
                    height: viewPort.height || DEFAULT_CANVAS_HEIGHT
                });
            },
            _createHandlers: function () {
                var that = this;
                var element = that.element;
                element.on(MOUSEWHEEL_NS, proxy(that._wheel, that)).on('keydown' + NS, proxy(that._keydown, that));
                that._userEvents = new kendo.UserEvents(this.scrollable, {
                    multiTouch: true,
                    fastTap: true,
                    tap: proxy(that._tap, that),
                    start: proxy(that._dragStart, that),
                    move: proxy(that._drag, that),
                    end: proxy(that._dragEnd, that),
                    gesturestart: proxy(that._gestureStart, that),
                    gesturechange: proxy(that._gestureChange, that),
                    gestureend: proxy(that._gestureEnd, that)
                });
                that.toolService = new ToolService(that);
                this.scrollable.on('mouseover' + NS, proxy(that._mouseover, that)).on('mouseout' + NS, proxy(that._mouseout, that)).on('mousemove' + NS, proxy(that._mouseMove, that)).on('mousedown' + NS, proxy(that._mouseDown, that)).on('mouseup' + NS, proxy(that._mouseUp, that));
                this._syncHandler = proxy(that._syncChanges, that);
                that._resizeHandler = proxy(that.resize, that, false);
                kendo.onResize(that._resizeHandler);
                this.bind(ZOOM_START, proxy(that._destroyToolBar, that));
                this.bind(PAN, proxy(that._destroyToolBar, that));
            },
            _dragStart: function (e) {
                this._pauseMouseHandlers = true;
                var point = this._eventPositions(e, true);
                var event = e.event;
                if (this.toolService.start(point, this._meta(event))) {
                    this._destroyToolBar();
                    event.preventDefault();
                }
            },
            _drag: function (e) {
                var p = this._eventPositions(e);
                var event = e.event;
                if (this.toolService.move(p, this._meta(event))) {
                    event.preventDefault();
                }
            },
            _dragEnd: function (e) {
                this._pauseMouseHandlers = false;
                var p = this._eventPositions(e);
                var event = e.event;
                if (this.toolService.end(p, this._meta(event))) {
                    this._createToolBar();
                    event.preventDefault();
                }
            },
            _mouseMove: function (e) {
                if (!this._pauseMouseHandlers) {
                    var p = this._eventPositions(e);
                    this.toolService._updateHoveredItem(p);
                    this.toolService._updateCursor(p);
                }
            },
            _mouseDown: function () {
                this._pauseMouseHandlers = true;
            },
            _mouseUp: function () {
                this._pauseMouseHandlers = false;
            },
            _tap: function (e) {
                var toolService = this.toolService;
                var selectable = this.options.selectable;
                var point = this._eventPositions(e);
                var focused = this.focus();
                toolService._updateHoveredItem(point);
                if (toolService.hoveredItem) {
                    var item = toolService.hoveredItem;
                    this.trigger('click', {
                        item: item,
                        point: point
                    });
                    if (selectable && item.options.selectable !== false) {
                        var multiple = selectable.multiple !== false;
                        var ctrlPressed = kendo.support.mobileOS || this._meta(e.event).ctrlKey;
                        if (item.isSelected) {
                            if (ctrlPressed) {
                                this._destroyToolBar();
                                item.select(false);
                            } else {
                                this._createToolBar(focused);
                            }
                        } else {
                            this._destroyToolBar();
                            this.select(item, { addToSelection: multiple && ctrlPressed });
                            this._createToolBar(focused);
                        }
                    }
                } else if (selectable) {
                    this._destroyToolBar();
                    this.deselect();
                }
            },
            _keydown: function (e) {
                if (this.toolService.keyDown(e.keyCode, this._meta(e))) {
                    e.preventDefault();
                }
            },
            _wheel: function (e) {
                var delta = mwDelta(e), p = this._eventPositions(e), meta = deepExtend(this._meta(e), { delta: delta });
                if (this.toolService.wheel(p, meta)) {
                    e.preventDefault();
                }
            },
            _meta: function (e) {
                return {
                    ctrlKey: e.ctrlKey,
                    metaKey: e.metaKey,
                    altKey: e.altKey,
                    shiftKey: e.shiftKey,
                    type: e.type
                };
            },
            _eventPositions: function (e, start) {
                var point;
                if (e.touch) {
                    var field = start ? 'startLocation' : 'location';
                    point = new Point(e.x[field], e.y[field]);
                } else {
                    var event = e.originalEvent;
                    point = new Point(event.pageX, event.pageY);
                }
                return this.documentToModel(point);
            },
            _gestureStart: function (e) {
                this._destroyToolBar();
                this.scroller.disable();
                var initialCenter = this.documentToModel(new Point(e.center.x, e.center.y));
                var eventArgs = {
                    point: initialCenter,
                    zoom: this.zoom()
                };
                if (this.trigger(ZOOM_START, eventArgs)) {
                    return;
                }
                this._gesture = e;
                this._initialCenter = initialCenter;
            },
            _gestureChange: function (e) {
                var previousGesture = this._gesture;
                var initialCenter = this._initialCenter;
                var center = this.documentToView(new Point(e.center.x, e.center.y));
                var scaleDelta = e.distance / previousGesture.distance;
                var zoom = this._zoom;
                var updateZoom = false;
                if (math.abs(scaleDelta - 1) >= MOBILE_ZOOM_RATE) {
                    this._zoom = zoom = this._getValidZoom(zoom * scaleDelta);
                    this.options.zoom = zoom;
                    this._gesture = e;
                    updateZoom = true;
                }
                var zoomedPoint = initialCenter.times(zoom);
                var pan = center.minus(zoomedPoint);
                if (updateZoom || this._pan.distanceTo(pan) >= MOBILE_PAN_DISTANCE) {
                    this._panTransform(pan);
                    this._updateAdorners();
                }
                e.preventDefault();
            },
            _gestureEnd: function () {
                if (this.options.pannable !== false) {
                    this.scroller.enable();
                }
                this.trigger(ZOOM_END, {
                    point: this._initialCenter,
                    zoom: this.zoom()
                });
            },
            _resize: function () {
                var viewport = this.viewport();
                if (this.canvas) {
                    this.canvas.size(viewport);
                }
                if (this.scrollable && this.toolBar) {
                    this.scrollable.height(viewport.height);
                }
            },
            _mouseover: function (e) {
                var node = e.target._kendoNode;
                if (node && node.srcElement._hover) {
                    node.srcElement._hover(true, node.srcElement);
                }
            },
            _mouseout: function (e) {
                var node = e.target._kendoNode;
                if (node && node.srcElement._hover) {
                    node.srcElement._hover(false, node.srcElement);
                }
            },
            _initTheme: function () {
                var that = this, themes = dataviz.ui.themes || {}, themeName = ((that.options || {}).theme || '').toLowerCase(), themeOptions = (themes[themeName] || {}).diagram;
                that.options = deepExtend({}, themeOptions, that.options);
                if (that.options.editable === true) {
                    deepExtend(that.options, { editable: (themeOptions || {}).editable });
                }
            },
            _createOptionElements: function () {
                var options = this.options;
                var shapesLength = options.shapes.length;
                if (shapesLength) {
                    this._createShapes();
                }
                if (options.connections.length) {
                    this._createConnections();
                }
                if (shapesLength && options.layout) {
                    this.layout(options.layout);
                }
            },
            _createShapes: function () {
                var that = this, options = that.options, shapes = options.shapes, shape, i;
                for (i = 0; i < shapes.length; i++) {
                    shape = shapes[i];
                    that.addShape(shape);
                }
            },
            _createConnections: function () {
                var diagram = this, options = diagram.options, defaults = options.connectionDefaults, connections = options.connections, conn, source, target, i;
                for (i = 0; i < connections.length; i++) {
                    conn = connections[i];
                    source = diagram._findConnectionTarget(conn.from);
                    target = diagram._findConnectionTarget(conn.to);
                    diagram.connect(source, target, deepExtend({}, defaults, conn));
                }
            },
            _findConnectionTarget: function (options) {
                options = options || {};
                var diagram = this;
                var shapeId = isString(options) ? options : options.shapeId || options.id;
                var target;
                if (shapeId) {
                    target = diagram.getShapeById(shapeId);
                    if (options.connector) {
                        target = target.getConnector(options.connector);
                    }
                } else {
                    target = new Point(options.x || 0, options.y || 0);
                }
                return target;
            },
            destroy: function () {
                var that = this;
                Widget.fn.destroy.call(that);
                if (this._userEvents) {
                    this._userEvents.destroy();
                }
                kendo.unbindResize(that._resizeHandler);
                that.clear();
                that.element.off(NS);
                that.scroller.wrapper.off(NS);
                that.canvas.destroy(true);
                that.canvas = undefined;
                that._destroyEditor();
                that.destroyScroller();
                that._destroyGlobalToolBar();
                that._destroyToolBar();
            },
            destroyScroller: function () {
                var scroller = this.scroller;
                if (!scroller) {
                    return;
                }
                scroller.destroy();
                scroller.element.remove();
                this.scroller = null;
            },
            save: function () {
                var json = {
                    shapes: [],
                    connections: []
                };
                var i, connection, shape;
                for (i = 0; i < this.shapes.length; i++) {
                    shape = this.shapes[i];
                    if (shape.options.serializable) {
                        json.shapes.push(shape.options);
                    }
                }
                for (i = 0; i < this.connections.length; i++) {
                    connection = this.connections[i];
                    json.connections.push(deepExtend({}, connection.options, connection.toJSON()));
                }
                return json;
            },
            focus: function () {
                if (!this.element.is(kendo._activeElement())) {
                    var element = this.element, scrollContainer = element[0], containers = [], offsets = [], documentElement = document.documentElement, i;
                    do {
                        scrollContainer = scrollContainer.parentNode;
                        if (scrollContainer.scrollHeight > scrollContainer.clientHeight) {
                            containers.push(scrollContainer);
                            offsets.push(scrollContainer.scrollTop);
                        }
                    } while (scrollContainer != documentElement);
                    element.focus();
                    for (i = 0; i < containers.length; i++) {
                        containers[i].scrollTop = offsets[i];
                    }
                    return true;
                }
            },
            load: function (options) {
                this.clear();
                this.setOptions(options);
                this._createShapes();
                this._createConnections();
            },
            setOptions: function (options) {
                deepExtend(this.options, options);
            },
            clear: function () {
                var that = this;
                that.select(false);
                that.mainLayer.clear();
                that._shapesQuadTree.clear();
                that._initialize();
            },
            connect: function (source, target, options) {
                var connection;
                if (this.connectionsDataSource && this._isEditable) {
                    var dataItem = this.connectionsDataSource.add({});
                    connection = this._connectionsDataMap[dataItem.uid];
                    connection.source(source);
                    connection.target(target);
                    connection.redraw(options);
                    connection.updateModel();
                } else {
                    connection = new Connection(source, target, deepExtend({}, this.options.connectionDefaults, options));
                    this.addConnection(connection);
                }
                return connection;
            },
            connected: function (source, target) {
                for (var i = 0; i < this.connections.length; i++) {
                    var c = this.connections[i];
                    if (c.from == source && c.to == target) {
                        return true;
                    }
                }
                return false;
            },
            addConnection: function (connection, undoable) {
                if (undoable !== false) {
                    this.undoRedoService.add(new diagram.AddConnectionUnit(connection, this), false);
                }
                connection.diagram = this;
                connection._setOptionsFromModel();
                connection.refresh();
                this.mainLayer.append(connection.visual);
                this.connections.push(connection);
                this.trigger(CHANGE, {
                    added: [connection],
                    removed: []
                });
                return connection;
            },
            _addConnection: function (connection, undoable) {
                var connectionsDataSource = this.connectionsDataSource;
                var dataItem;
                if (connectionsDataSource && this._isEditable) {
                    dataItem = createModel(connectionsDataSource, cloneDataItem(connection.dataItem));
                    connection.dataItem = dataItem;
                    connection.updateModel();
                    if (!this.trigger('add', { connection: connection })) {
                        this._connectionsDataMap[dataItem.uid] = connection;
                        connectionsDataSource.add(dataItem);
                        this.addConnection(connection, undoable);
                        connection._updateConnectors();
                        return connection;
                    }
                } else if (!this.trigger('add', { connection: connection })) {
                    this.addConnection(connection, undoable);
                    connection._updateConnectors();
                    return connection;
                }
            },
            addShape: function (item, undoable) {
                var shape, shapeDefaults = this.options.shapeDefaults;
                if (item instanceof Shape) {
                    shape = item;
                } else if (!(item instanceof kendo.Class)) {
                    shapeDefaults = deepExtend({}, shapeDefaults, item || {});
                    shape = new Shape(shapeDefaults, this);
                } else {
                    return;
                }
                if (undoable !== false) {
                    this.undoRedoService.add(new diagram.AddShapeUnit(shape, this), false);
                }
                this.shapes.push(shape);
                if (shape.diagram !== this) {
                    this._shapesQuadTree.insert(shape);
                    shape.diagram = this;
                }
                this.mainLayer.append(shape.visual);
                this.trigger(CHANGE, {
                    added: [shape],
                    removed: []
                });
                return shape;
            },
            _addShape: function (shape, undoable) {
                var that = this;
                var dataSource = that.dataSource;
                var dataItem;
                if (dataSource && this._isEditable) {
                    dataItem = createModel(dataSource, cloneDataItem(shape.dataItem));
                    shape.dataItem = dataItem;
                    shape.updateModel();
                    if (!this.trigger('add', { shape: shape })) {
                        this.dataSource.add(dataItem);
                        var inactiveItem = this._inactiveShapeItems.getByUid(dataItem.uid);
                        inactiveItem.element = shape;
                        inactiveItem.undoable = undoable;
                        return shape;
                    }
                } else if (!this.trigger('add', { shape: shape })) {
                    return this.addShape(shape, undoable);
                }
            },
            remove: function (items, undoable) {
                items = isArray(items) ? items.slice(0) : [items];
                var elements = splitDiagramElements(items);
                var shapes = elements.shapes;
                var connections = elements.connections;
                var i;
                if (!defined(undoable)) {
                    undoable = true;
                }
                if (undoable) {
                    this.undoRedoService.begin();
                }
                this._suspendModelRefresh();
                for (i = shapes.length - 1; i >= 0; i--) {
                    this._removeItem(shapes[i], undoable, connections);
                }
                for (i = connections.length - 1; i >= 0; i--) {
                    this._removeItem(connections[i], undoable);
                }
                this._resumeModelRefresh();
                if (undoable) {
                    this.undoRedoService.commit(false);
                }
                this.trigger(CHANGE, {
                    added: [],
                    removed: items
                });
            },
            _removeShapeDataItem: function (item) {
                if (this._isEditable) {
                    this.dataSource.remove(item.dataItem);
                    delete this._dataMap[item.dataItem.id];
                }
            },
            _removeConnectionDataItem: function (item) {
                if (this._isEditable) {
                    this.connectionsDataSource.remove(item.dataItem);
                    delete this._connectionsDataMap[item.dataItem.uid];
                }
            },
            _triggerRemove: function (items) {
                var toRemove = [];
                var item, args, editable;
                for (var idx = 0; idx < items.length; idx++) {
                    item = items[idx];
                    editable = item.options.editable;
                    if (item instanceof Shape) {
                        args = { shape: item };
                    } else {
                        args = { connection: item };
                    }
                    if (editable && editable.remove !== false && !this.trigger('remove', args)) {
                        toRemove.push(item);
                    }
                }
                return toRemove;
            },
            undo: function () {
                this.undoRedoService.undo();
            },
            redo: function () {
                this.undoRedoService.redo();
            },
            select: function (item, options) {
                if (isDefined(item)) {
                    options = deepExtend({ addToSelection: false }, options);
                    var addToSelection = options.addToSelection, items = [], selected = [], i, element;
                    if (!addToSelection) {
                        this.deselect();
                    }
                    this._internalSelection = true;
                    if (item instanceof Array) {
                        items = item;
                    } else if (item instanceof DiagramElement) {
                        items = [item];
                    }
                    for (i = 0; i < items.length; i++) {
                        element = items[i];
                        if (element.select(true)) {
                            selected.push(element);
                        }
                    }
                    this._selectionChanged(selected, []);
                    this._internalSelection = false;
                } else {
                    return this._selectedItems;
                }
            },
            selectAll: function () {
                this.select(this.shapes.concat(this.connections));
            },
            selectArea: function (rect) {
                var i, items, item;
                this._internalSelection = true;
                var selected = [];
                if (rect instanceof Rect) {
                    items = this.shapes.concat(this.connections);
                    for (i = 0; i < items.length; i++) {
                        item = items[i];
                        if ((!rect || item._hitTest(rect)) && item.options.enable) {
                            if (item.select(true)) {
                                selected.push(item);
                            }
                        }
                    }
                }
                this._selectionChanged(selected, []);
                this._internalSelection = false;
            },
            deselect: function (item) {
                this._internalSelection = true;
                var deselected = [], items = [], element, i;
                if (item instanceof Array) {
                    items = item;
                } else if (item instanceof DiagramElement) {
                    items.push(item);
                } else if (!isDefined(item)) {
                    items = this._selectedItems.slice(0);
                }
                for (i = 0; i < items.length; i++) {
                    element = items[i];
                    if (element.select(false)) {
                        deselected.push(element);
                    }
                }
                this._selectionChanged([], deselected);
                this._internalSelection = false;
            },
            toFront: function (items, undoable) {
                if (!items) {
                    items = this._selectedItems.slice();
                }
                var result = this._getDiagramItems(items), indices;
                if (!defined(undoable) || undoable) {
                    indices = indicesOfItems(this.mainLayer, result.visuals);
                    var unit = new ToFrontUnit(this, items, indices);
                    this.undoRedoService.add(unit);
                } else {
                    this.mainLayer.toFront(result.visuals);
                    this._fixOrdering(result, true);
                }
            },
            toBack: function (items, undoable) {
                if (!items) {
                    items = this._selectedItems.slice();
                }
                var result = this._getDiagramItems(items), indices;
                if (!defined(undoable) || undoable) {
                    indices = indicesOfItems(this.mainLayer, result.visuals);
                    var unit = new ToBackUnit(this, items, indices);
                    this.undoRedoService.add(unit);
                } else {
                    this.mainLayer.toBack(result.visuals);
                    this._fixOrdering(result, false);
                }
            },
            bringIntoView: function (item, options) {
                var viewport = this.viewport();
                var aligner = new diagram.RectAlign(viewport);
                var current, rect, original, newPan;
                if (viewport.width === 0 || viewport.height === 0) {
                    return;
                }
                options = deepExtend({
                    animate: false,
                    align: 'center middle'
                }, options);
                if (options.align == 'none') {
                    options.align = 'center middle';
                }
                if (item instanceof DiagramElement) {
                    rect = item.bounds(TRANSFORMED);
                } else if (isArray(item)) {
                    rect = this.boundingBox(item);
                } else if (item instanceof Rect) {
                    rect = item.clone();
                }
                original = rect.clone();
                rect.zoom(this._zoom);
                if (rect.width > viewport.width || rect.height > viewport.height) {
                    this._zoom = this._getValidZoom(math.min(viewport.width / original.width, viewport.height / original.height));
                    rect = original.clone().zoom(this._zoom);
                }
                this._zoomMainLayer();
                current = rect.clone();
                aligner.align(rect, options.align);
                newPan = rect.topLeft().minus(current.topLeft());
                this.pan(newPan.times(-1), options.animate);
            },
            alignShapes: function (direction) {
                if (isUndefined(direction)) {
                    direction = 'Left';
                }
                var items = this.select(), val, item, i;
                if (items.length === 0) {
                    return;
                }
                switch (direction.toLowerCase()) {
                case 'left':
                case 'top':
                    val = MAX_VALUE;
                    break;
                case 'right':
                case 'bottom':
                    val = MIN_VALUE;
                    break;
                }
                for (i = 0; i < items.length; i++) {
                    item = items[i];
                    if (item instanceof Shape) {
                        switch (direction.toLowerCase()) {
                        case 'left':
                            val = math.min(val, item.options.x);
                            break;
                        case 'top':
                            val = math.min(val, item.options.y);
                            break;
                        case 'right':
                            val = math.max(val, item.options.x);
                            break;
                        case 'bottom':
                            val = math.max(val, item.options.y);
                            break;
                        }
                    }
                }
                var undoStates = [];
                var shapes = [];
                for (i = 0; i < items.length; i++) {
                    item = items[i];
                    if (item instanceof Shape) {
                        shapes.push(item);
                        undoStates.push(item.bounds());
                        switch (direction.toLowerCase()) {
                        case 'left':
                        case 'right':
                            item.position(new Point(val, item.options.y));
                            break;
                        case 'top':
                        case 'bottom':
                            item.position(new Point(item.options.x, val));
                            break;
                        }
                    }
                }
                var unit = new diagram.TransformUnit(shapes, undoStates);
                this.undoRedoService.add(unit, false);
            },
            zoom: function (zoom, options) {
                if (zoom) {
                    var staticPoint = options ? options.point : new diagram.Point(0, 0);
                    zoom = this._zoom = this._getValidZoom(zoom);
                    if (!isUndefined(staticPoint)) {
                        staticPoint = new diagram.Point(math.round(staticPoint.x), math.round(staticPoint.y));
                        var zoomedPoint = staticPoint.times(zoom);
                        var viewportVector = this.modelToView(staticPoint);
                        var raw = viewportVector.minus(zoomedPoint);
                        this._storePan(new diagram.Point(math.round(raw.x), math.round(raw.y)));
                    }
                    if (options) {
                        options.zoom = zoom;
                    }
                    this._panTransform();
                    this.canvas.surface.hideTooltip();
                    this._updateAdorners();
                }
                return this._zoom;
            },
            _getPan: function (pan) {
                var canvas = this.canvas;
                if (!canvas.translate) {
                    pan = pan.plus(this._pan);
                }
                return pan;
            },
            pan: function (pan, animate) {
                if (pan instanceof Point) {
                    var that = this;
                    var scroller = that.scroller;
                    pan = that._getPan(pan);
                    pan = pan.times(-1);
                    if (animate) {
                        scroller.animatedScrollTo(pan.x, pan.y, function () {
                            that._updateAdorners();
                        });
                    } else {
                        scroller.scrollTo(pan.x, pan.y);
                        that._updateAdorners();
                    }
                } else {
                    return this._pan.times(-1);
                }
            },
            viewport: function () {
                var element = this.element;
                var width = element.width();
                var height = element.height();
                if (this.toolBar) {
                    height -= outerHeight(this.toolBar.element);
                }
                return new Rect(0, 0, width, height);
            },
            copy: function () {
                if (this.options.copy.enabled) {
                    this._clipboard = [];
                    this._copyOffset = 1;
                    for (var i = 0; i < this._selectedItems.length; i++) {
                        var item = this._selectedItems[i];
                        this._clipboard.push(item);
                    }
                }
            },
            cut: function () {
                if (this.options.copy.enabled) {
                    this._clipboard = [];
                    this._copyOffset = 0;
                    for (var i = 0; i < this._selectedItems.length; i++) {
                        var item = this._selectedItems[i];
                        this._clipboard.push(item);
                    }
                    this.remove(this._clipboard, true);
                }
            },
            paste: function () {
                if (this._clipboard.length > 0) {
                    var item, copied, i;
                    var mapping = {};
                    var elements = splitDiagramElements(this._clipboard);
                    var connections = elements.connections;
                    var shapes = elements.shapes;
                    var offset = {
                        x: this._copyOffset * this.options.copy.offsetX,
                        y: this._copyOffset * this.options.copy.offsetY
                    };
                    this.deselect();
                    for (i = 0; i < shapes.length; i++) {
                        item = shapes[i];
                        copied = item.clone();
                        mapping[item.id] = copied;
                        copied.position(new Point(item.options.x + offset.x, item.options.y + offset.y));
                        copied.diagram = this;
                        copied = this._addShape(copied);
                        if (copied) {
                            copied.select();
                        }
                    }
                    for (i = 0; i < connections.length; i++) {
                        item = connections[i];
                        copied = this._addConnection(item.clone());
                        if (copied) {
                            this._updateCopiedConnection(copied, item, 'source', mapping, offset);
                            this._updateCopiedConnection(copied, item, 'target', mapping, offset);
                            copied.select(true);
                            copied.updateModel();
                        }
                    }
                    this._syncChanges();
                    this._copyOffset += 1;
                }
            },
            _updateCopiedConnection: function (connection, sourceConnection, connectorName, mapping, offset) {
                var onActivate, inactiveItem, targetShape;
                var target = sourceConnection[connectorName]();
                var diagram = this;
                if (target instanceof Connector && mapping[target.shape.id]) {
                    targetShape = mapping[target.shape.id];
                    if (diagram.getShapeById(targetShape.id)) {
                        connection[connectorName](targetShape.getConnector(target.options.name));
                    } else {
                        inactiveItem = diagram._inactiveShapeItems.getByUid(targetShape.dataItem.uid);
                        if (inactiveItem) {
                            onActivate = function (item) {
                                targetShape = diagram._dataMap[item.id];
                                connection[connectorName](targetShape.getConnector(target.options.name));
                                connection.updateModel();
                            };
                            diagram._deferredConnectionUpdates.push(inactiveItem.onActivate(onActivate));
                        }
                    }
                } else {
                    connection[connectorName](new Point(sourceConnection[connectorName + 'Point']().x + offset.x, sourceConnection[connectorName + 'Point']().y + offset.y));
                }
            },
            boundingBox: function (items, origin) {
                var rect = Rect.empty(), temp, di = isDefined(items) ? this._getDiagramItems(items) : { shapes: this.shapes };
                if (di.shapes.length > 0) {
                    var item = di.shapes[0];
                    rect = item.bounds(ROTATED);
                    for (var i = 1; i < di.shapes.length; i++) {
                        item = di.shapes[i];
                        temp = item.bounds(ROTATED);
                        if (origin === true) {
                            temp.x -= item._rotationOffset.x;
                            temp.y -= item._rotationOffset.y;
                        }
                        rect = rect.union(temp);
                    }
                }
                return rect;
            },
            _containerOffset: function () {
                var containerOffset = this.element.offset();
                if (this.toolBar) {
                    containerOffset.top += outerHeight(this.toolBar.element);
                }
                return containerOffset;
            },
            documentToView: function (point) {
                var containerOffset = this._containerOffset();
                return new Point(point.x - containerOffset.left, point.y - containerOffset.top);
            },
            viewToDocument: function (point) {
                var containerOffset = this._containerOffset();
                return new Point(point.x + containerOffset.left, point.y + containerOffset.top);
            },
            viewToModel: function (point) {
                return this._transformWithMatrix(point, this._matrixInvert);
            },
            modelToView: function (point) {
                return this._transformWithMatrix(point, this._matrix);
            },
            modelToLayer: function (point) {
                return this._transformWithMatrix(point, this._layerMatrix);
            },
            layerToModel: function (point) {
                return this._transformWithMatrix(point, this._layerMatrixInvert);
            },
            documentToModel: function (point) {
                var viewPoint = this.documentToView(point);
                if (!this.canvas.translate) {
                    viewPoint.x = viewPoint.x + this.scroller.scrollLeft;
                    viewPoint.y = viewPoint.y + this.scroller.scrollTop;
                }
                return this.viewToModel(viewPoint);
            },
            modelToDocument: function (point) {
                return this.viewToDocument(this.modelToView(point));
            },
            _transformWithMatrix: function (point, matrix) {
                var result = point;
                if (point instanceof Point) {
                    if (matrix) {
                        result = matrix.apply(point);
                    }
                } else {
                    var tl = this._transformWithMatrix(point.topLeft(), matrix), br = this._transformWithMatrix(point.bottomRight(), matrix);
                    result = Rect.fromPoints(tl, br);
                }
                return result;
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            },
            setConnectionsDataSource: function (dataSource) {
                this.options.connectionsDataSource = dataSource;
                this._connectionDataSource();
                if (this.options.autoBind) {
                    this.connectionsDataSource.fetch();
                }
            },
            layout: function (options) {
                this._layouting = true;
                var type;
                if (isUndefined(options)) {
                    options = this.options.layout;
                }
                if (isUndefined(options) || isUndefined(options.type)) {
                    type = 'Tree';
                } else {
                    type = options.type;
                }
                var l;
                switch (type.toLowerCase()) {
                case 'tree':
                    l = new diagram.TreeLayout(this);
                    break;
                case 'layered':
                    l = new diagram.LayeredLayout(this);
                    break;
                case 'forcedirected':
                case 'force':
                case 'spring':
                case 'springembedder':
                    l = new diagram.SpringLayout(this);
                    break;
                default:
                    throw 'Layout algorithm \'' + type + '\' is not supported.';
                }
                var initialState = new diagram.LayoutState(this);
                var finalState = l.layout(options);
                if (finalState) {
                    var unit = new diagram.LayoutUndoUnit(initialState, finalState, options ? options.animate : null);
                    this.undoRedoService.add(unit);
                }
                this._layouting = false;
                this._redrawConnections();
            },
            getShapeById: function (id) {
                var found;
                found = Utils.first(this.shapes, function (s) {
                    return s.visual.id === id;
                });
                if (found) {
                    return found;
                }
                found = Utils.first(this.connections, function (c) {
                    return c.visual.id === id;
                });
                return found;
            },
            getShapeByModelId: function (id) {
                var shape;
                if (this._isEditable) {
                    shape = this._dataMap[id];
                } else {
                    shape = Utils.first(this.shapes, function (shape) {
                        return (shape.dataItem || {}).id === id;
                    });
                }
                return shape;
            },
            getShapeByModelUid: function (uid) {
                var shape;
                if (this._isEditable) {
                    shape = Utils.first(this.shapes, function (shape) {
                        return (shape.dataItem || {}).uid === uid;
                    });
                } else {
                    shape = this._dataMap[uid];
                }
                return shape;
            },
            getConnectionByModelId: function (id) {
                var connection;
                if (this.connectionsDataSource) {
                    connection = Utils.first(this.connections, function (connection) {
                        return (connection.dataItem || {}).id === id;
                    });
                }
                return connection;
            },
            getConnectionByModelUid: function (uid) {
                var connection;
                if (this.connectionsDataSource) {
                    connection = this._connectionsDataMap[uid];
                }
                return connection;
            },
            _extendLayoutOptions: function (options) {
                if (options.layout) {
                    options.layout = deepExtend({}, diagram.LayoutBase.fn.defaultOptions || {}, options.layout);
                }
            },
            _selectionChanged: function (selected, deselected) {
                if (selected.length || deselected.length) {
                    this.trigger(SELECT, {
                        selected: selected,
                        deselected: deselected
                    });
                }
            },
            _getValidZoom: function (zoom) {
                return math.min(math.max(zoom, this.options.zoomMin), this.options.zoomMax);
            },
            _panTransform: function (pos) {
                var diagram = this, pan = pos || diagram._pan;
                if (diagram.canvas.translate) {
                    diagram.scroller.scrollTo(pan.x, pan.y);
                    diagram._zoomMainLayer();
                } else {
                    diagram._storePan(pan);
                    diagram._transformMainLayer();
                }
            },
            _finishPan: function () {
                this.trigger(PAN, {
                    total: this._pan,
                    delta: Number.NaN
                });
            },
            _storePan: function (pan) {
                this._pan = pan;
                this._storeViewMatrix();
            },
            _zoomMainLayer: function () {
                var zoom = this._zoom;
                var transform = new CompositeTransform(0, 0, zoom, zoom);
                transform.render(this.mainLayer);
                this._storeLayerMatrix(transform);
                this._storeViewMatrix();
            },
            _transformMainLayer: function () {
                var pan = this._pan, zoom = this._zoom;
                var transform = new CompositeTransform(pan.x, pan.y, zoom, zoom);
                transform.render(this.mainLayer);
                this._storeLayerMatrix(transform);
                this._storeViewMatrix();
            },
            _storeLayerMatrix: function (canvasTransform) {
                this._layerMatrix = canvasTransform.toMatrix();
                this._layerMatrixInvert = canvasTransform.invert().toMatrix();
            },
            _storeViewMatrix: function () {
                var pan = this._pan, zoom = this._zoom;
                var transform = new CompositeTransform(pan.x, pan.y, zoom, zoom);
                this._matrix = transform.toMatrix();
                this._matrixInvert = transform.invert().toMatrix();
            },
            _toIndex: function (items, indices) {
                var result = this._getDiagramItems(items);
                this.mainLayer.toIndex(result.visuals, indices);
                this._fixOrdering(result, false);
            },
            _fixOrdering: function (result, toFront) {
                var shapePos = toFront ? this.shapes.length - 1 : 0, conPos = toFront ? this.connections.length - 1 : 0, i, item;
                for (i = 0; i < result.shapes.length; i++) {
                    item = result.shapes[i];
                    Utils.remove(this.shapes, item);
                    Utils.insert(this.shapes, item, shapePos);
                }
                for (i = 0; i < result.cons.length; i++) {
                    item = result.cons[i];
                    Utils.remove(this.connections, item);
                    Utils.insert(this.connections, item, conPos);
                }
            },
            _getDiagramItems: function (items) {
                var i, result = {}, args = items;
                result.visuals = [];
                result.shapes = [];
                result.cons = [];
                if (!items) {
                    args = this._selectedItems.slice();
                } else if (!isArray(items)) {
                    args = [items];
                }
                for (i = 0; i < args.length; i++) {
                    var item = args[i];
                    if (item instanceof Shape) {
                        result.shapes.push(item);
                        result.visuals.push(item.visual);
                    } else if (item instanceof Connection) {
                        result.cons.push(item);
                        result.visuals.push(item.visual);
                    }
                }
                return result;
            },
            _removeItem: function (item, undoable, removedConnections) {
                item.select(false);
                if (item instanceof Shape) {
                    this._removeShapeDataItem(item);
                    this._removeShape(item, undoable, removedConnections);
                } else if (item instanceof Connection) {
                    this._removeConnectionDataItem(item);
                    this._removeConnection(item, undoable);
                }
                this.mainLayer.remove(item.visual);
            },
            _removeShape: function (shape, undoable, removedConnections) {
                var i, connection, connector, sources = [], targets = [];
                this.toolService._removeHover();
                if (undoable) {
                    this.undoRedoService.addCompositeItem(new DeleteShapeUnit(shape));
                }
                Utils.remove(this.shapes, shape);
                this._shapesQuadTree.remove(shape);
                for (i = 0; i < shape.connectors.length; i++) {
                    connector = shape.connectors[i];
                    for (var j = 0; j < connector.connections.length; j++) {
                        connection = connector.connections[j];
                        if (!removedConnections || !dataviz.inArray(connection, removedConnections)) {
                            if (connection.sourceConnector == connector) {
                                sources.push(connection);
                            } else if (connection.targetConnector == connector) {
                                targets.push(connection);
                            }
                        }
                    }
                }
                for (i = 0; i < sources.length; i++) {
                    sources[i].source(null, undoable);
                    sources[i].updateModel();
                }
                for (i = 0; i < targets.length; i++) {
                    targets[i].target(null, undoable);
                    targets[i].updateModel();
                }
            },
            _removeConnection: function (connection, undoable) {
                if (connection.sourceConnector) {
                    Utils.remove(connection.sourceConnector.connections, connection);
                }
                if (connection.targetConnector) {
                    Utils.remove(connection.targetConnector.connections, connection);
                }
                if (undoable) {
                    this.undoRedoService.addCompositeItem(new DeleteConnectionUnit(connection));
                }
                Utils.remove(this.connections, connection);
            },
            _removeDataItems: function (items, recursive) {
                var item, children, shape, idx;
                items = isArray(items) ? items : [items];
                while (items.length) {
                    item = items.shift();
                    shape = this._dataMap[item.uid];
                    if (shape) {
                        this._removeShapeConnections(shape);
                        this._removeItem(shape, false);
                        delete this._dataMap[item.uid];
                        if (recursive && item.hasChildren && item.loaded()) {
                            children = item.children.data();
                            for (idx = 0; idx < children.length; idx++) {
                                items.push(children[idx]);
                            }
                        }
                    }
                }
            },
            _removeShapeConnections: function (shape) {
                var connections = shape.connections();
                var idx;
                if (connections) {
                    for (idx = 0; idx < connections.length; idx++) {
                        this._removeItem(connections[idx], false);
                    }
                }
            },
            _addDataItem: function (dataItem, undoable) {
                if (!defined(dataItem)) {
                    return;
                }
                var shape = this._dataMap[dataItem.id];
                if (shape) {
                    return shape;
                }
                var options = deepExtend({}, this.options.shapeDefaults);
                options.dataItem = dataItem;
                shape = new Shape(options, this);
                this.addShape(shape, undoable !== false);
                this._dataMap[dataItem.id] = shape;
                return shape;
            },
            _addDataItemByUid: function (dataItem) {
                if (!defined(dataItem)) {
                    return;
                }
                var shape = this._dataMap[dataItem.uid];
                if (shape) {
                    return shape;
                }
                var options = deepExtend({}, this.options.shapeDefaults);
                options.dataItem = dataItem;
                shape = new Shape(options, this);
                this.addShape(shape);
                this._dataMap[dataItem.uid] = shape;
                return shape;
            },
            _addDataItems: function (items, parent) {
                var item, idx, shape, parentShape, connection;
                for (idx = 0; idx < items.length; idx++) {
                    item = items[idx];
                    shape = this._addDataItemByUid(item);
                    parentShape = this._addDataItemByUid(parent);
                    if (parentShape && !this.connected(parentShape, shape)) {
                        connection = this.connect(parentShape, shape);
                    }
                }
            },
            _refreshSource: function (e) {
                var that = this, node = e.node, action = e.action, items = e.items, options = that.options, idx, dataBound;
                if (e.field) {
                    for (idx = 0; idx < items.length; idx++) {
                        if (this._dataMap[items[idx].uid]) {
                            this._dataMap[items[idx].uid].redrawVisual();
                        }
                    }
                    return;
                }
                if (action == 'remove') {
                    this._removeDataItems(e.items, true);
                } else {
                    if ((!action || action === 'itemloaded') && !this._bindingRoots) {
                        this._bindingRoots = true;
                        dataBound = true;
                    }
                    if (!action && !node) {
                        that.clear();
                    }
                    this._addDataItems(items, node);
                    for (idx = 0; idx < items.length; idx++) {
                        items[idx].load();
                    }
                }
                if (options.layout && (dataBound || action == 'remove' || action == 'add')) {
                    that.layout(options.layout);
                }
                if (dataBound) {
                    this.trigger('dataBound');
                    this._bindingRoots = false;
                }
            },
            _addItem: function (item) {
                if (item instanceof Shape) {
                    this.addShape(item);
                } else if (item instanceof Connection) {
                    this.addConnection(item);
                }
            },
            _createToolBar: function (preventClosing) {
                var diagram = this.toolService.diagram;
                if (!this.singleToolBar && diagram.select().length === 1) {
                    var element = diagram.select()[0];
                    if (element && element.options.editable !== false) {
                        var editable = element.options.editable;
                        var tools = editable.tools;
                        if (this._isEditable && tools.length === 0) {
                            if (element instanceof Shape) {
                                tools = [
                                    'edit',
                                    'rotateClockwise',
                                    'rotateAnticlockwise'
                                ];
                            } else if (element instanceof Connection) {
                                tools = ['edit'];
                            }
                            if (editable && editable.remove !== false) {
                                tools.push('delete');
                            }
                        }
                        if (tools && tools.length) {
                            var padding = 20;
                            var point;
                            this.singleToolBar = new DiagramToolBar(diagram, {
                                tools: tools,
                                click: proxy(this._toolBarClick, this),
                                modal: true
                            });
                            var popupWidth = outerWidth(this.singleToolBar._popup.element);
                            var popupHeight = outerHeight(this.singleToolBar._popup.element);
                            if (element instanceof Shape) {
                                var shapeBounds = this.modelToView(element.bounds(ROTATED));
                                point = new Point(shapeBounds.x, shapeBounds.y).minus(new Point((popupWidth - shapeBounds.width) / 2, popupHeight + padding));
                            } else if (element instanceof Connection) {
                                var connectionBounds = this.modelToView(element.bounds());
                                point = new Point(connectionBounds.x, connectionBounds.y).minus(new Point((popupWidth - connectionBounds.width - 20) / 2, popupHeight + padding));
                            }
                            if (point) {
                                if (!this.canvas.translate) {
                                    point = point.minus(new Point(this.scroller.scrollLeft, this.scroller.scrollTop));
                                }
                                point = this.viewToDocument(point);
                                point = new Point(math.max(point.x, 0), math.max(point.y, 0));
                                this.singleToolBar.showAt(point);
                                if (preventClosing) {
                                    this.singleToolBar._popup.one('close', preventDefault);
                                }
                            } else {
                                this._destroyToolBar();
                            }
                        }
                    }
                }
            },
            _toolBarClick: function (e) {
                this.trigger('toolBarClick', e);
                this._destroyToolBar();
            },
            _normalizePointZoom: function (point) {
                return point.times(1 / this.zoom());
            },
            _initialize: function () {
                this.shapes = [];
                this._selectedItems = [];
                this.connections = [];
                this._dataMap = {};
                this._connectionsDataMap = {};
                this._inactiveShapeItems = new InactiveItemsCollection();
                this._deferredConnectionUpdates = [];
                this.undoRedoService = new UndoRedoService({
                    undone: this._syncHandler,
                    redone: this._syncHandler
                });
                this.id = diagram.randomId();
            },
            _fetchFreshData: function () {
                var that = this;
                that._dataSource();
                if (that._isEditable) {
                    that._connectionDataSource();
                }
                if (that.options.autoBind) {
                    if (that._isEditable) {
                        this._loadingShapes = true;
                        this._loadingConnections = true;
                        that.dataSource.fetch();
                        that.connectionsDataSource.fetch();
                    } else {
                        that.dataSource.fetch();
                    }
                }
            },
            _dataSource: function () {
                if (defined(this.options.connectionsDataSource)) {
                    this._isEditable = true;
                    var dsOptions = this.options.dataSource || {};
                    var ds = isArray(dsOptions) ? { data: dsOptions } : dsOptions;
                    if (this.dataSource && this._shapesRefreshHandler) {
                        this.dataSource.unbind('change', this._shapesRefreshHandler).unbind('requestStart', this._shapesRequestStartHandler).unbind('error', this._shapesErrorHandler);
                    } else {
                        this._shapesRefreshHandler = proxy(this._refreshShapes, this);
                        this._shapesRequestStartHandler = proxy(this._shapesRequestStart, this);
                        this._shapesErrorHandler = proxy(this._error, this);
                    }
                    this.dataSource = kendo.data.DataSource.create(ds).bind('change', this._shapesRefreshHandler).bind('requestStart', this._shapesRequestStartHandler).bind('error', this._shapesErrorHandler);
                } else {
                    this._treeDataSource();
                    this._isEditable = false;
                }
            },
            _connectionDataSource: function () {
                var dsOptions = this.options.connectionsDataSource;
                if (dsOptions) {
                    var ds = isArray(dsOptions) ? { data: dsOptions } : dsOptions;
                    if (this.connectionsDataSource && this._connectionsRefreshHandler) {
                        this.connectionsDataSource.unbind('change', this._connectionsRefreshHandler).unbind('requestStart', this._connectionsRequestStartHandler).unbind('error', this._connectionsErrorHandler);
                    } else {
                        this._connectionsRefreshHandler = proxy(this._refreshConnections, this);
                        this._connectionsRequestStartHandler = proxy(this._connectionsRequestStart, this);
                        this._connectionsErrorHandler = proxy(this._connectionsError, this);
                    }
                    this.connectionsDataSource = kendo.data.DataSource.create(ds).bind('change', this._connectionsRefreshHandler).bind('requestStart', this._connectionsRequestStartHandler).bind('error', this._connectionsErrorHandler);
                }
            },
            _shapesRequestStart: function (e) {
                if (e.type == 'read') {
                    this._loadingShapes = true;
                }
            },
            _connectionsRequestStart: function (e) {
                if (e.type == 'read') {
                    this._loadingConnections = true;
                }
            },
            _error: function () {
                this._loadingShapes = false;
            },
            _connectionsError: function () {
                this._loadingConnections = false;
            },
            _refreshShapes: function (e) {
                if (e.action === 'remove') {
                    if (this._shouldRefresh()) {
                        this._removeShapes(e.items);
                    }
                } else if (e.action === 'itemchange') {
                    if (this._shouldRefresh()) {
                        this._updateShapes(e.items, e.field);
                    }
                } else if (e.action === 'add') {
                    this._inactiveShapeItems.add(e.items);
                } else if (e.action === 'sync') {
                    this._syncShapes(e.items);
                } else {
                    this.refresh();
                }
            },
            _shouldRefresh: function () {
                return !this._suspended;
            },
            _suspendModelRefresh: function () {
                this._suspended = (this._suspended || 0) + 1;
            },
            _resumeModelRefresh: function () {
                this._suspended = math.max((this._suspended || 0) - 1, 0);
            },
            refresh: function () {
                this._loadingShapes = false;
                if (!this._loadingConnections) {
                    this._rebindShapesAndConnections();
                }
            },
            _rebindShapesAndConnections: function () {
                this.clear();
                this._addShapes(this.dataSource.view());
                if (this.connectionsDataSource) {
                    this._addConnections(this.connectionsDataSource.view(), false);
                }
                if (this.options.layout) {
                    this.layout(this.options.layout);
                } else {
                    this._redrawConnections();
                }
                this.trigger('dataBound');
            },
            refreshConnections: function () {
                this._loadingConnections = false;
                if (!this._loadingShapes) {
                    this._rebindShapesAndConnections();
                }
            },
            _redrawConnections: function () {
                var connections = this.connections;
                for (var idx = 0; idx < connections.length; idx++) {
                    connections[idx].refresh();
                }
            },
            _removeShapes: function (items) {
                var dataMap = this._dataMap;
                var item, i;
                for (i = 0; i < items.length; i++) {
                    item = items[i];
                    if (dataMap[item.id]) {
                        this.remove(dataMap[item.id], false);
                        dataMap[item.id] = null;
                    }
                }
            },
            _syncShapes: function () {
                var diagram = this;
                var inactiveItems = diagram._inactiveShapeItems;
                inactiveItems.forEach(function (inactiveItem) {
                    var dataItem = inactiveItem.dataItem;
                    var shape = inactiveItem.element;
                    if (!dataItem.isNew()) {
                        if (shape) {
                            shape._setOptionsFromModel();
                            diagram.addShape(shape, inactiveItem.undoable);
                            diagram._dataMap[dataItem.id] = shape;
                        } else {
                            diagram._addDataItem(dataItem);
                        }
                        inactiveItem.activate();
                        inactiveItems.remove(dataItem);
                    }
                });
            },
            _updateShapes: function (items, field) {
                for (var i = 0; i < items.length; i++) {
                    var dataItem = items[i];
                    var shape = this._dataMap[dataItem.id];
                    if (shape) {
                        shape.updateOptionsFromModel(dataItem, field);
                    }
                }
            },
            _addShapes: function (dataItems) {
                for (var i = 0; i < dataItems.length; i++) {
                    this._addDataItem(dataItems[i], false);
                }
            },
            _refreshConnections: function (e) {
                if (e.action === 'remove') {
                    if (this._shouldRefresh()) {
                        this._removeConnections(e.items);
                    }
                } else if (e.action === 'add') {
                    this._addConnections(e.items);
                } else if (e.action === 'sync') {
                } else if (e.action === 'itemchange') {
                    if (this._shouldRefresh()) {
                        this._updateConnections(e.items);
                    }
                } else {
                    this.refreshConnections();
                }
            },
            _removeConnections: function (items) {
                for (var i = 0; i < items.length; i++) {
                    this.remove(this._connectionsDataMap[items[i].uid], false);
                    this._connectionsDataMap[items[i].uid] = null;
                }
            },
            _updateConnections: function (items) {
                for (var i = 0; i < items.length; i++) {
                    var dataItem = items[i];
                    var connection = this._connectionsDataMap[dataItem.uid];
                    connection.updateOptionsFromModel(dataItem);
                }
            },
            _addConnections: function (connections, undoable) {
                var length = connections.length;
                for (var i = 0; i < length; i++) {
                    var dataItem = connections[i];
                    this._addConnectionDataItem(dataItem, undoable);
                }
            },
            _addConnectionDataItem: function (dataItem, undoable) {
                if (!this._connectionsDataMap[dataItem.uid]) {
                    var from = this._validateConnector(dataItem.from);
                    if (!defined(from) || from === null) {
                        from = new Point(dataItem.fromX, dataItem.fromY);
                    }
                    var to = this._validateConnector(dataItem.to);
                    if (!defined(to) || to === null) {
                        to = new Point(dataItem.toX, dataItem.toY);
                    }
                    if (defined(from) && defined(to)) {
                        var options = deepExtend({}, this.options.connectionDefaults);
                        options.dataItem = dataItem;
                        var connection = new Connection(from, to, options);
                        this._connectionsDataMap[dataItem.uid] = connection;
                        this.addConnection(connection, undoable);
                    }
                }
            },
            _validateConnector: function (value) {
                var connector;
                if (defined(value) && value !== null) {
                    connector = this._dataMap[value];
                }
                return connector;
            },
            _treeDataSource: function () {
                var that = this, options = that.options, dataSource = options.dataSource;
                dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
                if (dataSource instanceof kendo.data.DataSource && !(dataSource instanceof kendo.data.HierarchicalDataSource)) {
                    throw new Error('Incorrect DataSource type. If a single dataSource instance is set to the diagram then it should be a HierarchicalDataSource. You should set only the options instead of an instance or a HierarchicalDataSource instance or supply connectionsDataSource as well.');
                }
                if (!dataSource.fields) {
                    dataSource.fields = [
                        { field: 'text' },
                        { field: 'url' },
                        { field: 'spriteCssClass' },
                        { field: 'imageUrl' }
                    ];
                }
                if (that.dataSource && that._refreshHandler) {
                    that._unbindDataSource();
                }
                that._refreshHandler = proxy(that._refreshSource, that);
                that._errorHandler = proxy(that._error, that);
                that.dataSource = HierarchicalDataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(ERROR, that._errorHandler);
            },
            _unbindDataSource: function () {
                var that = this;
                that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(ERROR, that._errorHandler);
            },
            _adorn: function (adorner, isActive) {
                if (isActive !== undefined && adorner) {
                    if (isActive) {
                        this._adorners.push(adorner);
                        this.adornerLayer.append(adorner.visual);
                    } else {
                        Utils.remove(this._adorners, adorner);
                        this.adornerLayer.remove(adorner.visual);
                    }
                }
            },
            _showConnectors: function (shape, value) {
                if (value) {
                    this._connectorsAdorner.show(shape);
                } else {
                    this._connectorsAdorner.destroy();
                }
            },
            _updateAdorners: function () {
                var adorners = this._adorners;
                for (var i = 0; i < adorners.length; i++) {
                    var adorner = adorners[i];
                    if (adorner.refreshBounds) {
                        adorner.refreshBounds();
                    }
                    adorner.refresh();
                }
            },
            _refresh: function () {
                for (var i = 0; i < this.connections.length; i++) {
                    this.connections[i].refresh();
                }
            },
            _destroyToolBar: function () {
                if (this.singleToolBar) {
                    this.singleToolBar.hide();
                    this.singleToolBar.destroy();
                    this.singleToolBar = null;
                }
            },
            _destroyGlobalToolBar: function () {
                if (this.toolBar) {
                    this.toolBar.hide();
                    this.toolBar.destroy();
                    this.toolBar = null;
                }
            },
            exportDOMVisual: function () {
                var viewBox = this.canvas._viewBox;
                var scrollOffset = geom.transform().translate(-viewBox.x, -viewBox.y);
                var viewRect = new geom.Rect([
                    0,
                    0
                ], [
                    viewBox.width,
                    viewBox.height
                ]);
                var clipPath = draw.Path.fromRect(viewRect);
                var wrap = new draw.Group({ transform: scrollOffset });
                var clipWrap = new draw.Group({ clip: clipPath });
                var root = this.canvas.drawingElement.children[0];
                clipWrap.append(wrap);
                wrap.children.push(root);
                return clipWrap;
            },
            exportVisual: function () {
                var scale = geom.transform().scale(1 / this._zoom);
                var wrap = new draw.Group({ transform: scale });
                var root = this.mainLayer.drawingElement;
                wrap.children.push(root);
                return wrap;
            },
            _syncChanges: function () {
                this._syncShapeChanges();
                this._syncConnectionChanges();
            },
            _syncShapeChanges: function () {
                if (this.dataSource && this._isEditable) {
                    this.dataSource.sync();
                }
            },
            _syncConnectionChanges: function () {
                var that = this;
                if (that.connectionsDataSource && that._isEditable) {
                    $.when.apply($, that._deferredConnectionUpdates).then(function () {
                        that.connectionsDataSource.sync();
                    });
                    that.deferredConnectionUpdates = [];
                }
            }
        });
        dataviz.ExportMixin.extend(Diagram.fn, true);
        if (kendo.PDFMixin) {
            kendo.PDFMixin.extend(Diagram.fn);
        }
        function filterShapeDataItem(dataItem) {
            var result = {};
            dataItem = dataItem || {};
            if (defined(dataItem.text) && dataItem.text !== null) {
                result.text = dataItem.text;
            }
            if (defined(dataItem.x) && dataItem.x !== null) {
                result.x = dataItem.x;
            }
            if (defined(dataItem.y) && dataItem.y !== null) {
                result.y = dataItem.y;
            }
            if (defined(dataItem.width) && dataItem.width !== null) {
                result.width = dataItem.width;
            }
            if (defined(dataItem.height) && dataItem.height !== null) {
                result.height = dataItem.height;
            }
            if (defined(dataItem.type) && dataItem.type !== null) {
                result.type = dataItem.type;
            }
            return result;
        }
        function filterConnectionDataItem(dataItem) {
            var result = {};
            dataItem = dataItem || {};
            if (defined(dataItem.text) && dataItem.text !== null) {
                result.content = dataItem.text;
            }
            if (defined(dataItem.type) && dataItem.type !== null) {
                result.type = dataItem.type;
            }
            if (defined(dataItem.from) && dataItem.from !== null) {
                result.from = dataItem.from;
            }
            if (defined(dataItem.fromConnector) && dataItem.fromConnector !== null) {
                result.fromConnector = dataItem.fromConnector;
            }
            if (defined(dataItem.fromX) && dataItem.fromX !== null) {
                result.fromX = dataItem.fromX;
            }
            if (defined(dataItem.fromY) && dataItem.fromY !== null) {
                result.fromY = dataItem.fromY;
            }
            if (defined(dataItem.to) && dataItem.to !== null) {
                result.to = dataItem.to;
            }
            if (defined(dataItem.toConnector) && dataItem.toConnector !== null) {
                result.toConnector = dataItem.toConnector;
            }
            if (defined(dataItem.toX) && dataItem.toX !== null) {
                result.toX = dataItem.toX;
            }
            if (defined(dataItem.toY) && dataItem.toY !== null) {
                result.toY = dataItem.toY;
            }
            return result;
        }
        var DiagramToolBar = kendo.Observable.extend({
            init: function (diagram, options) {
                kendo.Observable.fn.init.call(this);
                this.diagram = diagram;
                this.options = deepExtend({}, this.options, options);
                this._tools = [];
                this.createToolBar();
                this.createTools();
                this.appendTools();
                if (this.options.modal) {
                    this.createPopup();
                }
                this.bind(this.events, options);
            },
            events: ['click'],
            createPopup: function () {
                this.container = $('<div/>').append(this.element);
                this._popup = this.container.kendoPopup({}).getKendoPopup();
            },
            appendTools: function () {
                for (var i = 0; i < this._tools.length; i++) {
                    var tool = this._tools[i];
                    if (tool.buttons && tool.buttons.length || !defined(tool.buttons)) {
                        this._toolBar.add(tool);
                    }
                }
            },
            createToolBar: function () {
                this.element = $('<div/>');
                this._toolBar = this.element.kendoToolBar({
                    click: proxy(this.click, this),
                    resizable: false
                }).getKendoToolBar();
                this.element.css('border', 'none');
            },
            createTools: function () {
                for (var i = 0; i < this.options.tools.length; i++) {
                    this.createTool(this.options.tools[i]);
                }
            },
            createTool: function (tool) {
                if (!isPlainObject(tool)) {
                    tool = { name: tool };
                }
                var toolName = tool.name + 'Tool';
                if (this[toolName]) {
                    this[toolName](tool);
                } else {
                    this._tools.push(deepExtend({}, tool, { attributes: this._setAttributes({ action: tool.name }) }));
                }
            },
            showAt: function (point) {
                if (this._popup) {
                    this._popup.open(point.x, point.y);
                }
            },
            hide: function () {
                if (this._popup) {
                    this._popup.close();
                }
            },
            newGroup: function () {
                return {
                    type: 'buttonGroup',
                    buttons: []
                };
            },
            editTool: function () {
                this._tools.push({
                    icon: 'edit',
                    showText: 'overflow',
                    type: 'button',
                    text: 'Edit',
                    attributes: this._setAttributes({ action: 'edit' })
                });
            },
            deleteTool: function () {
                this._tools.push({
                    icon: 'close',
                    showText: 'overflow',
                    type: 'button',
                    text: 'Delete',
                    attributes: this._setAttributes({ action: 'delete' })
                });
            },
            rotateAnticlockwiseTool: function (options) {
                this._appendGroup('rotate');
                this._rotateGroup.buttons.push({
                    icon: 'rotate-left',
                    showText: 'overflow',
                    text: 'RotateAnticlockwise',
                    group: 'rotate',
                    attributes: this._setAttributes({
                        action: 'rotateAnticlockwise',
                        step: options.step
                    })
                });
            },
            rotateClockwiseTool: function (options) {
                this._appendGroup('rotate');
                this._rotateGroup.buttons.push({
                    icon: 'rotate-right',
                    attributes: this._setAttributes({
                        action: 'rotateClockwise',
                        step: options.step
                    }),
                    showText: 'overflow',
                    text: 'RotateClockwise',
                    group: 'rotate'
                });
            },
            createShapeTool: function () {
                this._appendGroup('create');
                this._createGroup.buttons.push({
                    icon: 'shape',
                    showText: 'overflow',
                    text: 'CreateShape',
                    group: 'create',
                    attributes: this._setAttributes({ action: 'createShape' })
                });
            },
            createConnectionTool: function () {
                this._appendGroup('create');
                this._createGroup.buttons.push({
                    icon: 'connector',
                    showText: 'overflow',
                    text: 'CreateConnection',
                    group: 'create',
                    attributes: this._setAttributes({ action: 'createConnection' })
                });
            },
            undoTool: function () {
                this._appendGroup('history');
                this._historyGroup.buttons.push({
                    icon: 'undo',
                    showText: 'overflow',
                    text: 'Undo',
                    group: 'history',
                    attributes: this._setAttributes({ action: 'undo' })
                });
            },
            redoTool: function () {
                this._appendGroup('history');
                this._historyGroup.buttons.push({
                    icon: 'redo',
                    showText: 'overflow',
                    text: 'Redo',
                    group: 'history',
                    attributes: this._setAttributes({ action: 'redo' })
                });
            },
            _appendGroup: function (name) {
                var prop = '_' + name + 'Group';
                if (!this[prop]) {
                    this[prop] = this.newGroup();
                    this._tools.push(this[prop]);
                }
            },
            _setAttributes: function (attributes) {
                var attr = {};
                if (attributes.action) {
                    attr[kendo.attr('action')] = attributes.action;
                }
                if (attributes.step) {
                    attr[kendo.attr('step')] = attributes.step;
                }
                return attr;
            },
            _getAttributes: function (element) {
                var attr = {};
                var action = element.attr(kendo.attr('action'));
                if (action) {
                    attr.action = action;
                }
                var step = element.attr(kendo.attr('step'));
                if (step) {
                    attr.step = step;
                }
                return attr;
            },
            click: function (e) {
                var attributes = this._getAttributes($(e.target));
                var action = attributes.action;
                if (action && this[action]) {
                    this[action](attributes);
                }
                this.trigger('click', this.eventData(action, e.target));
            },
            eventData: function (action, target) {
                var elements = this.selectedElements(), length = elements.length, shapes = [], connections = [], element;
                for (var idx = 0; idx < length; idx++) {
                    element = elements[idx];
                    if (element instanceof Shape) {
                        shapes.push(element);
                    } else {
                        connections.push(element);
                    }
                }
                return {
                    shapes: shapes,
                    connections: connections,
                    action: action,
                    target: target
                };
            },
            'delete': function () {
                var diagram = this.diagram;
                var toRemove = diagram._triggerRemove(this.selectedElements());
                if (toRemove.length) {
                    this.diagram.remove(toRemove, true);
                    this.diagram._syncChanges();
                }
            },
            edit: function () {
                var selectedElemens = this.selectedElements();
                if (selectedElemens.length === 1) {
                    this.diagram.edit(selectedElemens[0]);
                }
            },
            rotateClockwise: function (options) {
                var angle = parseFloat(options.step || 90);
                this._rotate(angle);
            },
            rotateAnticlockwise: function (options) {
                var angle = parseFloat(options.step || 90);
                this._rotate(-angle);
            },
            _rotate: function (angle) {
                var adorner = this.diagram._resizingAdorner;
                adorner.angle(adorner.angle() + angle);
                adorner.rotate();
            },
            selectedElements: function () {
                return this.diagram.select();
            },
            createShape: function () {
                this.diagram.createShape();
            },
            createConnection: function () {
                this.diagram.createConnection();
            },
            undo: function () {
                this.diagram.undo();
            },
            redo: function () {
                this.diagram.redo();
            },
            destroy: function () {
                this.diagram = null;
                this.element = null;
                this.options = null;
                if (this._toolBar) {
                    this._toolBar.destroy();
                }
                if (this._popup) {
                    this._popup.destroy();
                }
            }
        });
        var Editor = kendo.Observable.extend({
            init: function (element, options) {
                kendo.Observable.fn.init.call(this);
                this.options = extend(true, {}, this.options, options);
                this.element = element;
                this.model = this.options.model;
                this.fields = this._getFields();
                this._initContainer();
                this.createEditable();
            },
            options: { editors: {} },
            _initContainer: function () {
                this.wrapper = this.element;
            },
            createEditable: function () {
                var options = this.options;
                this.editable = new kendo.ui.Editable(this.wrapper, {
                    fields: this.fields,
                    target: options.target,
                    clearContainer: false,
                    model: this.model
                });
            },
            _isEditable: function (field) {
                return this.model.editable && this.model.editable(field);
            },
            _getFields: function () {
                var fields = [];
                var modelFields = this.model.fields;
                for (var field in modelFields) {
                    var result = {};
                    if (this._isEditable(field)) {
                        var editor = this.options.editors[field];
                        if (editor) {
                            result.editor = editor;
                        }
                        result.field = field;
                        fields.push(result);
                    }
                }
                return fields;
            },
            end: function () {
                return this.editable.end();
            },
            destroy: function () {
                this.editable.destroy();
                this.editable.element.find('[' + kendo.attr('container-for') + ']').empty();
                this.model = this.wrapper = this.element = this.columns = this.editable = null;
            }
        });
        var PopupEditor = Editor.extend({
            init: function (element, options) {
                Editor.fn.init.call(this, element, options);
                this.bind(this.events, this.options);
                this.open();
            },
            events: [
                'update',
                'cancel'
            ],
            options: {
                window: {
                    modal: true,
                    resizable: false,
                    draggable: true,
                    title: 'Edit',
                    visible: false
                }
            },
            _initContainer: function () {
                var that = this;
                this.wrapper = $('<div class="k-popup-edit-form"/>').attr(kendo.attr('uid'), this.model.uid);
                var formContent = '';
                if (this.options.template) {
                    formContent += this._renderTemplate();
                    this.fields = [];
                } else {
                    formContent += this._renderFields();
                }
                formContent += this._renderButtons();
                this.wrapper.append($('<div class="k-edit-form-container"/>').append(formContent));
                this.window = new kendo.ui.Window(this.wrapper.appendTo(this.element), this.options.window);
                this.window.bind('close', function (e) {
                    if (e.userTriggered) {
                        e.sender.element.focus();
                        that._cancelClick(e);
                    }
                });
                this._attachButtonEvents();
            },
            _renderTemplate: function () {
                var template = this.options.template;
                if (typeof template === 'string') {
                    template = window.unescape(template);
                }
                template = kendo.template(template)(this.model);
                return template;
            },
            _renderFields: function () {
                var form = '';
                for (var i = 0; i < this.fields.length; i++) {
                    var field = this.fields[i];
                    form += '<div class="k-edit-label"><label for="' + field.field + '">' + (field.field || '') + '</label></div>';
                    if (this._isEditable(field.field)) {
                        form += '<div ' + kendo.attr('container-for') + '="' + field.field + '" class="k-edit-field"></div>';
                    }
                }
                return form;
            },
            _renderButtons: function () {
                var form = '<div class="k-edit-buttons k-state-default">';
                form += this._createButton('update');
                form += this._createButton('cancel');
                form += '</div>';
                return form;
            },
            _createButton: function (name) {
                return kendo.template(BUTTON_TEMPLATE)(defaultButtons[name]);
            },
            _attachButtonEvents: function () {
                this._cancelClickHandler = proxy(this._cancelClick, this);
                this.window.element.on(CLICK + NS, 'a.k-diagram-cancel', this._cancelClickHandler);
                this._updateClickHandler = proxy(this._updateClick, this);
                this.window.element.on(CLICK + NS, 'a.k-diagram-update', this._updateClickHandler);
            },
            _updateClick: function (e) {
                e.preventDefault();
                this.trigger('update');
            },
            _cancelClick: function (e) {
                e.preventDefault();
                this.trigger('cancel');
            },
            open: function () {
                this.window.center().open();
            },
            close: function () {
                this.window.bind('deactivate', proxy(this.destroy, this)).close();
            },
            destroy: function () {
                this.window.close().destroy();
                this.window.element.off(CLICK + NS, 'a.k-diagram-cancel', this._cancelClickHandler);
                this.window.element.off(CLICK + NS, 'a.k-diagram-update', this._updateClickHandler);
                this._cancelClickHandler = null;
                this._editUpdateClickHandler = null;
                this.window = null;
                Editor.fn.destroy.call(this);
            }
        });
        function connectionSelector(container, options) {
            var model = this.dataSource.reader.model;
            if (model) {
                var textField = model.fn.fields.text ? 'text' : model.idField;
                $('<input name=\'' + options.field + '\' />').appendTo(container).kendoDropDownList({
                    dataValueField: model.idField,
                    dataTextField: textField,
                    dataSource: this.dataSource.data().toJSON(),
                    optionLabel: ' ',
                    valuePrimitive: true
                });
            }
        }
        function InactiveItem(dataItem) {
            this.dataItem = dataItem;
            this.callbacks = [];
        }
        InactiveItem.fn = InactiveItem.prototype = {
            onActivate: function (callback) {
                var deffered = $.Deferred();
                this.callbacks.push({
                    callback: callback,
                    deferred: deffered
                });
                return deffered;
            },
            activate: function () {
                var callbacks = this.callbacks;
                var item;
                for (var idx = 0; idx < callbacks.length; idx++) {
                    item = this.callbacks[idx];
                    item.callback(this.dataItem);
                    item.deferred.resolve();
                }
                this.callbacks = [];
            }
        };
        function InactiveItemsCollection() {
            this.items = {};
        }
        InactiveItemsCollection.fn = InactiveItemsCollection.prototype = {
            add: function (items) {
                for (var idx = 0; idx < items.length; idx++) {
                    this.items[items[idx].uid] = new InactiveItem(items[idx]);
                }
            },
            forEach: function (callback) {
                for (var uid in this.items) {
                    callback(this.items[uid]);
                }
            },
            getByUid: function (uid) {
                return this.items[uid];
            },
            remove: function (item) {
                delete this.items[item.uid];
            }
        };
        var QuadRoot = Class.extend({
            init: function () {
                this.shapes = [];
            },
            _add: function (shape, bounds) {
                this.shapes.push({
                    bounds: bounds,
                    shape: shape
                });
                shape._quadNode = this;
            },
            insert: function (shape, bounds) {
                this._add(shape, bounds);
            },
            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;
                    }
                }
            },
            hitTestRect: function (rect, exclude) {
                var shapes = this.shapes;
                var length = shapes.length;
                for (var i = 0; i < length; i++) {
                    if (this._testRect(shapes[i].shape, rect) && !dataviz.inArray(shapes[i].shape, exclude)) {
                        return true;
                    }
                }
            },
            _testRect: function (shape, rect) {
                var angle = shape.rotate().angle;
                var bounds = shape.bounds();
                var hit;
                if (!angle) {
                    hit = bounds.overlaps(rect);
                } else {
                    hit = Intersect.rects(rect, bounds, -angle);
                }
                return hit;
            }
        });
        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.x <= rect.x && nodeRect.y <= rect.y && bottomRight.x <= nodeBottomRight.x && bottomRight.y <= nodeBottomRight.y;
                return inBounds;
            },
            overlapsBounds: function (rect) {
                return this.rect.overlaps(rect);
            },
            insert: function (shape, bounds) {
                var inserted = false;
                var children = this.children;
                var length = children.length;
                if (this.inBounds(bounds)) {
                    if (!length && this.shapes.length < 4) {
                        this._add(shape, bounds);
                    } else {
                        if (!length) {
                            this._initChildren();
                        }
                        for (var idx = 0; idx < children.length; idx++) {
                            if (children[idx].insert(shape, bounds)) {
                                inserted = true;
                                break;
                            }
                        }
                        if (!inserted) {
                            this._add(shape, bounds);
                        }
                    }
                    inserted = true;
                }
                return inserted;
            },
            _initChildren: function () {
                var rect = this.rect, children = this.children, shapes = this.shapes, center = rect.center(), halfWidth = rect.width / 2, halfHeight = rect.height / 2, childIdx, shapeIdx;
                children.push(new QuadNode(new Rect(rect.x, rect.y, halfWidth, halfHeight)), new QuadNode(new Rect(center.x, rect.y, halfWidth, halfHeight)), new QuadNode(new Rect(rect.x, center.y, halfWidth, halfHeight)), new QuadNode(new Rect(center.x, center.y, halfWidth, halfHeight)));
                for (shapeIdx = shapes.length - 1; shapeIdx >= 0; shapeIdx--) {
                    for (childIdx = 0; childIdx < children.length; childIdx++) {
                        if (children[childIdx].insert(shapes[shapeIdx].shape, shapes[shapeIdx].bounds)) {
                            shapes.splice(shapeIdx, 1);
                            break;
                        }
                    }
                }
            },
            hitTestRect: function (rect, exclude) {
                var idx;
                var children = this.children;
                var length = children.length;
                var hit = false;
                if (this.overlapsBounds(rect)) {
                    if (QuadRoot.fn.hitTestRect.call(this, rect, exclude)) {
                        hit = true;
                    } else {
                        for (idx = 0; idx < length; idx++) {
                            if (children[idx].hitTestRect(rect, exclude)) {
                                hit = true;
                                break;
                            }
                        }
                    }
                }
                return hit;
            }
        });
        var ShapesQuadTree = Class.extend({
            ROOT_SIZE: 1000,
            init: function (diagram) {
                var boundsChangeHandler = proxy(this._boundsChange, this);
                diagram.bind(ITEMBOUNDSCHANGE, boundsChangeHandler);
                diagram.bind(ITEMROTATE, boundsChangeHandler);
                this.initRoots();
            },
            initRoots: function () {
                this.rootMap = {};
                this.root = new QuadRoot();
            },
            clear: function () {
                this.initRoots();
            },
            _boundsChange: function (e) {
                if (e.item._quadNode) {
                    e.item._quadNode.remove(e.item);
                }
                this.insert(e.item);
            },
            insert: function (shape) {
                var bounds = shape.bounds(ROTATED);
                var rootSize = this.ROOT_SIZE;
                var sectors = this.getSectors(bounds);
                var x = sectors[0][0];
                var y = sectors[1][0];
                if (this.inRoot(sectors)) {
                    this.root.insert(shape, bounds);
                } 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, bounds);
                }
            },
            remove: function (shape) {
                if (shape._quadNode) {
                    shape._quadNode.remove(shape);
                }
            },
            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.x / rootSize); x <= bottomX; x++) {
                    sectors[0].push(x);
                }
                for (var y = math.floor(rect.y / rootSize); y <= bottomY; y++) {
                    sectors[1].push(y);
                }
                return sectors;
            },
            hitTestRect: function (rect, exclude) {
                var sectors = this.getSectors(rect);
                var xIdx, yIdx, x, y;
                var root;
                if (this.root.hitTestRect(rect, exclude)) {
                    return true;
                }
                for (xIdx = 0; xIdx < sectors[0].length; xIdx++) {
                    x = sectors[0][xIdx];
                    for (yIdx = 0; yIdx < sectors[1].length; yIdx++) {
                        y = sectors[1][yIdx];
                        root = (this.rootMap[x] || {})[y];
                        if (root && root.hitTestRect(rect, exclude)) {
                            return true;
                        }
                    }
                }
                return false;
            }
        });
        function cloneDataItem(dataItem) {
            var result = dataItem;
            if (dataItem instanceof kendo.data.Model) {
                result = dataItem.toJSON();
                result[dataItem.idField] = dataItem._defaultId;
            }
            return result;
        }
        function splitDiagramElements(elements) {
            var connections = [];
            var shapes = [];
            var element, idx;
            for (idx = 0; idx < elements.length; idx++) {
                element = elements[idx];
                if (element instanceof Shape) {
                    shapes.push(element);
                } else {
                    connections.push(element);
                }
            }
            return {
                shapes: shapes,
                connections: connections
            };
        }
        function createModel(dataSource, model) {
            if (dataSource.reader.model) {
                return new dataSource.reader.model(model);
            }
            return new kendo.data.ObservableObject(model);
        }
        function clearField(field, model) {
            if (defined(model[field])) {
                model.set(field, null);
            }
        }
        function copyDefaultOptions(mainOptions, elementOptions, fields) {
            var field;
            for (var idx = 0; idx < fields.length; idx++) {
                field = fields[idx];
                if (elementOptions && !defined(elementOptions[field])) {
                    elementOptions[field] = mainOptions[field];
                }
            }
        }
        function translateToOrigin(visual) {
            var bbox = visual.drawingContainer().clippedBBox(null);
            if (bbox.origin.x !== 0 || bbox.origin.y !== 0) {
                visual.position(-bbox.origin.x, -bbox.origin.y);
            }
        }
        function preventDefault(e) {
            e.preventDefault();
        }
        dataviz.ui.plugin(Diagram);
        deepExtend(diagram, {
            Shape: Shape,
            Connection: Connection,
            Connector: Connector,
            DiagramToolBar: DiagramToolBar,
            QuadNode: QuadNode,
            QuadRoot: QuadRoot,
            ShapesQuadTree: ShapesQuadTree,
            PopupEditor: PopupEditor
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.diagram', [
        'kendo.data',
        'kendo.draganddrop',
        'kendo.userevents',
        'kendo.mobile.scroller',
        'kendo.drawing',
        'dataviz/diagram/utils',
        'dataviz/diagram/math',
        'dataviz/diagram/svg',
        'dataviz/diagram/services',
        'dataviz/diagram/layout',
        'dataviz/diagram/dom'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.diagram',
        name: 'Diagram',
        category: 'dataviz',
        description: 'The Kendo DataViz Diagram ',
        depends: [
            'data',
            'userevents',
            'mobile.scroller',
            'draganddrop',
            'drawing',
            'dataviz.core',
            'dataviz.themes',
            'toolbar'
        ],
        features: [
            {
                id: 'dataviz.diagram-pdf-export',
                name: 'PDF export',
                description: 'Export Diagram as PDF',
                depends: ['pdf']
            },
            {
                id: 'dataviz.diagram-editing',
                name: 'Editing',
                description: 'Support for model editing',
                depends: [
                    'editable',
                    'window',
                    'dropdownlist'
                ]
            }
        ]
    };
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz.treemap', [
        'kendo.data',
        'kendo.userevents',
        'kendo.dataviz.themes'
    ], f);
}(function () {
    var __meta__ = {
        id: 'dataviz.treeMap',
        name: 'TreeMap',
        category: 'dataviz',
        description: 'The Kendo DataViz TreeMap',
        depends: [
            'data',
            'userevents',
            'dataviz.themes'
        ]
    };
    (function ($, undefined) {
        var math = Math, proxy = $.proxy, isArray = $.isArray, kendo = window.kendo, outerHeight = kendo._outerHeight, outerWidth = kendo._outerWidth, Class = kendo.Class, Widget = kendo.ui.Widget, template = kendo.template, deepExtend = kendo.deepExtend, HierarchicalDataSource = kendo.data.HierarchicalDataSource, getter = kendo.getter, dataviz = kendo.dataviz;
        var NS = '.kendoTreeMap', CHANGE = 'change', DATA_BOUND = 'dataBound', ITEM_CREATED = 'itemCreated', MAX_VALUE = Number.MAX_VALUE, MOUSEOVER_NS = 'mouseover' + NS, MOUSELEAVE_NS = 'mouseleave' + NS, UNDEFINED = 'undefined';
        var TreeMap = Widget.extend({
            init: function (element, options) {
                kendo.destroy(element);
                $(element).empty();
                Widget.fn.init.call(this, element, options);
                this.wrapper = this.element;
                this._initTheme(this.options);
                this.element.addClass('k-widget k-treemap');
                this._setLayout();
                this._originalOptions = deepExtend({}, this.options);
                this._initDataSource();
                this._attachEvents();
                kendo.notify(this, dataviz.ui);
            },
            options: {
                name: 'TreeMap',
                theme: 'default',
                autoBind: true,
                textField: 'text',
                valueField: 'value',
                colorField: 'color'
            },
            events: [
                DATA_BOUND,
                ITEM_CREATED
            ],
            _initTheme: function (options) {
                var that = this, themes = dataviz.ui.themes || {}, themeName = ((options || {}).theme || '').toLowerCase(), themeOptions = (themes[themeName] || {}).treeMap;
                that.options = deepExtend({}, themeOptions, options);
            },
            _attachEvents: function () {
                this.element.on(MOUSEOVER_NS, proxy(this._mouseover, this)).on(MOUSELEAVE_NS, proxy(this._mouseleave, this));
                this._resizeHandler = proxy(this.resize, this, false);
                kendo.onResize(this._resizeHandler);
            },
            _setLayout: function () {
                if (this.options.type === 'horizontal') {
                    this._layout = new SliceAndDice(false);
                    this._view = new SliceAndDiceView(this, this.options);
                } else if (this.options.type === 'vertical') {
                    this._layout = new SliceAndDice(true);
                    this._view = new SliceAndDiceView(this, this.options);
                } else {
                    this._layout = new Squarified();
                    this._view = new SquarifiedView(this, this.options);
                }
            },
            _initDataSource: function () {
                var that = this, options = that.options, dataSource = options.dataSource;
                that._dataChangeHandler = proxy(that._onDataChange, that);
                that.dataSource = HierarchicalDataSource.create(dataSource).bind(CHANGE, that._dataChangeHandler);
                if (dataSource) {
                    if (that.options.autoBind) {
                        that.dataSource.fetch();
                    }
                }
            },
            setDataSource: function (dataSource) {
                var that = this;
                that.dataSource.unbind(CHANGE, that._dataChangeHandler);
                that.dataSource = dataSource.bind(CHANGE, that._dataChangeHandler);
                if (dataSource) {
                    if (that.options.autoBind) {
                        that.dataSource.fetch();
                    }
                }
            },
            _onDataChange: function (e) {
                var node = e.node;
                var items = e.items;
                var options = this.options;
                var item, i;
                if (!node) {
                    this._cleanItems();
                    this.element.empty();
                    item = this._wrapItem(items[0]);
                    this._layout.createRoot(item, outerWidth(this.element), outerHeight(this.element), this.options.type === 'vertical');
                    this._view.createRoot(item);
                    this._root = item;
                    this._colorIdx = 0;
                } else {
                    if (items.length) {
                        var root = this._getByUid(node.uid);
                        root.children = [];
                        items = new kendo.data.Query(items)._sortForGrouping(options.valueField, 'desc');
                        for (i = 0; i < items.length; i++) {
                            item = items[i];
                            root.children.push(this._wrapItem(item));
                        }
                        var htmlSize = this._view.htmlSize(root);
                        this._layout.compute(root.children, root.coord, htmlSize);
                        this._setColors(root.children);
                        this._view.render(root);
                    }
                }
                for (i = 0; i < items.length; i++) {
                    items[i].load();
                }
                if (node) {
                    this.trigger(DATA_BOUND, { node: node });
                }
            },
            _cleanItems: function () {
                var that = this;
                that.angular('cleanup', function () {
                    return { elements: that.element.find('.k-leaf div,.k-treemap-title,.k-treemap-title-vertical') };
                });
            },
            _setColors: function (items) {
                var colors = this.options.colors;
                var colorIdx = this._colorIdx;
                var color = colors[colorIdx % colors.length];
                var colorRange, item;
                if (isArray(color)) {
                    colorRange = colorsByLength(color[0], color[1], items.length);
                }
                var leafNodes = false;
                for (var i = 0; i < items.length; i++) {
                    item = items[i];
                    if (!defined(item.color)) {
                        if (colorRange) {
                            item.color = colorRange[i];
                        } else {
                            item.color = color;
                        }
                    }
                    if (!item.dataItem.hasChildren) {
                        leafNodes = true;
                    }
                }
                if (leafNodes) {
                    this._colorIdx++;
                }
            },
            _contentSize: function (root) {
                this.view.renderHeight(root);
            },
            _wrapItem: function (item) {
                var wrap = {};
                if (defined(this.options.valueField)) {
                    wrap.value = getField(this.options.valueField, item);
                }
                if (defined(this.options.colorField)) {
                    wrap.color = getField(this.options.colorField, item);
                }
                if (defined(this.options.textField)) {
                    wrap.text = getField(this.options.textField, item);
                }
                wrap.level = item.level();
                wrap.dataItem = item;
                return wrap;
            },
            _getByUid: function (uid) {
                var items = [this._root];
                var item;
                while (items.length) {
                    item = items.pop();
                    if (item.dataItem.uid === uid) {
                        return item;
                    }
                    if (item.children) {
                        items = items.concat(item.children);
                    }
                }
            },
            dataItem: function (node) {
                var uid = $(node).attr(kendo.attr('uid')), dataSource = this.dataSource;
                return dataSource && dataSource.getByUid(uid);
            },
            findByUid: function (uid) {
                return this.element.find('.k-treemap-tile[' + kendo.attr('uid') + '=\'' + uid + '\']');
            },
            _mouseover: function (e) {
                var target = $(e.target);
                if (target.hasClass('k-leaf')) {
                    this._removeActiveState();
                    target.removeClass('k-state-hover').addClass('k-state-hover');
                }
            },
            _removeActiveState: function () {
                this.element.find('.k-state-hover').removeClass('k-state-hover');
            },
            _mouseleave: function () {
                this._removeActiveState();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.off(NS);
                if (this.dataSource) {
                    this.dataSource.unbind(CHANGE, this._dataChangeHandler);
                }
                this._root = null;
                kendo.unbindResize(this._resizeHandler);
                kendo.destroy(this.element);
            },
            items: function () {
                return $();
            },
            getSize: function () {
                return kendo.dimensions(this.element);
            },
            _resize: function () {
                var root = this._root;
                if (root) {
                    var element = this.element;
                    var rootElement = element.children();
                    root.coord.width = outerWidth(element);
                    root.coord.height = outerHeight(element);
                    rootElement.css({
                        width: root.coord.width,
                        height: root.coord.height
                    });
                    this._resizeItems(root, rootElement);
                }
            },
            _resizeItems: function (root, element) {
                if (root.children && root.children.length) {
                    var elements = element.children('.k-treemap-wrap').children();
                    var child, childElement;
                    this._layout.compute(root.children, root.coord, { text: this._view.titleSize(root, element) });
                    for (var idx = 0; idx < root.children.length; idx++) {
                        child = root.children[idx];
                        childElement = elements.filter('[' + kendo.attr('uid') + '=\'' + child.dataItem.uid + '\']');
                        this._view.setItemSize(child, childElement);
                        this._resizeItems(child, childElement);
                    }
                }
            },
            setOptions: function (options) {
                var dataSource = options.dataSource;
                options.dataSource = undefined;
                this._originalOptions = deepExtend(this._originalOptions, options);
                this.options = deepExtend({}, this._originalOptions);
                this._setLayout();
                this._initTheme(this.options);
                Widget.fn._setEvents.call(this, options);
                if (dataSource) {
                    this.setDataSource(HierarchicalDataSource.create(dataSource));
                }
                if (this.options.autoBind) {
                    this.dataSource.fetch();
                }
            }
        });
        var Squarified = Class.extend({
            createRoot: function (root, width, height) {
                root.coord = {
                    width: width,
                    height: height,
                    top: 0,
                    left: 0
                };
            },
            leaf: function (tree) {
                return !tree.children;
            },
            layoutChildren: function (items, coord) {
                var parentArea = coord.width * coord.height;
                var totalArea = 0, itemsArea = [], i;
                for (i = 0; i < items.length; i++) {
                    itemsArea[i] = parseFloat(items[i].value);
                    totalArea += itemsArea[i];
                }
                for (i = 0; i < itemsArea.length; i++) {
                    items[i].area = parentArea * itemsArea[i] / totalArea;
                }
                var minimumSideValue = this.layoutHorizontal() ? coord.height : coord.width;
                var firstElement = [items[0]];
                var tail = items.slice(1);
                this.squarify(tail, firstElement, minimumSideValue, coord);
            },
            squarify: function (tail, initElement, width, coord) {
                this.computeDim(tail, initElement, width, coord);
            },
            computeDim: function (tail, initElement, width, coord) {
                if (tail.length + initElement.length == 1) {
                    var element = tail.length == 1 ? tail : initElement;
                    this.layoutLast(element, width, coord);
                    return;
                }
                if (tail.length >= 2 && initElement.length === 0) {
                    initElement = [tail[0]];
                    tail = tail.slice(1);
                }
                if (tail.length === 0) {
                    if (initElement.length > 0) {
                        this.layoutRow(initElement, width, coord);
                    }
                    return;
                }
                var firstElement = tail[0];
                if (this.worstAspectRatio(initElement, width) >= this.worstAspectRatio([firstElement].concat(initElement), width)) {
                    this.computeDim(tail.slice(1), initElement.concat([firstElement]), width, coord);
                } else {
                    var newCoords = this.layoutRow(initElement, width, coord);
                    this.computeDim(tail, [], newCoords.dim, newCoords);
                }
            },
            layoutLast: function (items, w, coord) {
                items[0].coord = coord;
            },
            layoutRow: function (items, width, coord) {
                if (this.layoutHorizontal()) {
                    return this.layoutV(items, width, coord);
                } else {
                    return this.layoutH(items, width, coord);
                }
            },
            orientation: 'h',
            layoutVertical: function () {
                return this.orientation === 'v';
            },
            layoutHorizontal: function () {
                return this.orientation === 'h';
            },
            layoutChange: function () {
                this.orientation = this.layoutVertical() ? 'h' : 'v';
            },
            worstAspectRatio: function (items, width) {
                if (!items || items.length === 0) {
                    return MAX_VALUE;
                }
                var areaSum = 0, maxArea = 0, minArea = MAX_VALUE;
                for (var i = 0; i < items.length; i++) {
                    var area = items[i].area;
                    areaSum += area;
                    minArea = minArea < area ? minArea : area;
                    maxArea = maxArea > area ? maxArea : area;
                }
                return math.max(width * width * maxArea / (areaSum * areaSum), areaSum * areaSum / (width * width * minArea));
            },
            compute: function (children, rootCoord, htmlSize) {
                if (!(rootCoord.width >= rootCoord.height && this.layoutHorizontal())) {
                    this.layoutChange();
                }
                if (children && children.length > 0) {
                    var newRootCoord = {
                        width: rootCoord.width,
                        height: rootCoord.height - htmlSize.text,
                        top: 0,
                        left: 0
                    };
                    this.layoutChildren(children, newRootCoord);
                }
            },
            layoutV: function (items, width, coord) {
                var totalArea = this._totalArea(items), top = 0;
                width = round(totalArea / width);
                for (var i = 0; i < items.length; i++) {
                    var height = round(items[i].area / width);
                    items[i].coord = {
                        height: height,
                        width: width,
                        top: coord.top + top,
                        left: coord.left
                    };
                    top += height;
                }
                var ans = {
                    height: coord.height,
                    width: coord.width - width,
                    top: coord.top,
                    left: coord.left + width
                };
                ans.dim = math.min(ans.width, ans.height);
                if (ans.dim != ans.height) {
                    this.layoutChange();
                }
                return ans;
            },
            layoutH: function (items, width, coord) {
                var totalArea = this._totalArea(items);
                var height = round(totalArea / width), top = coord.top, left = 0;
                for (var i = 0; i < items.length; i++) {
                    items[i].coord = {
                        height: height,
                        width: round(items[i].area / height),
                        top: top,
                        left: coord.left + left
                    };
                    left += items[i].coord.width;
                }
                var ans = {
                    height: coord.height - height,
                    width: coord.width,
                    top: coord.top + height,
                    left: coord.left
                };
                ans.dim = math.min(ans.width, ans.height);
                if (ans.dim != ans.width) {
                    this.layoutChange();
                }
                return ans;
            },
            _totalArea: function (items) {
                var total = 0;
                for (var i = 0; i < items.length; i++) {
                    total += items[i].area;
                }
                return total;
            }
        });
        var SquarifiedView = Class.extend({
            init: function (treeMap, options) {
                this.options = deepExtend({}, this.options, options);
                this.treeMap = treeMap;
                this.element = $(treeMap.element);
                this.offset = 0;
            },
            titleSize: function (item, element) {
                var text = element.children('.k-treemap-title');
                return text.height();
            },
            htmlSize: function (root) {
                var rootElement = this._getByUid(root.dataItem.uid);
                var htmlSize = { text: 0 };
                if (root.children) {
                    this._clean(rootElement);
                    var text = this._getText(root);
                    if (text) {
                        var title = this._createTitle(root);
                        rootElement.append(title);
                        this._compile(title, root.dataItem);
                        htmlSize.text = title.height();
                    }
                    rootElement.append(this._createWrap());
                    this.offset = (outerWidth(rootElement) - rootElement.innerWidth()) / 2;
                }
                return htmlSize;
            },
            _compile: function (element, dataItem) {
                this.treeMap.angular('compile', function () {
                    return {
                        elements: element,
                        data: [{ dataItem: dataItem }]
                    };
                });
            },
            _getByUid: function (uid) {
                return this.element.find('.k-treemap-tile[' + kendo.attr('uid') + '=\'' + uid + '\']');
            },
            render: function (root) {
                var rootElement = this._getByUid(root.dataItem.uid);
                var children = root.children;
                if (children) {
                    var rootWrap = rootElement.find('.k-treemap-wrap');
                    for (var i = 0; i < children.length; i++) {
                        var leaf = children[i];
                        var htmlElement = this._createLeaf(leaf);
                        rootWrap.append(htmlElement);
                        this._compile(htmlElement.children(), leaf.dataItem);
                        this.treeMap.trigger(ITEM_CREATED, { element: htmlElement });
                    }
                }
            },
            createRoot: function (root) {
                var htmlElement = this._createLeaf(root);
                this.element.append(htmlElement);
                this._compile(htmlElement.children(), root.dataItem);
                this.treeMap.trigger(ITEM_CREATED, { element: htmlElement });
            },
            _clean: function (root) {
                this.treeMap.angular('cleanup', function () {
                    return { elements: root.children(':not(.k-treemap-wrap)') };
                });
                root.css('background-color', '');
                root.removeClass('k-leaf');
                root.removeClass('k-inverse');
                root.empty();
            },
            _createLeaf: function (item) {
                return this._createTile(item).css('background-color', item.color).addClass('k-leaf').toggleClass('k-inverse', this._tileColorBrightness(item) > 180).append($('<div></div>').html(this._getText(item)));
            },
            _createTile: function (item) {
                var tile = $('<div class=\'k-treemap-tile\'></div>');
                this.setItemSize(item, tile);
                if (defined(item.dataItem) && defined(item.dataItem.uid)) {
                    tile.attr(kendo.attr('uid'), item.dataItem.uid);
                }
                return tile;
            },
            _itemCoordinates: function (item) {
                var coordinates = {
                    width: item.coord.width,
                    height: item.coord.height,
                    left: item.coord.left,
                    top: item.coord.top
                };
                if (coordinates.left && this.offset) {
                    coordinates.width += this.offset * 2;
                } else {
                    coordinates.width += this.offset;
                }
                if (coordinates.top) {
                    coordinates.height += this.offset * 2;
                } else {
                    coordinates.height += this.offset;
                }
                return coordinates;
            },
            setItemSize: function (item, element) {
                var coordinates = this._itemCoordinates(item);
                element.css({
                    width: coordinates.width,
                    height: coordinates.height,
                    left: coordinates.left,
                    top: coordinates.top
                });
            },
            _getText: function (item) {
                var text = item.text;
                if (this.options.template) {
                    text = this._renderTemplate(item);
                }
                return text;
            },
            _renderTemplate: function (item) {
                var titleTemplate = template(this.options.template);
                return titleTemplate({
                    dataItem: item.dataItem,
                    text: item.text
                });
            },
            _createTitle: function (item) {
                return $('<div class=\'k-treemap-title\'></div>').append($('<div></div>').html(this._getText(item)));
            },
            _createWrap: function () {
                return $('<div class=\'k-treemap-wrap\'></div>');
            },
            _tileColorBrightness: function (item) {
                return colorBrightness(item.color);
            }
        });
        var SliceAndDice = Class.extend({
            createRoot: function (root, width, height, vertical) {
                root.coord = {
                    width: width,
                    height: height,
                    top: 0,
                    left: 0
                };
                root.vertical = vertical;
            },
            init: function (vertical) {
                this.vertical = vertical;
                this.quotient = vertical ? 1 : 0;
            },
            compute: function (children, rootCoord, htmlSize) {
                if (children.length > 0) {
                    var width = rootCoord.width;
                    var height = rootCoord.height;
                    if (this.vertical) {
                        height -= htmlSize.text;
                    } else {
                        width -= htmlSize.text;
                    }
                    var newRootCoord = {
                        width: width,
                        height: height,
                        top: 0,
                        left: 0
                    };
                    this.layoutChildren(children, newRootCoord);
                }
            },
            layoutChildren: function (items, coord) {
                var parentArea = coord.width * coord.height;
                var totalArea = 0;
                var itemsArea = [];
                var i;
                for (i = 0; i < items.length; i++) {
                    var item = items[i];
                    itemsArea[i] = parseFloat(items[i].value);
                    totalArea += itemsArea[i];
                    item.vertical = this.vertical;
                }
                for (i = 0; i < itemsArea.length; i++) {
                    items[i].area = parentArea * itemsArea[i] / totalArea;
                }
                this.sliceAndDice(items, coord);
            },
            sliceAndDice: function (items, coord) {
                var totalArea = this._totalArea(items);
                if (items[0].level % 2 === this.quotient) {
                    this.layoutHorizontal(items, coord, totalArea);
                } else {
                    this.layoutVertical(items, coord, totalArea);
                }
            },
            layoutHorizontal: function (items, coord, totalArea) {
                var left = 0;
                for (var i = 0; i < items.length; i++) {
                    var item = items[i];
                    var width = item.area / (totalArea / coord.width);
                    item.coord = {
                        height: coord.height,
                        width: width,
                        top: coord.top,
                        left: coord.left + left
                    };
                    left += width;
                }
            },
            layoutVertical: function (items, coord, totalArea) {
                var top = 0;
                for (var i = 0; i < items.length; i++) {
                    var item = items[i];
                    var height = item.area / (totalArea / coord.height);
                    item.coord = {
                        height: height,
                        width: coord.width,
                        top: coord.top + top,
                        left: coord.left
                    };
                    top += height;
                }
            },
            _totalArea: function (items) {
                var total = 0;
                for (var i = 0; i < items.length; i++) {
                    total += items[i].area;
                }
                return total;
            }
        });
        var SliceAndDiceView = SquarifiedView.extend({
            htmlSize: function (root) {
                var rootElement = this._getByUid(root.dataItem.uid);
                var htmlSize = {
                    text: 0,
                    offset: 0
                };
                if (root.children) {
                    this._clean(rootElement);
                    var text = this._getText(root);
                    if (text) {
                        var title = this._createTitle(root);
                        rootElement.append(title);
                        this._compile(title, root.dataItem);
                        if (root.vertical) {
                            htmlSize.text = title.height();
                        } else {
                            htmlSize.text = title.width();
                        }
                    }
                    rootElement.append(this._createWrap());
                    this.offset = (outerWidth(rootElement) - rootElement.innerWidth()) / 2;
                }
                return htmlSize;
            },
            titleSize: function (item, element) {
                var size;
                if (item.vertical) {
                    size = element.children('.k-treemap-title').height();
                } else {
                    size = element.children('.k-treemap-title-vertical').width();
                }
                return size;
            },
            _createTitle: function (item) {
                var title;
                if (item.vertical) {
                    title = $('<div class=\'k-treemap-title\'></div>');
                } else {
                    title = $('<div class=\'k-treemap-title-vertical\'></div>');
                }
                return title.append($('<div></div>').html(this._getText(item)));
            }
        });
        function getField(field, row) {
            if (row === null) {
                return row;
            }
            var get = getter(field, true);
            return get(row);
        }
        function defined(value) {
            return typeof value !== UNDEFINED;
        }
        function colorsByLength(min, max, length) {
            var minRGBtoDecimal = rgbToDecimal(min);
            var maxRGBtoDecimal = rgbToDecimal(max);
            var isDarker = colorBrightness(min) - colorBrightness(max) < 0;
            var colors = [];
            colors.push(min);
            for (var i = 0; i < length; i++) {
                var rgbColor = {
                    r: colorByIndex(minRGBtoDecimal.r, maxRGBtoDecimal.r, i, length, isDarker),
                    g: colorByIndex(minRGBtoDecimal.g, maxRGBtoDecimal.g, i, length, isDarker),
                    b: colorByIndex(minRGBtoDecimal.b, maxRGBtoDecimal.b, i, length, isDarker)
                };
                colors.push(buildColorFromRGB(rgbColor));
            }
            colors.push(max);
            return colors;
        }
        function colorByIndex(min, max, index, length, isDarker) {
            var minColor = math.min(math.abs(min), math.abs(max));
            var maxColor = math.max(math.abs(min), math.abs(max));
            var step = (maxColor - minColor) / (length + 1);
            var currentStep = step * (index + 1);
            var color;
            if (isDarker) {
                color = minColor + currentStep;
            } else {
                color = maxColor - currentStep;
            }
            return color;
        }
        function buildColorFromRGB(color) {
            return '#' + decimalToRgb(color.r) + decimalToRgb(color.g) + decimalToRgb(color.b);
        }
        function rgbToDecimal(color) {
            color = color.replace('#', '');
            var rgbColor = colorToRGB(color);
            return {
                r: rgbToHex(rgbColor.r),
                g: rgbToHex(rgbColor.g),
                b: rgbToHex(rgbColor.b)
            };
        }
        function decimalToRgb(number) {
            var result = math.round(number).toString(16).toUpperCase();
            if (result.length === 1) {
                result = '0' + result;
            }
            return result;
        }
        function colorToRGB(color) {
            var colorLength = color.length;
            var rgbColor = {};
            if (colorLength === 3) {
                rgbColor.r = color[0];
                rgbColor.g = color[1];
                rgbColor.b = color[2];
            } else {
                rgbColor.r = color.substring(0, 2);
                rgbColor.g = color.substring(2, 4);
                rgbColor.b = color.substring(4, 6);
            }
            return rgbColor;
        }
        function rgbToHex(rgb) {
            return parseInt(rgb.toString(16), 16);
        }
        function colorBrightness(color) {
            var brightness = 0;
            if (color) {
                color = rgbToDecimal(color);
                brightness = math.sqrt(0.241 * color.r * color.r + 0.691 * color.g * color.g + 0.068 * color.b * color.b);
            }
            return brightness;
        }
        function round(value) {
            var power = math.pow(10, 4);
            return math.round(value * power) / power;
        }
        dataviz.ui.plugin(TreeMap);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.dataviz', [
        'kendo.core',
        'kendo.fx',
        'kendo.router',
        'kendo.view',
        'kendo.data.odata',
        'kendo.data.xml',
        'kendo.data',
        'kendo.data.signalr',
        'kendo.binder',
        'kendo.userevents',
        'kendo.draganddrop',
        'kendo.mobile.scroller',
        'kendo.popup',
        'kendo.tooltip',
        'kendo.drawing',
        'kendo.dataviz.core',
        'kendo.dataviz.themes',
        'kendo.dataviz.chart',
        'kendo.dataviz.gauge',
        'kendo.dataviz.barcode',
        'kendo.dataviz.qrcode',
        'kendo.dataviz.stock',
        'kendo.dataviz.sparkline',
        'kendo.dataviz.map',
        'kendo.dataviz.diagram',
        'kendo.dataviz.treemap',
        'kendo.angular'
    ], f);
}(function () {
    'bundle all';
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.modalview', [
        'kendo.mobile.shim',
        'kendo.mobile.view'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.modalview',
        name: 'ModalView',
        category: 'mobile',
        description: 'The Kendo ModalView is used to present self-contained functionality in the context of the current task.',
        depends: [
            'mobile.shim',
            'mobile.view'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.mobile.ui, Shim = ui.Shim, Widget = ui.Widget, BEFORE_OPEN = 'beforeOpen', OPEN = 'open', CLOSE = 'close', INIT = 'init', WRAP = '<div class="km-modalview-wrapper" />';
        var ModalView = ui.View.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that._id();
                that._wrap();
                that._shim();
                if (!this.options.$angular) {
                    that._layout();
                    that._scroller();
                    that._model();
                }
                that.element.css('display', '');
                that.trigger(INIT);
            },
            events: [
                INIT,
                BEFORE_OPEN,
                OPEN,
                CLOSE
            ],
            options: {
                name: 'ModalView',
                modal: true,
                width: null,
                height: null
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.shim.destroy();
            },
            open: function (target) {
                var that = this;
                that.target = $(target);
                that.shim.show();
                that._invokeNgController();
                that.trigger('show', { view: that });
            },
            openFor: function (target) {
                if (!this.trigger(BEFORE_OPEN, { target: target })) {
                    this.open(target);
                    this.trigger(OPEN, { target: target });
                }
            },
            close: function () {
                if (this.element.is(':visible') && !this.trigger(CLOSE)) {
                    this.shim.hide();
                }
            },
            _wrap: function () {
                var that = this, element = that.element, options = that.options, width, height;
                width = element[0].style.width || 'auto';
                height = element[0].style.height || 'auto';
                element.addClass('km-modalview').wrap(WRAP);
                that.wrapper = element.parent().css({
                    width: options.width || width || 300,
                    height: options.height || height || 300
                }).addClass(height == 'auto' ? ' km-auto-height' : '');
                element.css({
                    width: '',
                    height: ''
                });
            },
            _shim: function () {
                var that = this;
                that.shim = new Shim(that.wrapper, {
                    modal: that.options.modal,
                    position: 'center center',
                    align: 'center center',
                    effect: 'fade:in',
                    className: 'km-modalview-root',
                    hide: function (e) {
                        if (that.trigger(CLOSE)) {
                            e.preventDefault();
                        }
                    }
                });
            }
        });
        ui.plugin(ModalView);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.drawer', [
        'kendo.mobile.view',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.drawer',
        name: 'Drawer',
        category: 'mobile',
        description: 'The Kendo Mobile Drawer widget provides slide to reveal global application toolbox',
        depends: [
            'mobile.view',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, os = kendo.support.mobileOS, Transition = kendo.effects.Transition, roleSelector = kendo.roleSelector, AXIS = 'x', ui = mobile.ui, SWIPE_TO_OPEN = !(os.ios && os.majorVersion == 7 && !os.appMode), BEFORE_SHOW = 'beforeShow', INIT = 'init', SHOW = 'show', HIDE = 'hide', AFTER_HIDE = 'afterHide', NULL_VIEW = { enable: $.noop };
        var Drawer = ui.View.extend({
            init: function (element, options) {
                $(element).parent().prepend(element);
                mobile.ui.Widget.fn.init.call(this, element, options);
                if (!this.options.$angular) {
                    this._layout();
                    this._scroller();
                }
                this._model();
                var pane = this.element.closest(roleSelector('pane')).data('kendoMobilePane'), userEvents;
                if (pane) {
                    this.pane = pane;
                    this.pane.bind('viewShow', function (e) {
                        drawer._viewShow(e);
                    });
                    this.pane.bind('sameViewRequested', function () {
                        drawer.hide();
                    });
                    userEvents = this.userEvents = new kendo.UserEvents(pane.element, {
                        fastTap: true,
                        filter: roleSelector('view splitview'),
                        allowSelection: true
                    });
                } else {
                    this.currentView = NULL_VIEW;
                    var container = $(this.options.container);
                    if (!container) {
                        throw new Error('The drawer needs a container configuration option set.');
                    }
                    userEvents = this.userEvents = new kendo.UserEvents(container, {
                        fastTap: true,
                        allowSelection: true
                    });
                    this._attachTransition(container);
                }
                var drawer = this;
                var hide = function (e) {
                    if (drawer.visible) {
                        drawer.hide();
                        e.preventDefault();
                    }
                };
                if (this.options.swipeToOpen && SWIPE_TO_OPEN) {
                    userEvents.bind('press', function () {
                        drawer.transition.cancel();
                    });
                    userEvents.bind('start', function (e) {
                        drawer._start(e);
                    });
                    userEvents.bind('move', function (e) {
                        drawer._update(e);
                    });
                    userEvents.bind('end', function (e) {
                        drawer._end(e);
                    });
                    userEvents.bind('tap', hide);
                } else {
                    userEvents.bind('press', hide);
                }
                this.leftPositioned = this.options.position === 'left';
                this.visible = false;
                this.element.hide().addClass('km-drawer').addClass(this.leftPositioned ? 'km-left-drawer' : 'km-right-drawer');
                this.trigger(INIT);
            },
            options: {
                name: 'Drawer',
                position: 'left',
                views: [],
                swipeToOpenViews: [],
                swipeToOpen: true,
                title: '',
                container: null
            },
            events: [
                BEFORE_SHOW,
                HIDE,
                AFTER_HIDE,
                INIT,
                SHOW
            ],
            show: function () {
                if (this._activate()) {
                    this._show();
                }
            },
            hide: function () {
                if (!this.currentView) {
                    return;
                }
                this.currentView.enable();
                Drawer.current = null;
                this._moveViewTo(0);
                this.trigger(HIDE, { view: this });
            },
            openFor: function () {
                if (this.visible) {
                    this.hide();
                } else {
                    this.show();
                }
            },
            destroy: function () {
                ui.View.fn.destroy.call(this);
                this.userEvents.destroy();
            },
            _activate: function () {
                if (this.visible) {
                    return true;
                }
                var visibleOnCurrentView = this._currentViewIncludedIn(this.options.views);
                if (!visibleOnCurrentView || this.trigger(BEFORE_SHOW, { view: this })) {
                    return false;
                }
                this._setAsCurrent();
                this.element.show();
                this.trigger(SHOW, { view: this });
                this._invokeNgController();
                return true;
            },
            _currentViewIncludedIn: function (views) {
                if (!this.pane || !views.length) {
                    return true;
                }
                var view = this.pane.view();
                return $.inArray(view.id.replace('#', ''), views) > -1 || $.inArray(view.element.attr('id'), views) > -1;
            },
            _show: function () {
                this.currentView.enable(false);
                this.visible = true;
                var offset = this.element.width();
                if (!this.leftPositioned) {
                    offset = -offset;
                }
                this._moveViewTo(offset);
            },
            _setAsCurrent: function () {
                if (Drawer.last !== this) {
                    if (Drawer.last) {
                        Drawer.last.element.hide();
                    }
                    this.element.show();
                }
                Drawer.last = this;
                Drawer.current = this;
            },
            _moveViewTo: function (offset) {
                this.userEvents.cancel();
                this.transition.moveTo({
                    location: offset,
                    duration: 400,
                    ease: Transition.easeOutExpo
                });
            },
            _viewShow: function (e) {
                if (this.currentView) {
                    this.currentView.enable();
                }
                if (this.currentView === e.view) {
                    this.hide();
                    return;
                }
                this.currentView = e.view;
                this._attachTransition(e.view.element);
            },
            _attachTransition: function (element) {
                var that = this, movable = this.movable, currentOffset = movable && movable.x;
                if (this.transition) {
                    this.transition.cancel();
                    this.movable.moveAxis('x', 0);
                }
                movable = this.movable = new kendo.ui.Movable(element);
                this.transition = new Transition({
                    axis: AXIS,
                    movable: this.movable,
                    onEnd: function () {
                        if (movable[AXIS] === 0) {
                            element[0].style.cssText = '';
                            that.element.hide();
                            that.trigger(AFTER_HIDE);
                            that.visible = false;
                        }
                    }
                });
                if (currentOffset) {
                    element.addClass('k-fx-hidden');
                    kendo.animationFrame(function () {
                        element.removeClass('k-fx-hidden');
                        that.movable.moveAxis(AXIS, currentOffset);
                        that.hide();
                    });
                }
            },
            _start: function (e) {
                var userEvents = e.sender;
                if (Math.abs(e.x.velocity) < Math.abs(e.y.velocity) || kendo.triggeredByInput(e.event) || !this._currentViewIncludedIn(this.options.swipeToOpenViews)) {
                    userEvents.cancel();
                    return;
                }
                var leftPositioned = this.leftPositioned, visible = this.visible, canMoveLeft = leftPositioned && visible || !leftPositioned && !Drawer.current, canMoveRight = !leftPositioned && visible || leftPositioned && !Drawer.current, leftSwipe = e.x.velocity < 0;
                if (canMoveLeft && leftSwipe || canMoveRight && !leftSwipe) {
                    if (this._activate()) {
                        userEvents.capture();
                        return;
                    }
                }
                userEvents.cancel();
            },
            _update: function (e) {
                var movable = this.movable, newPosition = movable.x + e.x.delta, limitedPosition;
                if (this.leftPositioned) {
                    limitedPosition = Math.min(Math.max(0, newPosition), this.element.width());
                } else {
                    limitedPosition = Math.max(Math.min(0, newPosition), -this.element.width());
                }
                this.movable.moveAxis(AXIS, limitedPosition);
                e.event.preventDefault();
                e.event.stopPropagation();
            },
            _end: function (e) {
                var velocity = e.x.velocity, pastHalf = Math.abs(this.movable.x) > this.element.width() / 2, velocityThreshold = 0.8, shouldShow;
                if (this.leftPositioned) {
                    shouldShow = velocity > -velocityThreshold && (velocity > velocityThreshold || pastHalf);
                } else {
                    shouldShow = velocity < velocityThreshold && (velocity < -velocityThreshold || pastHalf);
                }
                if (shouldShow) {
                    this._show();
                } else {
                    this.hide();
                }
            }
        });
        ui.plugin(Drawer);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.splitview', ['kendo.mobile.pane'], f);
}(function () {
    var __meta__ = {
        id: 'mobile.splitview',
        name: 'SplitView',
        category: 'mobile',
        description: 'The mobile SplitView is a tablet-specific view that consists of two or more mobile Pane widgets.',
        depends: ['mobile.pane']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, EXPANED_PANE_SHIM = '<div class=\'km-expanded-pane-shim\' />', View = ui.View;
        var SplitView = View.extend({
            init: function (element, options) {
                var that = this, pane, modalViews;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                $.extend(that, options);
                that._id();
                if (!that.options.$angular) {
                    that._layout();
                    that._overlay();
                } else {
                    that._overlay();
                }
                that._style();
                modalViews = element.children(that._locate('modalview'));
                if (!that.options.$angular) {
                    kendo.mobile.init(modalViews);
                } else {
                    modalViews.each(function (idx, element) {
                        kendo.compileMobileDirective($(element), options.$angular[0]);
                    });
                }
                that.panes = [];
                that._paramsHistory = [];
                if (!that.options.$angular) {
                    that.content.children(kendo.roleSelector('pane')).each(function () {
                        pane = kendo.initWidget(this, {}, ui.roles);
                        that.panes.push(pane);
                    });
                } else {
                    that.element.children(kendo.directiveSelector('pane')).each(function () {
                        pane = kendo.compileMobileDirective($(this), options.$angular[0]);
                        that.panes.push(pane);
                    });
                    that.element.children(kendo.directiveSelector('header footer')).each(function () {
                        kendo.compileMobileDirective($(this), options.$angular[0]);
                    });
                }
                that.expandedPaneShim = $(EXPANED_PANE_SHIM).appendTo(that.element);
                that._shimUserEvents = new kendo.UserEvents(that.expandedPaneShim, {
                    fastTap: true,
                    tap: function () {
                        that.collapsePanes();
                    }
                });
            },
            _locate: function (selectors) {
                return this.options.$angular ? kendo.directiveSelector(selectors) : kendo.roleSelector(selectors);
            },
            options: {
                name: 'SplitView',
                style: 'horizontal'
            },
            expandPanes: function () {
                this.element.addClass('km-expanded-splitview');
            },
            collapsePanes: function () {
                this.element.removeClass('km-expanded-splitview');
            },
            _layout: function () {
                var that = this, element = that.element;
                that.transition = kendo.attrValue(element, 'transition');
                kendo.mobile.ui.View.prototype._layout.call(this);
                kendo.mobile.init(this.header.add(this.footer));
                that.element.addClass('km-splitview');
                that.content.addClass('km-split-content');
            },
            _style: function () {
                var style = this.options.style, element = this.element, styles;
                if (style) {
                    styles = style.split(' ');
                    $.each(styles, function () {
                        element.addClass('km-split-' + this);
                    });
                }
            },
            showStart: function () {
                var that = this;
                that.element.css('display', '');
                if (!that.inited) {
                    that.inited = true;
                    $.each(that.panes, function () {
                        if (this.options.initial) {
                            this.navigateToInitial();
                        } else {
                            this.navigate('');
                        }
                    });
                    that.trigger('init', { view: that });
                } else {
                    this._invokeNgController();
                }
                that.trigger('show', { view: that });
            }
        });
        ui.plugin(SplitView);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.application', [
        'kendo.mobile.pane',
        'kendo.router'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.application',
        name: 'Application',
        category: 'mobile',
        description: 'The Mobile application provides a framework to build native looking web applications on mobile devices.',
        depends: [
            'mobile.pane',
            'router'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, support = kendo.support, Widget = mobile.ui.Widget, Pane = mobile.ui.Pane, DEFAULT_OS = 'ios7', OS = support.mobileOS, BERRYPHONEGAP = OS.device == 'blackberry' && OS.flatVersion >= 600 && OS.flatVersion < 1000 && OS.appMode, FONT_SIZE_COEF = 0.93, VERTICAL = 'km-vertical', CHROME = OS.browser === 'chrome', BROKEN_WEBVIEW_RESIZE = OS.ios && OS.flatVersion >= 700 && OS.flatVersion < 800 && (OS.appMode || CHROME), INITIALLY_HORIZONTAL = Math.abs(window.orientation) / 90 == 1, HORIZONTAL = 'km-horizontal', MOBILE_PLATFORMS = {
                ios7: {
                    ios: true,
                    browser: 'default',
                    device: 'iphone',
                    flatVersion: '700',
                    majorVersion: '7',
                    minorVersion: '0.0',
                    name: 'ios',
                    tablet: false
                },
                ios: {
                    ios: true,
                    browser: 'default',
                    device: 'iphone',
                    flatVersion: '612',
                    majorVersion: '6',
                    minorVersion: '1.2',
                    name: 'ios',
                    tablet: false
                },
                android: {
                    android: true,
                    browser: 'default',
                    device: 'android',
                    flatVersion: '442',
                    majorVersion: '4',
                    minorVersion: '4.2',
                    name: 'android',
                    tablet: false
                },
                blackberry: {
                    blackberry: true,
                    browser: 'default',
                    device: 'blackberry',
                    flatVersion: '710',
                    majorVersion: '7',
                    minorVersion: '1.0',
                    name: 'blackberry',
                    tablet: false
                },
                meego: {
                    meego: true,
                    browser: 'default',
                    device: 'meego',
                    flatVersion: '850',
                    majorVersion: '8',
                    minorVersion: '5.0',
                    name: 'meego',
                    tablet: false
                },
                wp: {
                    wp: true,
                    browser: 'default',
                    device: 'wp',
                    flatVersion: '800',
                    majorVersion: '8',
                    minorVersion: '0.0',
                    name: 'wp',
                    tablet: false
                }
            }, viewportTemplate = kendo.template('<meta content="initial-scale=#: data.scale #, maximum-scale=#: data.scale #, user-scalable=no#=data.height#" name="viewport" />', { usedWithBlock: false }), systemMeta = kendo.template('<meta name="apple-mobile-web-app-capable" content="#= data.webAppCapable === false ? \'no\' : \'yes\' #" /> ' + '<meta name="apple-mobile-web-app-status-bar-style" content="#=data.statusBarStyle#" /> ' + '<meta name="msapplication-tap-highlight" content="no" /> ', { usedWithBlock: false }), clipTemplate = kendo.template('<style>.km-view { clip: rect(0 #= data.width #px #= data.height #px 0); }</style>', { usedWithBlock: false }), ENABLE_CLIP = OS.android && OS.browser != 'chrome' || OS.blackberry, iconMeta = kendo.template('<link rel="apple-touch-icon' + (OS.android ? '-precomposed' : '') + '" # if(data.size) { # sizes="#=data.size#" #}# href="#=data.icon#" />', { usedWithBlock: false }), HIDEBAR = (OS.device == 'iphone' || OS.device == 'ipod') && OS.majorVersion < 7, SUPPORT_SWIPE_TO_GO_BACK = (OS.device == 'iphone' || OS.device == 'ipod') && OS.majorVersion >= 7, HISTORY_TRANSITION = SUPPORT_SWIPE_TO_GO_BACK ? 'none' : null, BARCOMPENSATION = OS.browser == 'mobilesafari' ? 60 : 0, STATUS_BAR_HEIGHT = 20, WINDOW = $(window), SCREEN = window.screen, HEAD = $('head'), INIT = 'init', proxy = $.proxy;
        function osCssClass(os, options) {
            var classes = [];
            if (OS) {
                classes.push('km-on-' + OS.name);
            }
            if (os.skin) {
                classes.push('km-' + os.skin);
            } else {
                if (os.name == 'ios' && os.majorVersion > 6) {
                    classes.push('km-ios7');
                } else {
                    classes.push('km-' + os.name);
                }
            }
            if (os.name == 'ios' && os.majorVersion < 7 || os.name != 'ios') {
                classes.push('km-' + os.name + os.majorVersion);
            }
            classes.push('km-' + os.majorVersion);
            classes.push('km-m' + (os.minorVersion ? os.minorVersion[0] : 0));
            if (os.variant && (os.skin && os.skin === os.name || !os.skin || os.setDefaultPlatform === false)) {
                classes.push('km-' + (os.skin ? os.skin : os.name) + '-' + os.variant);
            }
            if (os.cordova) {
                classes.push('km-cordova');
            }
            if (os.appMode) {
                classes.push('km-app');
            } else {
                classes.push('km-web');
            }
            if (options && options.statusBarStyle) {
                classes.push('km-' + options.statusBarStyle + '-status-bar');
            }
            return classes.join(' ');
        }
        function wp8Background(os) {
            return 'km-wp-' + (os.noVariantSet ? parseInt($('<div style=\'background: Background\' />').css('background-color').split(',')[1], 10) === 0 ? 'dark' : 'light' : os.variant + ' km-wp-' + os.variant + '-force');
        }
        function isOrientationHorizontal(element) {
            return OS.wp ? element.css('animation-name') == '-kendo-landscape' : Math.abs(window.orientation) / 90 == 1;
        }
        function getOrientationClass(element) {
            return isOrientationHorizontal(element) ? HORIZONTAL : VERTICAL;
        }
        function setMinimumHeight(pane) {
            pane.parent().addBack().css('min-height', window.innerHeight);
        }
        function applyViewportHeight() {
            $('meta[name=viewport]').remove();
            HEAD.append(viewportTemplate({ height: ', width=device-width' + (isOrientationHorizontal() ? ', height=' + window.innerHeight + 'px' : support.mobileOS.flatVersion >= 600 && support.mobileOS.flatVersion < 700 ? ', height=' + window.innerWidth + 'px' : ', height=device-height') }));
        }
        var Application = Widget.extend({
            init: function (element, options) {
                mobile.application = this;
                $($.proxy(this, 'bootstrap', element, options));
            },
            bootstrap: function (element, options) {
                element = $(element);
                if (!element[0]) {
                    element = $(document.body);
                }
                Widget.fn.init.call(this, element, options);
                this.element.removeAttr('data-' + kendo.ns + 'role');
                this._setupPlatform();
                this._attachMeta();
                this._setupElementClass();
                this._attachHideBarHandlers();
                var paneOptions = $.extend({}, this.options);
                delete paneOptions.name;
                var that = this, startHistory = function () {
                        that.pane = new Pane(that.element, paneOptions);
                        that.pane.navigateToInitial();
                        if (that.options.updateDocumentTitle) {
                            that._setupDocumentTitle();
                        }
                        that._startHistory();
                        that.trigger(INIT);
                    };
                if (this.options.$angular) {
                    setTimeout(startHistory);
                } else {
                    startHistory();
                }
            },
            options: {
                name: 'Application',
                hideAddressBar: true,
                browserHistory: true,
                historyTransition: HISTORY_TRANSITION,
                modelScope: window,
                statusBarStyle: 'black',
                transition: '',
                retina: false,
                platform: null,
                skin: null,
                updateDocumentTitle: true,
                useNativeScrolling: false
            },
            events: [INIT],
            navigate: function (url, transition) {
                this.pane.navigate(url, transition);
            },
            replace: function (url, transition) {
                this.pane.replace(url, transition);
            },
            scroller: function () {
                return this.view().scroller;
            },
            hideLoading: function () {
                if (this.pane) {
                    this.pane.hideLoading();
                } else {
                    throw new Error('The mobile application instance is not fully instantiated. Please consider activating loading in the application init event handler.');
                }
            },
            showLoading: function () {
                if (this.pane) {
                    this.pane.showLoading();
                } else {
                    throw new Error('The mobile application instance is not fully instantiated. Please consider activating loading in the application init event handler.');
                }
            },
            changeLoadingMessage: function (message) {
                if (this.pane) {
                    this.pane.changeLoadingMessage(message);
                } else {
                    throw new Error('The mobile application instance is not fully instantiated. Please consider changing the message in the application init event handler.');
                }
            },
            view: function () {
                return this.pane.view();
            },
            skin: function (skin) {
                var that = this;
                if (!arguments.length) {
                    return that.options.skin;
                }
                that.options.skin = skin || '';
                that.element[0].className = 'km-pane';
                that._setupPlatform();
                that._setupElementClass();
                return that.options.skin;
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.pane.destroy();
                if (this.options.browserHistory) {
                    this.router.destroy();
                }
            },
            _setupPlatform: function () {
                var that = this, platform = that.options.platform, skin = that.options.skin, split = [], os = OS || MOBILE_PLATFORMS[DEFAULT_OS];
                if (platform) {
                    os.setDefaultPlatform = true;
                    if (typeof platform === 'string') {
                        split = platform.split('-');
                        os = $.extend({ variant: split[1] }, os, MOBILE_PLATFORMS[split[0]]);
                    } else {
                        os = platform;
                    }
                }
                if (skin) {
                    split = skin.split('-');
                    if (!OS) {
                        os.setDefaultPlatform = false;
                    }
                    os = $.extend({}, os, {
                        skin: split[0],
                        variant: split[1]
                    });
                }
                if (!os.variant) {
                    os.noVariantSet = true;
                    os.variant = 'dark';
                }
                that.os = os;
                that.osCssClass = osCssClass(that.os, that.options);
                if (os.name == 'wp') {
                    if (!that.refreshBackgroundColorProxy) {
                        that.refreshBackgroundColorProxy = $.proxy(function () {
                            if (that.os.variant && (that.os.skin && that.os.skin === that.os.name) || !that.os.skin) {
                                that.element.removeClass('km-wp-dark km-wp-light km-wp-dark-force km-wp-light-force').addClass(wp8Background(that.os));
                            }
                        }, that);
                    }
                    $(document).off('visibilitychange', that.refreshBackgroundColorProxy);
                    $(document).off('resume', that.refreshBackgroundColorProxy);
                    if (!os.skin) {
                        that.element.parent().css('overflow', 'hidden');
                        $(document).on('visibilitychange', that.refreshBackgroundColorProxy);
                        $(document).on('resume', that.refreshBackgroundColorProxy);
                        that.refreshBackgroundColorProxy();
                    }
                }
            },
            _startHistory: function () {
                if (this.options.browserHistory) {
                    this.router = new kendo.Router({
                        pushState: this.options.pushState,
                        root: this.options.root,
                        hashBang: this.options.hashBang
                    });
                    this.pane.bindToRouter(this.router);
                    this.router.start();
                } else {
                    if (!this.options.initial) {
                        this.pane.navigate('');
                    }
                }
            },
            _resizeToScreenHeight: function () {
                var includeStatusBar = $('meta[name=apple-mobile-web-app-status-bar-style]').attr('content').match(/black-translucent|hidden/), element = this.element, height;
                if (CHROME) {
                    height = window.innerHeight;
                } else {
                    if (isOrientationHorizontal(element)) {
                        if (includeStatusBar) {
                            if (INITIALLY_HORIZONTAL) {
                                height = SCREEN.availWidth + STATUS_BAR_HEIGHT;
                            } else {
                                height = SCREEN.availWidth;
                            }
                        } else {
                            if (INITIALLY_HORIZONTAL) {
                                height = SCREEN.availWidth;
                            } else {
                                height = SCREEN.availWidth - STATUS_BAR_HEIGHT;
                            }
                        }
                    } else {
                        if (includeStatusBar) {
                            if (INITIALLY_HORIZONTAL) {
                                height = SCREEN.availHeight;
                            } else {
                                height = SCREEN.availHeight + STATUS_BAR_HEIGHT;
                            }
                        } else {
                            if (INITIALLY_HORIZONTAL) {
                                height = SCREEN.availHeight - STATUS_BAR_HEIGHT;
                            } else {
                                height = SCREEN.availHeight;
                            }
                        }
                    }
                }
                element.height(height);
            },
            _setupElementClass: function () {
                var that = this, size, element = that.element;
                element.parent().addClass('km-root km-' + (that.os.tablet ? 'tablet' : 'phone'));
                element.addClass(that.osCssClass + ' ' + getOrientationClass(element));
                if (this.options.useNativeScrolling) {
                    element.parent().addClass('km-native-scrolling');
                }
                if (CHROME) {
                    element.addClass('km-ios-chrome');
                }
                if (support.wpDevicePixelRatio) {
                    element.parent().css('font-size', support.wpDevicePixelRatio + 'em');
                }
                if (this.options.retina) {
                    element.parent().addClass('km-retina');
                    element.parent().css('font-size', support.devicePixelRatio * FONT_SIZE_COEF + 'em');
                }
                if (BERRYPHONEGAP) {
                    applyViewportHeight();
                }
                if (that.options.useNativeScrolling) {
                    element.parent().addClass('km-native-scrolling');
                } else if (ENABLE_CLIP) {
                    size = (screen.availWidth > screen.availHeight ? screen.availWidth : screen.availHeight) + 200;
                    $(clipTemplate({
                        width: size,
                        height: size
                    })).appendTo(HEAD);
                }
                if (BROKEN_WEBVIEW_RESIZE) {
                    that._resizeToScreenHeight();
                }
                kendo.onResize(function () {
                    element.removeClass('km-horizontal km-vertical').addClass(getOrientationClass(element));
                    if (that.options.useNativeScrolling) {
                        setMinimumHeight(element);
                    }
                    if (BROKEN_WEBVIEW_RESIZE) {
                        that._resizeToScreenHeight();
                    }
                    if (BERRYPHONEGAP) {
                        applyViewportHeight();
                    }
                    kendo.resize(element);
                });
            },
            _clearExistingMeta: function () {
                HEAD.find('meta').filter('[name|=\'apple-mobile-web-app\'],[name|=\'msapplication-tap\'],[name=\'viewport\']').remove();
            },
            _attachMeta: function () {
                var options = this.options, icon = options.icon, size;
                this._clearExistingMeta();
                if (!BERRYPHONEGAP) {
                    HEAD.prepend(viewportTemplate({
                        height: '',
                        scale: this.options.retina ? 1 / support.devicePixelRatio : '1.0'
                    }));
                }
                HEAD.prepend(systemMeta(options));
                if (icon) {
                    if (typeof icon === 'string') {
                        icon = { '': icon };
                    }
                    for (size in icon) {
                        HEAD.prepend(iconMeta({
                            icon: icon[size],
                            size: size
                        }));
                    }
                }
                if (options.useNativeScrolling) {
                    setMinimumHeight(this.element);
                }
            },
            _attachHideBarHandlers: function () {
                var that = this, hideBar = proxy(that, '_hideBar');
                if (support.mobileOS.appMode || !that.options.hideAddressBar || !HIDEBAR || that.options.useNativeScrolling) {
                    return;
                }
                that._initialHeight = {};
                WINDOW.on('load', hideBar);
                kendo.onResize(function () {
                    setTimeout(window.scrollTo, 0, 0, 1);
                });
            },
            _setupDocumentTitle: function () {
                var that = this, defaultTitle = document.title;
                that.pane.bind('viewShow', function (e) {
                    var title = e.view.title;
                    document.title = title !== undefined ? title : defaultTitle;
                });
            },
            _hideBar: function () {
                var that = this, element = that.element;
                element.height(kendo.support.transforms.css + 'calc(100% + ' + BARCOMPENSATION + 'px)');
                $(window).trigger(kendo.support.resize);
            }
        });
        kendo.mobile.Application = Application;
        kendo.ui.plugin(Application, kendo.mobile, 'Mobile');
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.button', ['kendo.userevents'], f);
}(function () {
    var __meta__ = {
        id: 'mobile.button',
        name: 'Button',
        category: 'mobile',
        description: 'The Button widget navigates between mobile Application views when pressed.',
        depends: ['userevents']
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, Widget = ui.Widget, support = kendo.support, os = support.mobileOS, ANDROID3UP = os.android && os.flatVersion >= 300, CLICK = 'click', DISABLED = 'disabled', DISABLEDSTATE = 'km-state-disabled';
        function highlightButton(widget, event, highlight) {
            $(event.target).closest('.km-button,.km-detail').toggleClass('km-state-active', highlight);
            if (ANDROID3UP && widget.deactivateTimeoutID) {
                clearTimeout(widget.deactivateTimeoutID);
                widget.deactivateTimeoutID = 0;
            }
        }
        function createBadge(value) {
            return $('<span class="km-badge">' + value + '</span>');
        }
        var Button = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                var useTap = that.options.clickOn === 'up';
                that._wrap();
                that._style();
                if (!useTap) {
                    that.element.attr('data-navigate-on-press', true);
                }
                that.options.enable = that.options.enable && !that.element.attr(DISABLED);
                that.enable(that.options.enable);
                that._userEvents = new kendo.UserEvents(that.element, {
                    allowSelection: !useTap,
                    fastTap: true,
                    press: function (e) {
                        that._activate(e);
                    },
                    release: function (e) {
                        highlightButton(that, e, false);
                        if (!useTap) {
                            e.event.stopPropagation();
                        }
                    }
                });
                that._userEvents.bind(useTap ? 'tap' : 'press', function (e) {
                    that._release(e);
                });
                if (ANDROID3UP) {
                    that.element.on('move', function (e) {
                        that._timeoutDeactivate(e);
                    });
                }
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this._userEvents.destroy();
            },
            events: [CLICK],
            options: {
                name: 'Button',
                icon: '',
                style: '',
                badge: '',
                clickOn: 'up',
                enable: true
            },
            badge: function (value) {
                var badge = this.badgeElement = this.badgeElement || createBadge(value).appendTo(this.element);
                if (value || value === 0) {
                    badge.html(value);
                    return this;
                }
                if (value === false) {
                    badge.empty().remove();
                    this.badgeElement = false;
                    return this;
                }
                return badge.html();
            },
            enable: function (enable) {
                var element = this.element;
                if (typeof enable == 'undefined') {
                    enable = true;
                }
                this.options.enable = enable;
                if (enable) {
                    element.removeAttr(DISABLED);
                } else {
                    element.attr(DISABLED, DISABLED);
                }
                element.toggleClass(DISABLEDSTATE, !enable);
            },
            _timeoutDeactivate: function (e) {
                if (!this.deactivateTimeoutID) {
                    this.deactivateTimeoutID = setTimeout(highlightButton, 500, this, e, false);
                }
            },
            _activate: function (e) {
                var activeElement = document.activeElement, nodeName = activeElement ? activeElement.nodeName : '';
                if (this.options.enable) {
                    highlightButton(this, e, true);
                    if (nodeName == 'INPUT' || nodeName == 'TEXTAREA') {
                        activeElement.blur();
                    }
                }
            },
            _release: function (e) {
                var that = this;
                if (e.which > 1) {
                    return;
                }
                if (!that.options.enable) {
                    e.preventDefault();
                    return;
                }
                if (that.trigger(CLICK, {
                        target: $(e.target),
                        button: that.element
                    })) {
                    e.preventDefault();
                }
            },
            _style: function () {
                var style = this.options.style, element = this.element, styles;
                if (style) {
                    styles = style.split(' ');
                    $.each(styles, function () {
                        element.addClass('km-' + this);
                    });
                }
            },
            _wrap: function () {
                var that = this, icon = that.options.icon, badge = that.options.badge, iconSpan = '<span class="km-icon km-' + icon, element = that.element.addClass('km-button'), span = element.children('span:not(.km-icon)').addClass('km-text'), image = element.find('img').addClass('km-image');
                if (!span[0] && element.html()) {
                    span = element.wrapInner('<span class="km-text" />').children('span.km-text');
                }
                if (!image[0] && icon) {
                    if (!span[0]) {
                        iconSpan += ' km-notext';
                    }
                    that.iconElement = element.prepend($(iconSpan + '" />'));
                }
                if (badge || badge === 0) {
                    that.badgeElement = createBadge(badge).appendTo(element);
                }
            }
        });
        var BackButton = Button.extend({
            options: {
                name: 'BackButton',
                style: 'back'
            },
            init: function (element, options) {
                var that = this;
                Button.fn.init.call(that, element, options);
                if (typeof that.element.attr('href') === 'undefined') {
                    that.element.attr('href', '#:back');
                }
            }
        });
        var DetailButton = Button.extend({
            options: {
                name: 'DetailButton',
                style: ''
            },
            init: function (element, options) {
                Button.fn.init.call(this, element, options);
            },
            _style: function () {
                var style = this.options.style + ' detail', element = this.element;
                if (style) {
                    var styles = style.split(' ');
                    $.each(styles, function () {
                        element.addClass('km-' + this);
                    });
                }
            },
            _wrap: function () {
                var that = this, icon = that.options.icon, iconSpan = '<span class="km-icon km-' + icon, element = that.element, span = element.children('span'), image = element.find('img').addClass('km-image');
                if (!image[0] && icon) {
                    if (!span[0]) {
                        iconSpan += ' km-notext';
                    }
                    element.prepend($(iconSpan + '" />'));
                }
            }
        });
        ui.plugin(Button);
        ui.plugin(BackButton);
        ui.plugin(DetailButton);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.buttongroup', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'mobile.buttongroup',
        name: 'ButtonGroup',
        category: 'mobile',
        description: 'The Kendo mobile ButtonGroup widget is a linear set of grouped buttons.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, ACTIVE = 'state-active', DISABLE = 'state-disabled', SELECT = 'select', SELECTOR = 'li:not(.km-' + ACTIVE + ')';
        function className(name) {
            return 'k-' + name + ' km-' + name;
        }
        function createBadge(value) {
            return $('<span class="' + className('badge') + '">' + value + '</span>');
        }
        var ButtonGroup = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.element.addClass('km-buttongroup k-widget k-button-group').find('li').each(that._button);
                that.element.on(that.options.selectOn, SELECTOR, '_select');
                that._enable = true;
                that.select(that.options.index);
                if (!that.options.enable) {
                    that._enable = false;
                    that.wrapper.addClass(className(DISABLE));
                }
            },
            events: [SELECT],
            options: {
                name: 'ButtonGroup',
                selectOn: 'down',
                index: -1,
                enable: true
            },
            current: function () {
                return this.element.find('.km-' + ACTIVE);
            },
            select: function (li) {
                var that = this, index = -1;
                if (li === undefined || li === -1 || !that._enable || $(li).is('.km-' + DISABLE)) {
                    return;
                }
                that.current().removeClass(className(ACTIVE));
                if (typeof li === 'number') {
                    index = li;
                    li = $(that.element[0].children[li]);
                } else if (li.nodeType) {
                    li = $(li);
                    index = li.index();
                }
                li.addClass(className(ACTIVE));
                that.selectedIndex = index;
            },
            badge: function (item, value) {
                var buttongroup = this.element, badge;
                if (!isNaN(item)) {
                    item = buttongroup.children().get(item);
                }
                item = buttongroup.find(item);
                badge = $(item.children('.km-badge')[0] || createBadge(value).appendTo(item));
                if (value || value === 0) {
                    badge.html(value);
                    return this;
                }
                if (value === false) {
                    badge.empty().remove();
                    return this;
                }
                return badge.html();
            },
            enable: function (enable) {
                if (typeof enable == 'undefined') {
                    enable = true;
                }
                this.wrapper.toggleClass(className(DISABLE), !enable);
                this._enable = this.options.enable = enable;
            },
            _button: function () {
                var button = $(this).addClass(className('button')), icon = kendo.attrValue(button, 'icon'), badge = kendo.attrValue(button, 'badge'), span = button.children('span'), image = button.find('img').addClass(className('image'));
                if (!span[0]) {
                    span = button.wrapInner('<span/>').children('span');
                }
                span.addClass(className('text'));
                if (!image[0] && icon) {
                    button.prepend($('<span class="' + className('icon') + ' ' + className(icon) + '"/>'));
                }
                if (badge || badge === 0) {
                    createBadge(badge).appendTo(button);
                }
            },
            _select: function (e) {
                if (e.which > 1 || e.isDefaultPrevented() || !this._enable) {
                    return;
                }
                this.select(e.currentTarget);
                this.trigger(SELECT, { index: this.selectedIndex });
            }
        });
        ui.plugin(ButtonGroup);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.collapsible', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'mobile.collapsible',
        name: 'Collapsible',
        category: 'mobile',
        description: 'The Kendo mobile Collapsible widget provides ability for creating collapsible blocks of content.',
        depends: [
            'core',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, COLLAPSIBLE = 'km-collapsible', HEADER = 'km-collapsible-header', CONTENT = 'km-collapsible-content', INSET = 'km-collapsibleinset', HEADER_WRAPPER = '<div data-role=\'collapsible-header\' class=\'' + HEADER + '\'></div>', CONTENT_WRAPPER = '<div data-role=\'collapsible-content\' class=\'' + CONTENT + '\'></div>', COLLAPSED = 'km-collapsed', EXPANDED = 'km-expanded', ANIMATED = 'km-animated', LEFT = 'left', EXAPND = 'expand', COLLAPSE = 'collapse';
        var Collapsible = Widget.extend({
            init: function (element, options) {
                var that = this, container = $(element);
                Widget.fn.init.call(that, container, options);
                container.addClass(COLLAPSIBLE);
                that._buildHeader();
                that.content = container.children().not(that.header).wrapAll(CONTENT_WRAPPER).parent();
                that._userEvents = new kendo.UserEvents(that.header, {
                    fastTap: true,
                    tap: function () {
                        that.toggle();
                    }
                });
                container.addClass(that.options.collapsed ? COLLAPSED : EXPANDED);
                if (that.options.inset) {
                    container.addClass(INSET);
                }
                if (that.options.animation) {
                    that.content.addClass(ANIMATED);
                    that.content.height(0);
                    if (that.options.collapsed) {
                        that.content.hide();
                    }
                } else if (that.options.collapsed) {
                    that.content.hide();
                }
            },
            events: [
                EXAPND,
                COLLAPSE
            ],
            options: {
                name: 'Collapsible',
                collapsed: true,
                collapseIcon: 'arrow-n',
                expandIcon: 'arrow-s',
                iconPosition: LEFT,
                animation: true,
                inset: false
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this._userEvents.destroy();
            },
            expand: function (instant) {
                var icon = this.options.collapseIcon, content = this.content, ios = kendo.support.mobileOS.ios;
                if (!this.trigger(EXAPND)) {
                    if (icon) {
                        this.header.find('.km-icon').removeClass().addClass('km-icon km-' + icon);
                    }
                    this.element.removeClass(COLLAPSED).addClass(EXPANDED);
                    if (this.options.animation && !instant) {
                        content.off('transitionend');
                        content.show();
                        if (ios) {
                            content.removeClass(ANIMATED);
                        }
                        content.height(this._getContentHeight());
                        if (ios) {
                            content.addClass(ANIMATED);
                        }
                        kendo.resize(content);
                    } else {
                        content.show();
                    }
                }
            },
            collapse: function (instant) {
                var icon = this.options.expandIcon, content = this.content;
                if (!this.trigger(COLLAPSE)) {
                    if (icon) {
                        this.header.find('.km-icon').removeClass().addClass('km-icon km-' + icon);
                    }
                    this.element.removeClass(EXPANDED).addClass(COLLAPSED);
                    if (this.options.animation && !instant) {
                        content.one('transitionend', function () {
                            content.hide();
                        });
                        content.height(0);
                    } else {
                        content.hide();
                    }
                }
            },
            toggle: function (instant) {
                if (this.isCollapsed()) {
                    this.expand(instant);
                } else {
                    this.collapse(instant);
                }
            },
            isCollapsed: function () {
                return this.element.hasClass(COLLAPSED);
            },
            resize: function () {
                if (!this.isCollapsed() && this.options.animation) {
                    this.content.height(this._getContentHeight());
                }
            },
            _buildHeader: function () {
                var header = this.element.children(':header').wrapAll(HEADER_WRAPPER), iconSpan = $('<span class="km-icon"/>'), icon = this.options.collapsed ? this.options.expandIcon : this.options.collapseIcon, iconPosition = this.options.iconPosition;
                if (icon) {
                    header.prepend(iconSpan);
                    iconSpan.addClass('km-' + icon);
                }
                this.header = header.parent();
                this.header.addClass('km-icon-' + iconPosition);
            },
            _getContentHeight: function () {
                var style = this.content.attr('style'), height;
                this.content.css({
                    position: 'absolute',
                    visibility: 'hidden',
                    height: 'auto'
                });
                height = this.content.height();
                this.content.attr('style', style ? style : '');
                return height;
            }
        });
        ui.plugin(Collapsible);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.listview', [
        'kendo.data',
        'kendo.userevents',
        'kendo.mobile.button'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.listview',
        name: 'ListView',
        category: 'mobile',
        description: 'The Kendo Mobile ListView widget is used to display flat or grouped list of items.',
        depends: [
            'data',
            'userevents',
            'mobile.button'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, Node = window.Node, mobile = kendo.mobile, ui = mobile.ui, outerHeight = kendo._outerHeight, DataSource = kendo.data.DataSource, Widget = ui.DataBoundWidget, ITEM_SELECTOR = '.km-list > li, > li:not(.km-group-container)', HIGHLIGHT_SELECTOR = '.km-listview-link, .km-listview-label', ICON_SELECTOR = '[' + kendo.attr('icon') + ']', proxy = $.proxy, attrValue = kendo.attrValue, GROUP_CLASS = 'km-group-title', ACTIVE_CLASS = 'km-state-active', GROUP_WRAPPER = '<div class="' + GROUP_CLASS + '"><div class="km-text"></div></div>', GROUP_TEMPLATE = kendo.template('<li><div class="' + GROUP_CLASS + '"><div class="km-text">#= this.headerTemplate(data) #</div></div><ul>#= kendo.render(this.template, data.items)#</ul></li>'), WRAPPER = '<div class="km-listview-wrapper" />', SEARCH_TEMPLATE = kendo.template('<form class="km-filter-form"><div class="km-filter-wrap"><input type="search" placeholder="#=placeholder#"/><a href="\\#" class="km-filter-reset" title="Clear"><span class="km-icon km-clear"></span><span class="km-text">Clear</span></a></div></form>'), NS = '.kendoMobileListView', STYLED = 'styled', DATABOUND = 'dataBound', DATABINDING = 'dataBinding', ITEM_CHANGE = 'itemChange', CLICK = 'click', CHANGE = 'change', PROGRESS = 'progress', FUNCTION = 'function', whitespaceRegExp = /^\s+$/, buttonRegExp = /button/;
        function whitespace() {
            return this.nodeType === Node.TEXT_NODE && this.nodeValue.match(whitespaceRegExp);
        }
        function addIcon(item, icon) {
            if (icon && !item[0].querySelector('.km-icon')) {
                item.prepend('<span class="km-icon km-' + icon + '"/>');
            }
        }
        function enhanceItem(item) {
            addIcon(item, attrValue(item, 'icon'));
            addIcon(item, attrValue(item.children(ICON_SELECTOR), 'icon'));
        }
        function enhanceLinkItem(item) {
            var parent = item.parent(), itemAndDetailButtons = item.add(parent.children(kendo.roleSelector('detailbutton'))), otherNodes = parent.contents().not(itemAndDetailButtons).not(whitespace);
            if (otherNodes.length) {
                return;
            }
            item.addClass('km-listview-link').attr(kendo.attr('role'), 'listview-link');
            addIcon(item, attrValue(parent, 'icon'));
            addIcon(item, attrValue(item, 'icon'));
        }
        function enhanceCheckBoxItem(label) {
            if (!label[0].querySelector('input[type=checkbox],input[type=radio]')) {
                return;
            }
            var item = label.parent();
            if (item.contents().not(label).not(function () {
                    return this.nodeType == 3;
                })[0]) {
                return;
            }
            label.addClass('km-listview-label');
            label.children('[type=checkbox],[type=radio]').addClass('km-widget km-icon km-check');
        }
        function putAt(element, top) {
            $(element).css('transform', 'translate3d(0px, ' + top + 'px, 0px)');
        }
        var HeaderFixer = kendo.Class.extend({
            init: function (listView) {
                var scroller = listView.scroller();
                if (!scroller) {
                    return;
                }
                this.options = listView.options;
                this.element = listView.element;
                this.scroller = listView.scroller();
                this._shouldFixHeaders();
                var headerFixer = this;
                var cacheHeaders = function () {
                    headerFixer._cacheHeaders();
                };
                listView.bind('resize', cacheHeaders);
                listView.bind(STYLED, cacheHeaders);
                listView.bind(DATABOUND, cacheHeaders);
                this._scrollHandler = function (e) {
                    headerFixer._fixHeader(e);
                };
                scroller.bind('scroll', this._scrollHandler);
            },
            destroy: function () {
                var that = this;
                if (that.scroller) {
                    that.scroller.unbind('scroll', that._scrollHandler);
                }
            },
            _fixHeader: function (e) {
                if (!this.fixedHeaders) {
                    return;
                }
                var i = 0, scroller = this.scroller, headers = this.headers, scrollTop = e.scrollTop, headerPair, offset, header;
                do {
                    headerPair = headers[i++];
                    if (!headerPair) {
                        header = $('<div />');
                        break;
                    }
                    offset = headerPair.offset;
                    header = headerPair.header;
                } while (offset + 1 > scrollTop);
                if (this.currentHeader != i) {
                    scroller.fixedContainer.html(header.clone());
                    this.currentHeader = i;
                }
            },
            _shouldFixHeaders: function () {
                this.fixedHeaders = this.options.type === 'group' && this.options.fixedHeaders;
            },
            _cacheHeaders: function () {
                this._shouldFixHeaders();
                if (!this.fixedHeaders) {
                    return;
                }
                var headers = [], offset = this.scroller.scrollTop;
                this.element.find('.' + GROUP_CLASS).each(function (_, header) {
                    header = $(header);
                    headers.unshift({
                        offset: header.position().top + offset,
                        header: header
                    });
                });
                this.headers = headers;
                this._fixHeader({ scrollTop: offset });
            }
        });
        var DEFAULT_PULL_PARAMETERS = function () {
            return { page: 1 };
        };
        var RefreshHandler = kendo.Class.extend({
            init: function (listView) {
                var handler = this, options = listView.options, scroller = listView.scroller(), pullParameters = options.pullParameters || DEFAULT_PULL_PARAMETERS;
                this.listView = listView;
                this.scroller = scroller;
                listView.bind('_dataSource', function (e) {
                    handler.setDataSource(e.dataSource);
                });
                scroller.setOptions({
                    pullToRefresh: true,
                    pull: function () {
                        if (!handler._pulled) {
                            handler._pulled = true;
                            handler.dataSource.read(pullParameters.call(listView, handler._first));
                        }
                    },
                    messages: {
                        pullTemplate: options.messages.pullTemplate,
                        releaseTemplate: options.messages.releaseTemplate,
                        refreshTemplate: options.messages.refreshTemplate
                    }
                });
            },
            setDataSource: function (dataSource) {
                var handler = this;
                this._first = dataSource.view()[0];
                this.dataSource = dataSource;
                dataSource.bind('change', function () {
                    handler._change();
                });
                dataSource.bind('error', function () {
                    handler._change();
                });
            },
            _change: function () {
                var scroller = this.scroller, dataSource = this.dataSource;
                if (this._pulled) {
                    scroller.pullHandled();
                }
                if (this._pulled || !this._first) {
                    var view = dataSource.view();
                    if (view[0]) {
                        this._first = view[0];
                    }
                }
                this._pulled = false;
            }
        });
        var VirtualList = kendo.Observable.extend({
            init: function (options) {
                var list = this;
                kendo.Observable.fn.init.call(list);
                list.buffer = options.buffer;
                list.height = options.height;
                list.item = options.item;
                list.items = [];
                list.footer = options.footer;
                list.buffer.bind('reset', function () {
                    list.refresh();
                });
            },
            refresh: function () {
                var buffer = this.buffer, items = this.items, endReached = false;
                while (items.length) {
                    items.pop().destroy();
                }
                this.offset = buffer.offset;
                var itemConstructor = this.item, prevItem, item;
                for (var idx = 0; idx < buffer.viewSize; idx++) {
                    if (idx === buffer.total()) {
                        endReached = true;
                        break;
                    }
                    item = itemConstructor(this.content(this.offset + items.length));
                    item.below(prevItem);
                    prevItem = item;
                    items.push(item);
                }
                this.itemCount = items.length;
                this.trigger('reset');
                this._resize();
                if (endReached) {
                    this.trigger('endReached');
                }
            },
            totalHeight: function () {
                if (!this.items[0]) {
                    return 0;
                }
                var list = this, items = list.items, top = items[0].top, bottom = items[items.length - 1].bottom, averageItemHeight = (bottom - top) / list.itemCount, remainingItemsCount = list.buffer.length - list.offset - list.itemCount;
                return (this.footer ? this.footer.height : 0) + bottom + remainingItemsCount * averageItemHeight;
            },
            batchUpdate: function (top) {
                var height = this.height(), items = this.items, item, initialOffset = this.offset;
                if (!items[0]) {
                    return;
                }
                if (this.lastDirection) {
                    while (items[items.length - 1].bottom > top + height * 2) {
                        if (this.offset === 0) {
                            break;
                        }
                        this.offset--;
                        item = items.pop();
                        item.update(this.content(this.offset));
                        item.above(items[0]);
                        items.unshift(item);
                    }
                } else {
                    while (items[0].top < top - height) {
                        var nextIndex = this.offset + this.itemCount;
                        if (nextIndex === this.buffer.total()) {
                            this.trigger('endReached');
                            break;
                        }
                        if (nextIndex === this.buffer.length) {
                            break;
                        }
                        item = items.shift();
                        item.update(this.content(this.offset + this.itemCount));
                        item.below(items[items.length - 1]);
                        items.push(item);
                        this.offset++;
                    }
                }
                if (initialOffset !== this.offset) {
                    this._resize();
                }
            },
            update: function (top) {
                var list = this, items = this.items, item, firstItem, lastItem, height = this.height(), itemCount = this.itemCount, padding = height / 2, up = (this.lastTop || 0) > top, topBorder = top - padding, bottomBorder = top + height + padding;
                if (!items[0]) {
                    return;
                }
                this.lastTop = top;
                this.lastDirection = up;
                if (up) {
                    if (items[0].top > topBorder && items[items.length - 1].bottom > bottomBorder + padding && this.offset > 0) {
                        this.offset--;
                        item = items.pop();
                        firstItem = items[0];
                        item.update(this.content(this.offset));
                        items.unshift(item);
                        item.above(firstItem);
                        list._resize();
                    }
                } else {
                    if (items[items.length - 1].bottom < bottomBorder && items[0].top < topBorder - padding) {
                        var nextIndex = this.offset + itemCount;
                        if (nextIndex === this.buffer.total()) {
                            this.trigger('endReached');
                        } else if (nextIndex !== this.buffer.length) {
                            item = items.shift();
                            lastItem = items[items.length - 1];
                            items.push(item);
                            item.update(this.content(this.offset + this.itemCount));
                            list.offset++;
                            item.below(lastItem);
                            list._resize();
                        }
                    }
                }
            },
            content: function (index) {
                return this.buffer.at(index);
            },
            destroy: function () {
                this.unbind();
            },
            _resize: function () {
                var items = this.items, top = 0, bottom = 0, firstItem = items[0], lastItem = items[items.length - 1];
                if (firstItem) {
                    top = firstItem.top;
                    bottom = lastItem.bottom;
                }
                this.trigger('resize', {
                    top: top,
                    bottom: bottom
                });
                if (this.footer) {
                    this.footer.below(lastItem);
                }
            }
        });
        kendo.mobile.ui.VirtualList = VirtualList;
        var VirtualListViewItem = kendo.Class.extend({
            init: function (listView, dataItem) {
                var element = listView.append([dataItem], true)[0], height = element.offsetHeight;
                $.extend(this, {
                    top: 0,
                    element: element,
                    listView: listView,
                    height: height,
                    bottom: height
                });
            },
            update: function (dataItem) {
                this.element = this.listView.setDataItem(this.element, dataItem);
            },
            above: function (item) {
                if (item) {
                    this.height = this.element.offsetHeight;
                    this.top = item.top - this.height;
                    this.bottom = item.top;
                    putAt(this.element, this.top);
                }
            },
            below: function (item) {
                if (item) {
                    this.height = this.element.offsetHeight;
                    this.top = item.bottom;
                    this.bottom = this.top + this.height;
                    putAt(this.element, this.top);
                }
            },
            destroy: function () {
                kendo.destroy(this.element);
                $(this.element).remove();
            }
        });
        var LOAD_ICON = '<div><span class="km-icon"></span><span class="km-loading-left"></span><span class="km-loading-right"></span></div>';
        var VirtualListViewLoadingIndicator = kendo.Class.extend({
            init: function (listView) {
                this.element = $('<li class="km-load-more km-scroller-refresh" style="display: none"></li>').appendTo(listView.element);
                this._loadIcon = $(LOAD_ICON).appendTo(this.element);
            },
            enable: function () {
                this.element.show();
                this.height = outerHeight(this.element, true);
            },
            disable: function () {
                this.element.hide();
                this.height = 0;
            },
            below: function (item) {
                if (item) {
                    this.top = item.bottom;
                    this.bottom = this.height + this.top;
                    putAt(this.element, this.top);
                }
            }
        });
        var VirtualListViewPressToLoadMore = VirtualListViewLoadingIndicator.extend({
            init: function (listView, buffer) {
                this._loadIcon = $(LOAD_ICON).hide();
                this._loadButton = $('<a class="km-load">' + listView.options.messages.loadMoreText + '</a>').hide();
                this.element = $('<li class="km-load-more" style="display: none"></li>').append(this._loadIcon).append(this._loadButton).appendTo(listView.element);
                var loadMore = this;
                this._loadButton.kendoMobileButton().data('kendoMobileButton').bind('click', function () {
                    loadMore._hideShowButton();
                    buffer.next();
                });
                buffer.bind('resize', function () {
                    loadMore._showLoadButton();
                });
                this.height = outerHeight(this.element, true);
                this.disable();
            },
            _hideShowButton: function () {
                this._loadButton.hide();
                this.element.addClass('km-scroller-refresh');
                this._loadIcon.css('display', 'block');
            },
            _showLoadButton: function () {
                this._loadButton.show();
                this.element.removeClass('km-scroller-refresh');
                this._loadIcon.hide();
            }
        });
        var VirtualListViewItemBinder = kendo.Class.extend({
            init: function (listView) {
                var binder = this;
                this.chromeHeight = outerHeight(listView.wrapper.children().not(listView.element));
                this.listView = listView;
                this.scroller = listView.scroller();
                this.options = listView.options;
                listView.bind('_dataSource', function (e) {
                    binder.setDataSource(e.dataSource, e.empty);
                });
                listView.bind('resize', function () {
                    if (!binder.list.items.length) {
                        return;
                    }
                    binder.scroller.reset();
                    binder.buffer.range(0);
                    binder.list.refresh();
                });
                this.scroller.makeVirtual();
                this._scroll = function (e) {
                    binder.list.update(e.scrollTop);
                };
                this.scroller.bind('scroll', this._scroll);
                this._scrollEnd = function (e) {
                    binder.list.batchUpdate(e.scrollTop);
                };
                this.scroller.bind('scrollEnd', this._scrollEnd);
            },
            destroy: function () {
                this.list.unbind();
                this.buffer.unbind();
                this.scroller.unbind('scroll', this._scroll);
                this.scroller.unbind('scrollEnd', this._scrollEnd);
            },
            setDataSource: function (dataSource, empty) {
                var binder = this, options = this.options, listView = this.listView, scroller = listView.scroller(), pressToLoadMore = options.loadMore, pageSize, buffer, footer;
                this.dataSource = dataSource;
                pageSize = dataSource.pageSize() || options.virtualViewSize;
                if (!pageSize && !empty) {
                    throw new Error('the DataSource does not have page size configured. Page Size setting is mandatory for the mobile listview virtual scrolling to work as expected.');
                }
                if (this.buffer) {
                    this.buffer.destroy();
                }
                buffer = new kendo.data.Buffer(dataSource, Math.floor(pageSize / 2), pressToLoadMore);
                if (pressToLoadMore) {
                    footer = new VirtualListViewPressToLoadMore(listView, buffer);
                } else {
                    footer = new VirtualListViewLoadingIndicator(listView);
                }
                if (this.list) {
                    this.list.destroy();
                }
                var list = new VirtualList({
                    buffer: buffer,
                    footer: footer,
                    item: function (dataItem) {
                        return new VirtualListViewItem(listView, dataItem);
                    },
                    height: function () {
                        return scroller.height();
                    }
                });
                list.bind('resize', function () {
                    binder.updateScrollerSize();
                    listView.updateSize();
                });
                list.bind('reset', function () {
                    binder.footer.enable();
                });
                list.bind('endReached', function () {
                    footer.disable();
                    binder.updateScrollerSize();
                });
                buffer.bind('expand', function () {
                    list.lastDirection = false;
                    list.batchUpdate(scroller.scrollTop);
                });
                $.extend(this, {
                    buffer: buffer,
                    scroller: scroller,
                    list: list,
                    footer: footer
                });
            },
            updateScrollerSize: function () {
                this.scroller.virtualSize(0, this.list.totalHeight() + this.chromeHeight);
            },
            refresh: function () {
                this.list.refresh();
            },
            reset: function () {
                this.buffer.range(0);
                this.list.refresh();
            }
        });
        var ListViewItemBinder = kendo.Class.extend({
            init: function (listView) {
                var binder = this;
                this.listView = listView;
                this.options = listView.options;
                var itemBinder = this;
                this._refreshHandler = function (e) {
                    itemBinder.refresh(e);
                };
                this._progressHandler = function () {
                    listView.showLoading();
                };
                listView.bind('_dataSource', function (e) {
                    binder.setDataSource(e.dataSource);
                });
            },
            destroy: function () {
                this._unbindDataSource();
            },
            reset: function () {
            },
            refresh: function (e) {
                var action = e && e.action, dataItems = e && e.items, listView = this.listView, dataSource = this.dataSource, prependOnRefresh = this.options.appendOnRefresh, view = dataSource.view(), groups = dataSource.group(), groupedMode = groups && groups[0], item;
                if (action === 'itemchange') {
                    if (!listView._hasBindingTarget()) {
                        item = listView.findByDataItem(dataItems)[0];
                        if (item) {
                            listView.setDataItem(item, dataItems[0]);
                        }
                    }
                    return;
                }
                var removedItems, addedItems, addedDataItems;
                var adding = action === 'add' && !groupedMode || prependOnRefresh && !listView._filter;
                var removing = action === 'remove' && !groupedMode;
                if (adding) {
                    removedItems = [];
                } else if (removing) {
                    removedItems = listView.findByDataItem(dataItems);
                }
                if (listView.trigger(DATABINDING, {
                        action: action || 'rebind',
                        items: dataItems,
                        removedItems: removedItems,
                        index: e && e.index
                    })) {
                    if (this._shouldShowLoading()) {
                        listView.hideLoading();
                    }
                    return;
                }
                if (action === 'add' && !groupedMode) {
                    var index = view.indexOf(dataItems[0]);
                    if (index > -1) {
                        addedItems = listView.insertAt(dataItems, index);
                        addedDataItems = dataItems;
                    }
                } else if (action === 'remove' && !groupedMode) {
                    addedItems = [];
                    listView.remove(dataItems);
                } else if (groupedMode) {
                    listView.replaceGrouped(view);
                } else if (prependOnRefresh && !listView._filter) {
                    addedItems = listView.prepend(view);
                    addedDataItems = view;
                } else {
                    listView.replace(view);
                }
                if (this._shouldShowLoading()) {
                    listView.hideLoading();
                }
                listView.trigger(DATABOUND, {
                    ns: ui,
                    addedItems: addedItems,
                    addedDataItems: addedDataItems
                });
            },
            setDataSource: function (dataSource) {
                if (this.dataSource) {
                    this._unbindDataSource();
                }
                this.dataSource = dataSource;
                dataSource.bind(CHANGE, this._refreshHandler);
                if (this._shouldShowLoading()) {
                    this.dataSource.bind(PROGRESS, this._progressHandler);
                }
            },
            _unbindDataSource: function () {
                this.dataSource.unbind(CHANGE, this._refreshHandler).unbind(PROGRESS, this._progressHandler);
            },
            _shouldShowLoading: function () {
                var options = this.options;
                return !options.pullToRefresh && !options.loadMore && !options.endlessScroll;
            }
        });
        var ListViewFilter = kendo.Class.extend({
            init: function (listView) {
                var filter = this, filterable = listView.options.filterable, events = 'change paste', that = this;
                this.listView = listView;
                this.options = filterable;
                listView.element.before(SEARCH_TEMPLATE({ placeholder: filterable.placeholder || 'Search...' }));
                if (filterable.autoFilter !== false) {
                    events += ' keyup';
                }
                this.element = listView.wrapper.find('.km-search-form');
                this.searchInput = listView.wrapper.find('input[type=search]').closest('form').on('submit' + NS, function (e) {
                    e.preventDefault();
                }).end().on('focus' + NS, function () {
                    filter._oldFilter = filter.searchInput.val();
                }).on(events.split(' ').join(NS + ' ') + NS, proxy(this._filterChange, this));
                this.clearButton = listView.wrapper.find('.km-filter-reset').on(CLICK, proxy(this, '_clearFilter')).hide();
                this._dataSourceChange = $.proxy(this._refreshInput, this);
                listView.bind('_dataSource', function (e) {
                    e.dataSource.bind('change', that._dataSourceChange);
                });
            },
            _refreshInput: function () {
                var appliedFilters = this.listView.dataSource.filter();
                var searchInput = this.listView._filter.searchInput;
                if (!appliedFilters || appliedFilters.filters[0].field !== this.listView.options.filterable.field) {
                    searchInput.val('');
                } else {
                    searchInput.val(appliedFilters.filters[0].value);
                }
            },
            _search: function (expr) {
                this._filter = true;
                this.clearButton[expr ? 'show' : 'hide']();
                this.listView.dataSource.filter(expr);
            },
            _filterChange: function (e) {
                var filter = this;
                if (e.type == 'paste' && this.options.autoFilter !== false) {
                    setTimeout(function () {
                        filter._applyFilter();
                    }, 1);
                } else {
                    this._applyFilter();
                }
            },
            _applyFilter: function () {
                var options = this.options, value = this.searchInput.val(), expr = value.length ? {
                        field: options.field,
                        operator: options.operator || 'startswith',
                        ignoreCase: options.ignoreCase,
                        value: value
                    } : null;
                if (value === this._oldFilter) {
                    return;
                }
                this._oldFilter = value;
                this._search(expr);
            },
            _clearFilter: function (e) {
                this.searchInput.val('');
                this._search(null);
                e.preventDefault();
            }
        });
        var ListView = Widget.extend({
            init: function (element, options) {
                var listView = this;
                Widget.fn.init.call(this, element, options);
                element = this.element;
                options = this.options;
                if (options.scrollTreshold) {
                    options.scrollThreshold = options.scrollTreshold;
                }
                element.on('down', HIGHLIGHT_SELECTOR, '_highlight').on('move up cancel', HIGHLIGHT_SELECTOR, '_dim');
                this._userEvents = new kendo.UserEvents(element, {
                    fastTap: true,
                    filter: ITEM_SELECTOR,
                    allowSelection: true,
                    tap: function (e) {
                        listView._click(e);
                    }
                });
                element.css('-ms-touch-action', 'auto');
                element.wrap(WRAPPER);
                this.wrapper = this.element.parent();
                this._headerFixer = new HeaderFixer(this);
                this._itemsCache = {};
                this._templates();
                this.virtual = options.endlessScroll || options.loadMore;
                this._style();
                if (this.options.$angular && (this.virtual || this.options.pullToRefresh)) {
                    setTimeout($.proxy(this, '_start'));
                } else {
                    this._start();
                }
            },
            _start: function () {
                var options = this.options;
                if (this.options.filterable) {
                    this._filter = new ListViewFilter(this);
                }
                if (this.virtual) {
                    this._itemBinder = new VirtualListViewItemBinder(this);
                } else {
                    this._itemBinder = new ListViewItemBinder(this);
                }
                if (this.options.pullToRefresh) {
                    this._pullToRefreshHandler = new RefreshHandler(this);
                }
                this.setDataSource(options.dataSource);
                this._enhanceItems(this.items());
                kendo.notify(this, ui);
            },
            events: [
                CLICK,
                DATABINDING,
                DATABOUND,
                ITEM_CHANGE
            ],
            options: {
                name: 'ListView',
                style: '',
                type: 'flat',
                autoBind: true,
                fixedHeaders: false,
                template: '#:data#',
                headerTemplate: '<span class="km-text">#:value#</span>',
                appendOnRefresh: false,
                loadMore: false,
                endlessScroll: false,
                scrollThreshold: 30,
                pullToRefresh: false,
                messages: {
                    loadMoreText: 'Press to load more',
                    pullTemplate: 'Pull to refresh',
                    releaseTemplate: 'Release to refresh',
                    refreshTemplate: 'Refreshing'
                },
                pullOffset: 140,
                filterable: false,
                virtualViewSize: null
            },
            refresh: function () {
                this._itemBinder.refresh();
            },
            reset: function () {
                this._itemBinder.reset();
            },
            setDataSource: function (dataSource) {
                var emptyDataSource = !dataSource;
                this.dataSource = DataSource.create(dataSource);
                this.trigger('_dataSource', {
                    dataSource: this.dataSource,
                    empty: emptyDataSource
                });
                if (this.options.autoBind && !emptyDataSource) {
                    this.items().remove();
                    this.dataSource.fetch();
                }
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                kendo.destroy(this.element);
                this._userEvents.destroy();
                if (this._itemBinder) {
                    this._itemBinder.destroy();
                }
                if (this._headerFixer) {
                    this._headerFixer.destroy();
                }
                this.element.unwrap();
                delete this.element;
                delete this.wrapper;
                delete this._userEvents;
            },
            items: function () {
                if (this.options.type === 'group') {
                    return this.element.find('.km-list').children();
                } else {
                    return this.element.children().not('.km-load-more');
                }
            },
            scroller: function () {
                if (!this._scrollerInstance) {
                    this._scrollerInstance = this.element.closest('.km-scroll-wrapper').data('kendoMobileScroller');
                }
                return this._scrollerInstance;
            },
            showLoading: function () {
                var view = this.view();
                if (view && view.loader) {
                    view.loader.show();
                }
            },
            hideLoading: function () {
                var view = this.view();
                if (view && view.loader) {
                    view.loader.hide();
                }
            },
            insertAt: function (dataItems, index, triggerChange) {
                var listView = this;
                return listView._renderItems(dataItems, function (items) {
                    if (index === 0) {
                        listView.element.prepend(items);
                    } else if (index === -1) {
                        listView.element.append(items);
                    } else {
                        listView.items().eq(index - 1).after(items);
                    }
                    if (triggerChange) {
                        for (var i = 0; i < items.length; i++) {
                            listView.trigger(ITEM_CHANGE, {
                                item: items.eq(i),
                                data: dataItems[i],
                                ns: ui
                            });
                        }
                    }
                });
            },
            append: function (dataItems, triggerChange) {
                return this.insertAt(dataItems, -1, triggerChange);
            },
            prepend: function (dataItems, triggerChange) {
                return this.insertAt(dataItems, 0, triggerChange);
            },
            replace: function (dataItems) {
                this.options.type = 'flat';
                this._angularItems('cleanup');
                kendo.destroy(this.element.children());
                this.element.empty();
                this._userEvents.cancel();
                this._style();
                return this.insertAt(dataItems, 0);
            },
            replaceGrouped: function (groups) {
                this.options.type = 'group';
                this._angularItems('cleanup');
                this.element.empty();
                var items = $(kendo.render(this.groupTemplate, groups));
                this._enhanceItems(items.children('ul').children('li'));
                this.element.append(items);
                mobile.init(items);
                this._style();
                this._angularItems('compile');
            },
            remove: function (dataItems) {
                var items = this.findByDataItem(dataItems);
                this.angular('cleanup', function () {
                    return { elements: items };
                });
                kendo.destroy(items);
                items.remove();
            },
            findByDataItem: function (dataItems) {
                var selectors = [];
                for (var idx = 0, length = dataItems.length; idx < length; idx++) {
                    selectors[idx] = '[data-' + kendo.ns + 'uid=' + dataItems[idx].uid + ']';
                }
                return this.element.find(selectors.join(','));
            },
            setDataItem: function (item, dataItem) {
                var listView = this, replaceItem = function (items) {
                        var newItem = $(items[0]);
                        kendo.destroy(item);
                        listView.angular('cleanup', function () {
                            return { elements: [$(item)] };
                        });
                        $(item).replaceWith(newItem);
                        listView.trigger(ITEM_CHANGE, {
                            item: newItem,
                            data: dataItem,
                            ns: ui
                        });
                    };
                return this._renderItems([dataItem], replaceItem)[0];
            },
            updateSize: function () {
                this._size = this.getSize();
            },
            _renderItems: function (dataItems, callback) {
                var items = $(kendo.render(this.template, dataItems));
                callback(items);
                this.angular('compile', function () {
                    return {
                        elements: items,
                        data: dataItems.map(function (data) {
                            return { dataItem: data };
                        })
                    };
                });
                mobile.init(items);
                this._enhanceItems(items);
                return items;
            },
            _dim: function (e) {
                this._toggle(e, false);
            },
            _highlight: function (e) {
                this._toggle(e, true);
            },
            _toggle: function (e, highlight) {
                if (e.which > 1) {
                    return;
                }
                var clicked = $(e.currentTarget), item = clicked.parent(), role = attrValue(clicked, 'role') || '', plainItem = !role.match(buttonRegExp), prevented = e.isDefaultPrevented();
                if (plainItem) {
                    item.toggleClass(ACTIVE_CLASS, highlight && !prevented);
                }
            },
            _templates: function () {
                var template = this.options.template, headerTemplate = this.options.headerTemplate, dataIDAttribute = ' data-uid="#=arguments[0].uid || ""#"', templateProxy = {}, groupTemplateProxy = {};
                if (typeof template === FUNCTION) {
                    templateProxy.template = template;
                    template = '#=this.template(data)#';
                }
                this.template = proxy(kendo.template('<li' + dataIDAttribute + '>' + template + '</li>'), templateProxy);
                groupTemplateProxy.template = this.template;
                if (typeof headerTemplate === FUNCTION) {
                    groupTemplateProxy._headerTemplate = headerTemplate;
                    headerTemplate = '#=this._headerTemplate(data)#';
                }
                groupTemplateProxy.headerTemplate = kendo.template(headerTemplate);
                this.groupTemplate = proxy(GROUP_TEMPLATE, groupTemplateProxy);
            },
            _click: function (e) {
                if (e.event.which > 1 || e.event.isDefaultPrevented()) {
                    return;
                }
                var dataItem, item = e.target, target = $(e.event.target), buttonElement = target.closest(kendo.roleSelector('button', 'detailbutton', 'backbutton')), button = kendo.widgetInstance(buttonElement, ui), id = item.attr(kendo.attr('uid'));
                if (id) {
                    dataItem = this.dataSource.getByUid(id);
                }
                if (this.trigger(CLICK, {
                        target: target,
                        item: item,
                        dataItem: dataItem,
                        button: button
                    })) {
                    e.preventDefault();
                }
            },
            _styleGroups: function () {
                var rootItems = this.element.children();
                rootItems.children('ul').addClass('km-list');
                rootItems.each(function () {
                    var li = $(this), groupHeader = li.contents().first();
                    li.addClass('km-group-container');
                    if (!groupHeader.is('ul') && !groupHeader.is('div.' + GROUP_CLASS)) {
                        groupHeader.wrap(GROUP_WRAPPER);
                    }
                });
            },
            _style: function () {
                var options = this.options, grouped = options.type === 'group', element = this.element, inset = options.style === 'inset';
                element.addClass('km-listview').toggleClass('km-list', !grouped).toggleClass('km-virtual-list', this.virtual).toggleClass('km-listinset', !grouped && inset).toggleClass('km-listgroup', grouped && !inset).toggleClass('km-listgroupinset', grouped && inset);
                if (!element.parents('.km-listview')[0]) {
                    element.closest('.km-content').toggleClass('km-insetcontent', inset);
                }
                if (grouped) {
                    this._styleGroups();
                }
                this.trigger(STYLED);
            },
            _enhanceItems: function (items) {
                items.each(function () {
                    var item = $(this), child, enhanced = false;
                    item.children().each(function () {
                        child = $(this);
                        if (child.is('a')) {
                            enhanceLinkItem(child);
                            enhanced = true;
                        } else if (child.is('label')) {
                            enhanceCheckBoxItem(child);
                            enhanced = true;
                        }
                    });
                    if (!enhanced) {
                        enhanceItem(item);
                    }
                });
            }
        });
        ui.plugin(ListView);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.navbar', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'mobile.navbar',
        name: 'NavBar',
        category: 'mobile',
        description: 'The Kendo mobile NavBar widget is used inside a mobile View or Layout Header element to display an application navigation bar.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, Widget = ui.Widget;
        function createContainer(align, element) {
            var items = element.find('[' + kendo.attr('align') + '=' + align + ']');
            if (items[0]) {
                return $('<div class="km-' + align + 'item" />').append(items).prependTo(element);
            }
        }
        function toggleTitle(centerElement) {
            var siblings = centerElement.siblings(), noTitle = !!centerElement.children('ul')[0], showTitle = !!siblings[0] && $.trim(centerElement.text()) === '', android = !!(kendo.mobile.application && kendo.mobile.application.element.is('.km-android'));
            centerElement.prevAll().toggleClass('km-absolute', noTitle);
            centerElement.toggleClass('km-show-title', showTitle);
            centerElement.toggleClass('km-fill-title', showTitle && !$.trim(centerElement.html()));
            centerElement.toggleClass('km-no-title', noTitle);
            centerElement.toggleClass('km-hide-title', android && !siblings.children().is(':visible'));
        }
        var NavBar = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                element = that.element;
                that.container().bind('show', $.proxy(this, 'refresh'));
                element.addClass('km-navbar').wrapInner($('<div class="km-view-title km-show-title" />'));
                that.leftElement = createContainer('left', element);
                that.rightElement = createContainer('right', element);
                that.centerElement = element.find('.km-view-title');
            },
            options: { name: 'NavBar' },
            title: function (value) {
                this.element.find(kendo.roleSelector('view-title')).text(value);
                toggleTitle(this.centerElement);
            },
            refresh: function (e) {
                var view = e.view;
                this.title(view.options.title);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                kendo.destroy(this.element);
            }
        });
        ui.plugin(NavBar);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.scrollview', [
        'kendo.fx',
        'kendo.data',
        'kendo.draganddrop'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.scrollview',
        name: 'ScrollView',
        category: 'mobile',
        description: 'The Kendo Mobile ScrollView widget is used to scroll content wider than the device screen.',
        depends: [
            'fx',
            'data',
            'draganddrop'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, mobile = kendo.mobile, ui = mobile.ui, proxy = $.proxy, Transition = kendo.effects.Transition, Pane = kendo.ui.Pane, PaneDimensions = kendo.ui.PaneDimensions, Widget = ui.DataBoundWidget, DataSource = kendo.data.DataSource, Buffer = kendo.data.Buffer, BatchBuffer = kendo.data.BatchBuffer, math = Math, abs = math.abs, ceil = math.ceil, round = math.round, max = math.max, min = math.min, floor = math.floor, CHANGE = 'change', CHANGING = 'changing', REFRESH = 'refresh', CURRENT_PAGE_CLASS = 'current-page', VIRTUAL_PAGE_CLASS = 'virtual-page', FUNCTION = 'function', ITEM_CHANGE = 'itemChange', CLEANUP = 'cleanup', VIRTUAL_PAGE_COUNT = 3, LEFT_PAGE = -1, CETER_PAGE = 0, RIGHT_PAGE = 1, LEFT_SWIPE = -1, NUDGE = 0, RIGHT_SWIPE = 1;
        function className(name) {
            return 'k-' + name + ' km-' + name;
        }
        var Pager = kendo.Class.extend({
            init: function (scrollView) {
                var that = this, element = $('<ol class=\'' + className('pages') + '\'/>');
                scrollView.element.append(element);
                this._changeProxy = proxy(that, '_change');
                this._refreshProxy = proxy(that, '_refresh');
                scrollView.bind(CHANGE, this._changeProxy);
                scrollView.bind(REFRESH, this._refreshProxy);
                $.extend(that, {
                    element: element,
                    scrollView: scrollView
                });
            },
            items: function () {
                return this.element.children();
            },
            _refresh: function (e) {
                var pageHTML = '';
                for (var idx = 0; idx < e.pageCount; idx++) {
                    pageHTML += '<li/>';
                }
                this.element.html(pageHTML);
                this.items().eq(e.page).addClass(className(CURRENT_PAGE_CLASS));
            },
            _change: function (e) {
                this.items().removeClass(className(CURRENT_PAGE_CLASS)).eq(e.page).addClass(className(CURRENT_PAGE_CLASS));
            },
            destroy: function () {
                this.scrollView.unbind(CHANGE, this._changeProxy);
                this.scrollView.unbind(REFRESH, this._refreshProxy);
                this.element.remove();
            }
        });
        kendo.mobile.ui.ScrollViewPager = Pager;
        var TRANSITION_END = 'transitionEnd', DRAG_START = 'dragStart', DRAG_END = 'dragEnd';
        var ElasticPane = kendo.Observable.extend({
            init: function (element, options) {
                var that = this;
                kendo.Observable.fn.init.call(this);
                this.element = element;
                this.container = element.parent();
                var movable, transition, userEvents, dimensions, dimension, pane;
                movable = new kendo.ui.Movable(that.element);
                transition = new Transition({
                    axis: 'x',
                    movable: movable,
                    onEnd: function () {
                        that.trigger(TRANSITION_END);
                    }
                });
                userEvents = new kendo.UserEvents(element, {
                    fastTap: true,
                    start: function (e) {
                        if (abs(e.x.velocity) * 2 >= abs(e.y.velocity)) {
                            userEvents.capture();
                        } else {
                            userEvents.cancel();
                        }
                        that.trigger(DRAG_START, e);
                        transition.cancel();
                    },
                    allowSelection: true,
                    end: function (e) {
                        that.trigger(DRAG_END, e);
                    }
                });
                dimensions = new PaneDimensions({
                    element: that.element,
                    container: that.container
                });
                dimension = dimensions.x;
                dimension.bind(CHANGE, function () {
                    that.trigger(CHANGE);
                });
                pane = new Pane({
                    dimensions: dimensions,
                    userEvents: userEvents,
                    movable: movable,
                    elastic: true
                });
                $.extend(that, {
                    duration: options && options.duration || 1,
                    movable: movable,
                    transition: transition,
                    userEvents: userEvents,
                    dimensions: dimensions,
                    dimension: dimension,
                    pane: pane
                });
                this.bind([
                    TRANSITION_END,
                    DRAG_START,
                    DRAG_END,
                    CHANGE
                ], options);
            },
            size: function () {
                return {
                    width: this.dimensions.x.getSize(),
                    height: this.dimensions.y.getSize()
                };
            },
            total: function () {
                return this.dimension.getTotal();
            },
            offset: function () {
                return -this.movable.x;
            },
            updateDimension: function () {
                this.dimension.update(true);
            },
            refresh: function () {
                this.dimensions.refresh();
            },
            moveTo: function (offset) {
                this.movable.moveAxis('x', -offset);
            },
            transitionTo: function (offset, ease, instant) {
                if (instant) {
                    this.moveTo(-offset);
                } else {
                    this.transition.moveTo({
                        location: offset,
                        duration: this.duration,
                        ease: ease
                    });
                }
            }
        });
        kendo.mobile.ui.ScrollViewElasticPane = ElasticPane;
        var ScrollViewContent = kendo.Observable.extend({
            init: function (element, pane, options) {
                var that = this;
                kendo.Observable.fn.init.call(this);
                that.element = element;
                that.pane = pane;
                that._getPages();
                this.page = 0;
                this.pageSize = options.pageSize || 1;
                this.contentHeight = options.contentHeight;
                this.enablePager = options.enablePager;
                this.pagerOverlay = options.pagerOverlay;
            },
            scrollTo: function (page, instant) {
                this.page = page;
                this.pane.transitionTo(-page * this.pane.size().width, Transition.easeOutExpo, instant);
            },
            paneMoved: function (swipeType, bounce, callback, instant) {
                var that = this, pane = that.pane, width = pane.size().width * that.pageSize, approx = round, ease = bounce ? Transition.easeOutBack : Transition.easeOutExpo, snap, nextPage;
                if (swipeType === LEFT_SWIPE) {
                    approx = ceil;
                } else if (swipeType === RIGHT_SWIPE) {
                    approx = floor;
                }
                nextPage = approx(pane.offset() / width);
                snap = max(that.minSnap, min(-nextPage * width, that.maxSnap));
                if (nextPage != that.page) {
                    if (callback && callback({
                            currentPage: that.page,
                            nextPage: nextPage
                        })) {
                        snap = -that.page * pane.size().width;
                    }
                }
                pane.transitionTo(snap, ease, instant);
            },
            updatePage: function () {
                var pane = this.pane, page = round(pane.offset() / pane.size().width);
                if (page != this.page) {
                    this.page = page;
                    return true;
                }
                return false;
            },
            forcePageUpdate: function () {
                return this.updatePage();
            },
            resizeTo: function (size) {
                var pane = this.pane, width = size.width;
                this.pageElements.width(width);
                if (this.contentHeight === '100%') {
                    var containerHeight = this.element.parent().height();
                    if (this.enablePager === true) {
                        var pager = this.element.parent().find('ol.km-pages');
                        if (!this.pagerOverlay && pager.length) {
                            containerHeight -= kendo._outerHeight(pager, true);
                        }
                    }
                    this.element.css('height', containerHeight);
                    this.pageElements.css('height', containerHeight);
                }
                pane.updateDimension();
                if (!this._paged) {
                    this.page = floor(pane.offset() / width);
                }
                this.scrollTo(this.page, true);
                this.pageCount = ceil(pane.total() / width);
                this.minSnap = -(this.pageCount - 1) * width;
                this.maxSnap = 0;
            },
            _getPages: function () {
                this.pageElements = this.element.find(kendo.roleSelector('page'));
                this._paged = this.pageElements.length > 0;
            }
        });
        kendo.mobile.ui.ScrollViewContent = ScrollViewContent;
        var VirtualScrollViewContent = kendo.Observable.extend({
            init: function (element, pane, options) {
                var that = this;
                kendo.Observable.fn.init.call(this);
                that.element = element;
                that.pane = pane;
                that.options = options;
                that._templates();
                that.page = options.page || 0;
                that.pages = [];
                that._initPages();
                that.resizeTo(that.pane.size());
                that.pane.dimension.forceEnabled();
            },
            setDataSource: function (dataSource) {
                this.dataSource = DataSource.create(dataSource);
                this._buffer();
                this._pendingPageRefresh = false;
                this._pendingWidgetRefresh = false;
            },
            _viewShow: function () {
                var that = this;
                if (that._pendingWidgetRefresh) {
                    setTimeout(function () {
                        that._resetPages();
                    }, 0);
                    that._pendingWidgetRefresh = false;
                }
            },
            _buffer: function () {
                var itemsPerPage = this.options.itemsPerPage;
                if (this.buffer) {
                    this.buffer.destroy();
                }
                if (itemsPerPage > 1) {
                    this.buffer = new BatchBuffer(this.dataSource, itemsPerPage);
                } else {
                    this.buffer = new Buffer(this.dataSource, itemsPerPage * 3);
                }
                this._resizeProxy = proxy(this, '_onResize');
                this._resetProxy = proxy(this, '_onReset');
                this._endReachedProxy = proxy(this, '_onEndReached');
                this.buffer.bind({
                    'resize': this._resizeProxy,
                    'reset': this._resetProxy,
                    'endreached': this._endReachedProxy
                });
            },
            _templates: function () {
                var template = this.options.template, emptyTemplate = this.options.emptyTemplate, templateProxy = {}, emptyTemplateProxy = {};
                if (typeof template === FUNCTION) {
                    templateProxy.template = template;
                    template = '#=this.template(data)#';
                }
                this.template = proxy(kendo.template(template), templateProxy);
                if (typeof emptyTemplate === FUNCTION) {
                    emptyTemplateProxy.emptyTemplate = emptyTemplate;
                    emptyTemplate = '#=this.emptyTemplate(data)#';
                }
                this.emptyTemplate = proxy(kendo.template(emptyTemplate), emptyTemplateProxy);
            },
            _initPages: function () {
                var pages = this.pages, element = this.element, page;
                for (var i = 0; i < VIRTUAL_PAGE_COUNT; i++) {
                    page = new Page(element);
                    pages.push(page);
                }
                this.pane.updateDimension();
            },
            resizeTo: function (size) {
                var pages = this.pages, pane = this.pane;
                for (var i = 0; i < pages.length; i++) {
                    pages[i].setWidth(size.width);
                }
                if (this.options.contentHeight === 'auto') {
                    this.element.css('height', this.pages[1].element.height());
                } else if (this.options.contentHeight === '100%') {
                    var containerHeight = this.element.parent().height();
                    if (this.options.enablePager === true) {
                        var pager = this.element.parent().find('ol.km-pages');
                        if (!this.options.pagerOverlay && pager.length) {
                            containerHeight -= kendo._outerHeight(pager, true);
                        }
                    }
                    this.element.css('height', containerHeight);
                    pages[0].element.css('height', containerHeight);
                    pages[1].element.css('height', containerHeight);
                    pages[2].element.css('height', containerHeight);
                }
                pane.updateDimension();
                this._repositionPages();
                this.width = size.width;
            },
            scrollTo: function (page) {
                var buffer = this.buffer, dataItem;
                buffer.syncDataSource();
                dataItem = buffer.at(page);
                if (!dataItem) {
                    return;
                }
                this._updatePagesContent(page);
                this.page = page;
            },
            paneMoved: function (swipeType, bounce, callback, instant) {
                var that = this, pane = that.pane, width = pane.size().width, offset = pane.offset(), thresholdPassed = Math.abs(offset) >= width / 3, ease = bounce ? kendo.effects.Transition.easeOutBack : kendo.effects.Transition.easeOutExpo, isEndReached = that.page + 2 > that.buffer.total(), nextPage, delta = 0;
                if (swipeType === RIGHT_SWIPE) {
                    if (that.page !== 0) {
                        delta = -1;
                    }
                } else if (swipeType === LEFT_SWIPE && !isEndReached) {
                    delta = 1;
                } else if (offset > 0 && (thresholdPassed && !isEndReached)) {
                    delta = 1;
                } else if (offset < 0 && thresholdPassed) {
                    if (that.page !== 0) {
                        delta = -1;
                    }
                }
                nextPage = that.page;
                if (delta) {
                    nextPage = delta > 0 ? nextPage + 1 : nextPage - 1;
                }
                if (callback && callback({
                        currentPage: that.page,
                        nextPage: nextPage
                    })) {
                    delta = 0;
                }
                if (delta === 0) {
                    that._cancelMove(ease, instant);
                } else if (delta === -1) {
                    that._moveBackward(instant);
                } else if (delta === 1) {
                    that._moveForward(instant);
                }
            },
            updatePage: function () {
                var pages = this.pages;
                if (this.pane.offset() === 0) {
                    return false;
                }
                if (this.pane.offset() > 0) {
                    pages.push(this.pages.shift());
                    this.page++;
                    this.setPageContent(pages[2], this.page + 1);
                } else {
                    pages.unshift(this.pages.pop());
                    this.page--;
                    this.setPageContent(pages[0], this.page - 1);
                }
                this._repositionPages();
                this._resetMovable();
                return true;
            },
            forcePageUpdate: function () {
                var offset = this.pane.offset(), threshold = this.pane.size().width * 3 / 4;
                if (abs(offset) > threshold) {
                    return this.updatePage();
                }
                return false;
            },
            _resetMovable: function () {
                this.pane.moveTo(0);
            },
            _moveForward: function (instant) {
                this.pane.transitionTo(-this.width, kendo.effects.Transition.easeOutExpo, instant);
            },
            _moveBackward: function (instant) {
                this.pane.transitionTo(this.width, kendo.effects.Transition.easeOutExpo, instant);
            },
            _cancelMove: function (ease, instant) {
                this.pane.transitionTo(0, ease, instant);
            },
            _resetPages: function () {
                this.page = this.options.page || 0;
                this._updatePagesContent(this.page);
                this._repositionPages();
                this.trigger('reset');
            },
            _onResize: function () {
                this.pageCount = ceil(this.dataSource.total() / this.options.itemsPerPage);
                if (this._pendingPageRefresh) {
                    this._updatePagesContent(this.page);
                    this._pendingPageRefresh = false;
                }
                this.trigger('resize');
            },
            _onReset: function () {
                this.pageCount = ceil(this.dataSource.total() / this.options.itemsPerPage);
                this._resetPages();
            },
            _onEndReached: function () {
                this._pendingPageRefresh = true;
            },
            _repositionPages: function () {
                var pages = this.pages;
                pages[0].position(LEFT_PAGE);
                pages[1].position(CETER_PAGE);
                pages[2].position(RIGHT_PAGE);
            },
            _updatePagesContent: function (offset) {
                var pages = this.pages, currentPage = offset || 0;
                this.setPageContent(pages[0], currentPage - 1);
                this.setPageContent(pages[1], currentPage);
                this.setPageContent(pages[2], currentPage + 1);
            },
            setPageContent: function (page, index) {
                var buffer = this.buffer, template = this.template, emptyTemplate = this.emptyTemplate, view = null;
                if (index >= 0) {
                    view = buffer.at(index);
                    if ($.isArray(view) && !view.length) {
                        view = null;
                    }
                }
                this.trigger(CLEANUP, { item: page.element });
                if (view !== null) {
                    page.content(template(view));
                } else {
                    page.content(emptyTemplate({}));
                }
                kendo.mobile.init(page.element);
                this.trigger(ITEM_CHANGE, {
                    item: page.element,
                    data: view,
                    ns: kendo.mobile.ui
                });
            }
        });
        kendo.mobile.ui.VirtualScrollViewContent = VirtualScrollViewContent;
        var Page = kendo.Class.extend({
            init: function (container) {
                this.element = $('<div class=\'' + className(VIRTUAL_PAGE_CLASS) + '\'></div>');
                this.width = container.width();
                this.element.width(this.width);
                container.append(this.element);
            },
            content: function (theContent) {
                this.element.html(theContent);
            },
            position: function (position) {
                this.element.css('transform', 'translate3d(' + this.width * position + 'px, 0, 0)');
            },
            setWidth: function (width) {
                this.width = width;
                this.element.width(width);
            }
        });
        kendo.mobile.ui.VirtualPage = Page;
        var ScrollView = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                element = that.element;
                kendo.stripWhitespace(element[0]);
                element.wrapInner('<div/>').addClass('k-widget ' + className('scrollview'));
                if (this.options.enablePager) {
                    this.pager = new Pager(this);
                    if (this.options.pagerOverlay) {
                        element.addClass(className('scrollview-overlay'));
                    }
                }
                that.inner = element.children().first();
                that.page = 0;
                that.inner.css('height', options.contentHeight);
                that.pane = new ElasticPane(that.inner, {
                    duration: this.options.duration,
                    transitionEnd: proxy(this, '_transitionEnd'),
                    dragStart: proxy(this, '_dragStart'),
                    dragEnd: proxy(this, '_dragEnd'),
                    change: proxy(this, REFRESH)
                });
                that.bind('resize', function () {
                    that.pane.refresh();
                });
                that.page = options.page;
                var empty = this.inner.children().length === 0;
                var content = empty ? new VirtualScrollViewContent(that.inner, that.pane, options) : new ScrollViewContent(that.inner, that.pane, options);
                content.page = that.page;
                content.bind('reset', function () {
                    this._pendingPageRefresh = false;
                    that._syncWithContent();
                    that.trigger(REFRESH, {
                        pageCount: content.pageCount,
                        page: content.page
                    });
                });
                content.bind('resize', function () {
                    that.trigger(REFRESH, {
                        pageCount: content.pageCount,
                        page: content.page
                    });
                });
                content.bind(ITEM_CHANGE, function (e) {
                    that.trigger(ITEM_CHANGE, e);
                    that.angular('compile', function () {
                        return {
                            elements: e.item,
                            data: [{ dataItem: e.data }]
                        };
                    });
                });
                content.bind(CLEANUP, function (e) {
                    that.angular('cleanup', function () {
                        return { elements: e.item };
                    });
                });
                that._content = content;
                that.setDataSource(options.dataSource);
                var mobileContainer = that.container();
                if (mobileContainer.nullObject) {
                    that.viewInit();
                    that.viewShow();
                } else {
                    mobileContainer.bind('show', proxy(this, 'viewShow')).bind('init', proxy(this, 'viewInit'));
                }
            },
            options: {
                name: 'ScrollView',
                page: 0,
                duration: 400,
                velocityThreshold: 0.8,
                contentHeight: 'auto',
                pageSize: 1,
                itemsPerPage: 1,
                bounceVelocityThreshold: 1.6,
                enablePager: true,
                pagerOverlay: false,
                autoBind: true,
                template: '',
                emptyTemplate: ''
            },
            events: [
                CHANGING,
                CHANGE,
                REFRESH
            ],
            destroy: function () {
                Widget.fn.destroy.call(this);
                kendo.destroy(this.element);
            },
            viewInit: function () {
                if (this.options.autoBind) {
                    this._content.scrollTo(this._content.page, true);
                }
            },
            viewShow: function () {
                this.pane.refresh();
            },
            refresh: function () {
                var content = this._content;
                content.resizeTo(this.pane.size());
                this.page = content.page;
                this.trigger(REFRESH, {
                    pageCount: content.pageCount,
                    page: content.page
                });
            },
            content: function (html) {
                this.element.children().first().html(html);
                this._content._getPages();
                this.pane.refresh();
            },
            value: function (item) {
                var dataSource = this.dataSource;
                if (item) {
                    this.scrollTo(dataSource.indexOf(item), true);
                } else {
                    return dataSource.at(this.page);
                }
            },
            scrollTo: function (page, instant) {
                this._content.scrollTo(page, instant);
                this._syncWithContent();
            },
            prev: function () {
                var that = this, prevPage = that.page - 1;
                if (that._content instanceof VirtualScrollViewContent) {
                    that._content.paneMoved(RIGHT_SWIPE, undefined, function (eventData) {
                        return that.trigger(CHANGING, eventData);
                    });
                } else if (prevPage > -1) {
                    that.scrollTo(prevPage);
                }
            },
            next: function () {
                var that = this, nextPage = that.page + 1;
                if (that._content instanceof VirtualScrollViewContent) {
                    that._content.paneMoved(LEFT_SWIPE, undefined, function (eventData) {
                        return that.trigger(CHANGING, eventData);
                    });
                } else if (nextPage < that._content.pageCount) {
                    that.scrollTo(nextPage);
                }
            },
            setDataSource: function (dataSource) {
                if (!(this._content instanceof VirtualScrollViewContent)) {
                    return;
                }
                var emptyDataSource = !dataSource;
                this.dataSource = DataSource.create(dataSource);
                this._content.setDataSource(this.dataSource);
                if (this.options.autoBind && !emptyDataSource) {
                    this.dataSource.fetch();
                }
            },
            items: function () {
                return this.element.find('.km-' + VIRTUAL_PAGE_CLASS);
            },
            _syncWithContent: function () {
                var pages = this._content.pages, buffer = this._content.buffer, data, element;
                this.page = this._content.page;
                data = buffer ? buffer.at(this.page) : undefined;
                if (!(data instanceof Array)) {
                    data = [data];
                }
                element = pages ? pages[1].element : undefined;
                this.trigger(CHANGE, {
                    page: this.page,
                    element: element,
                    data: data
                });
            },
            _dragStart: function () {
                if (this._content.forcePageUpdate()) {
                    this._syncWithContent();
                }
            },
            _dragEnd: function (e) {
                var that = this, velocity = e.x.velocity, velocityThreshold = this.options.velocityThreshold, swipeType = NUDGE, bounce = abs(velocity) > this.options.bounceVelocityThreshold;
                if (velocity > velocityThreshold) {
                    swipeType = RIGHT_SWIPE;
                } else if (velocity < -velocityThreshold) {
                    swipeType = LEFT_SWIPE;
                }
                this._content.paneMoved(swipeType, bounce, function (eventData) {
                    return that.trigger(CHANGING, eventData);
                });
            },
            _transitionEnd: function () {
                if (this._content.updatePage()) {
                    this._syncWithContent();
                }
            }
        });
        ui.plugin(ScrollView);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.switch', [
        'kendo.fx',
        'kendo.userevents'
    ], f);
}(function () {
    var __meta__ = {
        id: 'mobile.switch',
        name: 'Switch',
        category: 'mobile',
        description: 'The mobile Switch widget is used to display two exclusive choices.',
        depends: [
            'fx',
            'userevents'
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.mobile.ui, outerWidth = kendo._outerWidth, Widget = ui.Widget, support = kendo.support, CHANGE = 'change', SWITCHON = 'switch-on', SWITCHOFF = 'switch-off', MARGINLEFT = 'margin-left', ACTIVE_STATE = 'state-active', DISABLED_STATE = 'state-disabled', DISABLED = 'disabled', TRANSFORMSTYLE = support.transitions.css + 'transform', proxy = $.proxy;
        function className(name) {
            return 'k-' + name + ' km-' + name;
        }
        function limitValue(value, minLimit, maxLimit) {
            return Math.max(minLimit, Math.min(maxLimit, value));
        }
        var SWITCH_MARKUP = '<span class="' + className('switch') + ' ' + className('widget') + '">        <span class="' + className('switch-wrapper') + '">            <span class="' + className('switch-background') + '"></span>        </span>         <span class="' + className('switch-container') + '">            <span class="' + className('switch-handle') + '">                 <span class="' + className('switch-label-on') + '">{0}</span>                 <span class="' + className('switch-label-off') + '">{1}</span>             </span>         </span>    </span>';
        var Switch = Widget.extend({
            init: function (element, options) {
                var that = this, checked;
                Widget.fn.init.call(that, element, options);
                options = that.options;
                that.wrapper = $(kendo.format(SWITCH_MARKUP, options.onLabel, options.offLabel));
                that.handle = that.wrapper.find('.km-switch-handle');
                that.background = that.wrapper.find('.km-switch-background');
                that.wrapper.insertBefore(that.element).prepend(that.element);
                that._drag();
                that.origin = parseInt(that.background.css(MARGINLEFT), 10);
                that.constrain = 0;
                that.snapPoint = 0;
                element = that.element[0];
                element.type = 'checkbox';
                that._animateBackground = true;
                checked = that.options.checked;
                if (checked === null) {
                    checked = element.checked;
                }
                that.check(checked);
                that.options.enable = that.options.enable && !that.element.attr(DISABLED);
                that.enable(that.options.enable);
                that.refresh();
                kendo.notify(that, kendo.mobile.ui);
            },
            refresh: function () {
                var that = this, handleWidth = outerWidth(that.handle, true);
                that.width = that.wrapper.width();
                that.constrain = that.width - handleWidth;
                that.snapPoint = that.constrain / 2;
                if (typeof that.origin != 'number') {
                    that.origin = parseInt(that.background.css(MARGINLEFT), 10);
                }
                that.background.data('origin', that.origin);
                that.check(that.element[0].checked);
            },
            events: [CHANGE],
            options: {
                name: 'Switch',
                onLabel: 'on',
                offLabel: 'off',
                checked: null,
                enable: true
            },
            check: function (check) {
                var that = this, element = that.element[0];
                if (check === undefined) {
                    return element.checked;
                }
                that._position(check ? that.constrain : 0);
                element.checked = check;
                that.wrapper.toggleClass(className(SWITCHON), check).toggleClass(className(SWITCHOFF), !check);
            },
            value: function () {
                return this.check.apply(this, arguments);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.userEvents.destroy();
            },
            toggle: function () {
                var that = this;
                that.check(!that.element[0].checked);
            },
            enable: function (enable) {
                var element = this.element, wrapper = this.wrapper;
                if (typeof enable == 'undefined') {
                    enable = true;
                }
                this.options.enable = enable;
                if (enable) {
                    element.removeAttr(DISABLED);
                } else {
                    element.attr(DISABLED, DISABLED);
                }
                wrapper.toggleClass(className(DISABLED_STATE), !enable);
            },
            _resize: function () {
                this.refresh();
            },
            _move: function (e) {
                var that = this;
                e.preventDefault();
                that._position(limitValue(that.position + e.x.delta, 0, that.width - outerWidth(that.handle, true)));
            },
            _position: function (position) {
                var that = this;
                that.position = position;
                that.handle.css(TRANSFORMSTYLE, 'translatex(' + position + 'px)');
                if (that._animateBackground) {
                    that.background.css(MARGINLEFT, that.origin + position);
                }
            },
            _start: function () {
                if (!this.options.enable) {
                    this.userEvents.cancel();
                } else {
                    this.userEvents.capture();
                    this.handle.addClass(className(ACTIVE_STATE));
                }
            },
            _stop: function () {
                var that = this;
                that.handle.removeClass(className(ACTIVE_STATE));
                that._toggle(that.position > that.snapPoint);
            },
            _toggle: function (checked) {
                var that = this, handle = that.handle, element = that.element[0], value = element.checked, duration = kendo.mobile.application && kendo.mobile.application.os.wp ? 100 : 200, distance;
                that.wrapper.toggleClass(className(SWITCHON), checked).toggleClass(className(SWITCHOFF), !checked);
                that.position = distance = checked * that.constrain;
                if (that._animateBackground) {
                    that.background.kendoStop(true, true).kendoAnimate({
                        effects: 'slideMargin',
                        offset: distance,
                        reset: true,
                        reverse: !checked,
                        axis: 'left',
                        duration: duration
                    });
                }
                handle.kendoStop(true, true).kendoAnimate({
                    effects: 'slideTo',
                    duration: duration,
                    offset: distance + 'px,0',
                    reset: true,
                    complete: function () {
                        if (value !== checked) {
                            element.checked = checked;
                            that.trigger(CHANGE, { checked: checked });
                        }
                    }
                });
            },
            _drag: function () {
                var that = this;
                that.userEvents = new kendo.UserEvents(that.wrapper, {
                    fastTap: true,
                    tap: function () {
                        if (that.options.enable) {
                            that._toggle(!that.element[0].checked);
                        }
                    },
                    start: proxy(that._start, that),
                    move: proxy(that._move, that),
                    end: proxy(that._stop, that)
                });
            }
        });
        ui.plugin(Switch);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile.tabstrip', ['kendo.core'], f);
}(function () {
    var __meta__ = {
        id: 'mobile.tabstrip',
        name: 'TabStrip',
        category: 'mobile',
        description: 'The mobile TabStrip widget is used inside a mobile view or layout footer element to display an application-wide group of navigation buttons.',
        depends: ['core']
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.mobile.ui, Widget = ui.Widget, ACTIVE_STATE_CLASS = 'km-state-active', SELECT = 'select';
        function createBadge(value) {
            return $('<span class="km-badge">' + value + '</span>');
        }
        var TabStrip = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.container().bind('show', $.proxy(this, 'refresh'));
                that.element.addClass('km-tabstrip').find('a').each(that._buildButton).eq(that.options.selectedIndex).addClass(ACTIVE_STATE_CLASS);
                that.element.on('down', 'a', '_release');
            },
            events: [SELECT],
            switchTo: function (url) {
                var tabs = this.element.find('a'), tab, path, idx = 0, length = tabs.length;
                if (isNaN(url)) {
                    for (; idx < length; idx++) {
                        tab = tabs[idx];
                        path = tab.href.replace(/(\#.+)(\?.+)$/, '$1');
                        if (path.indexOf(url, path.length - url.length) !== -1) {
                            this._setActiveItem($(tab));
                            return true;
                        }
                    }
                } else {
                    this._setActiveItem(tabs.eq(url));
                    return true;
                }
                return false;
            },
            switchByFullUrl: function (url) {
                var tab;
                tab = this.element.find('a[href$=\'' + url + '\']');
                this._setActiveItem(tab);
            },
            clear: function () {
                this.currentItem().removeClass(ACTIVE_STATE_CLASS);
            },
            currentItem: function () {
                return this.element.children('.' + ACTIVE_STATE_CLASS);
            },
            badge: function (item, value) {
                var tabstrip = this.element, badge;
                if (!isNaN(item)) {
                    item = tabstrip.children().get(item);
                }
                item = tabstrip.find(item);
                badge = $(item.find('.km-badge')[0] || createBadge(value).insertAfter(item.children('.km-icon')));
                if (value || value === 0) {
                    badge.html(value);
                    return this;
                }
                if (value === false) {
                    badge.empty().remove();
                    return this;
                }
                return badge.html();
            },
            _release: function (e) {
                if (e.which > 1) {
                    return;
                }
                var that = this, item = $(e.currentTarget);
                if (item[0] === that.currentItem()[0]) {
                    return;
                }
                if (that.trigger(SELECT, { item: item })) {
                    e.preventDefault();
                } else {
                    that._setActiveItem(item);
                }
            },
            _setActiveItem: function (item) {
                if (!item[0]) {
                    return;
                }
                this.clear();
                item.addClass(ACTIVE_STATE_CLASS);
            },
            _buildButton: function () {
                var button = $(this), icon = kendo.attrValue(button, 'icon'), badge = kendo.attrValue(button, 'badge'), image = button.find('img'), iconSpan = $('<span class="km-icon"/>');
                button.addClass('km-button').attr(kendo.attr('role'), 'tab').contents().not(image).wrapAll('<span class="km-text"/>');
                if (image[0]) {
                    image.addClass('km-image').prependTo(button);
                } else {
                    button.prepend(iconSpan);
                    if (icon) {
                        iconSpan.addClass('km-' + icon);
                        if (badge || badge === 0) {
                            createBadge(badge).insertAfter(iconSpan);
                        }
                    }
                }
            },
            refresh: function (e) {
                var url = e.view.id;
                if (url && !this.switchTo(e.view.id)) {
                    this.switchTo(url);
                }
            },
            options: {
                name: 'TabStrip',
                selectedIndex: 0,
                enable: true
            }
        });
        ui.plugin(TabStrip);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.mobile', [
        'kendo.core',
        'kendo.fx',
        'kendo.data.odata',
        'kendo.data.xml',
        'kendo.data',
        'kendo.data.signalr',
        'kendo.binder',
        'kendo.validator',
        'kendo.router',
        'kendo.view',
        'kendo.userevents',
        'kendo.draganddrop',
        'kendo.popup',
        'kendo.touch',
        'kendo.mobile.popover',
        'kendo.mobile.loader',
        'kendo.mobile.scroller',
        'kendo.mobile.shim',
        'kendo.mobile.view',
        'kendo.mobile.modalview',
        'kendo.mobile.drawer',
        'kendo.mobile.splitview',
        'kendo.mobile.pane',
        'kendo.mobile.application',
        'kendo.mobile.actionsheet',
        'kendo.mobile.button',
        'kendo.mobile.buttongroup',
        'kendo.mobile.collapsible',
        'kendo.mobile.listview',
        'kendo.mobile.navbar',
        'kendo.mobile.scrollview',
        'kendo.mobile.switch',
        'kendo.mobile.tabstrip',
        'kendo.angular'
    ], f);
}(function () {
    'bundle all';
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.all', [
        'kendo.web',
        'kendo.dataviz',
        'kendo.mobile',
        'kendo.drawing',
        'kendo.dom'
    ], f);
}(function () {
    'bundle all';
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));;/** 
 * Kendo UI v2017.2.504 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2017 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(e,define){define("aspnetmvc/kendo.data.aspnetmvc.min",["kendo.data.min","kendo.combobox.min","kendo.multiselect.min","kendo.validator.min"],e)}(function(){!function(e,t){function n(t,n,r){var i,o={};return t.sort?(o[this.options.prefix+"sort"]=e.map(t.sort,function(e){return e.field+"-"+e.dir}).join("~"),delete t.sort):o[this.options.prefix+"sort"]="",t.page&&(o[this.options.prefix+"page"]=t.page,delete t.page),t.pageSize&&(o[this.options.prefix+"pageSize"]=t.pageSize,delete t.pageSize),t.group?(o[this.options.prefix+"group"]=e.map(t.group,function(e){return e.field+"-"+e.dir}).join("~"),delete t.group):o[this.options.prefix+"group"]="",t.aggregate&&(o[this.options.prefix+"aggregate"]=e.map(t.aggregate,function(e){return e.field+"-"+e.aggregate}).join("~"),delete t.aggregate),t.filter?(o[this.options.prefix+"filter"]=a(t.filter,r.encode),delete t.filter):(o[this.options.prefix+"filter"]="",delete t.filter),delete t.take,delete t.skip,i=new g(r),i.serialize(o,t,""),o}function a(n,i){return n.filters?e.map(n.filters,function(e){var t=e.filters&&e.filters.length>1,n=a(e,i);return n&&t&&(n="("+n+")"),n}).join("~"+n.logic+"~"):n.field?n.field+"~"+n.operator+"~"+r(n.value,i):t}function r(e,t){if("string"==typeof e){if(!(e.indexOf("Date(")>-1))return e=e.replace(l,"''"),t&&(e=encodeURIComponent(e)),"'"+e+"'";e=new Date(parseInt(e.replace(/^\/Date\((.*?)\)\/$/,"$1"),10))}return e&&e.getTime?"datetime'"+c.format("{0:yyyy-MM-ddTHH-mm-ss}",e)+"'":e}function i(e,n){return t!==e?e:n}function o(t){var n=t.HasSubgroups||t.hasSubgroups||!1,a=t.Items||t.items;return{value:i(t.Key,i(t.key,t.value)),field:t.Member||t.member||t.field,hasSubgroups:n,aggregates:d(t.Aggregates||t.aggregates),items:n?e.map(a,o):a}}function s(e){var t={};return t[e.AggregateMethodName.toLowerCase()]=e.Value,t}function d(e){var t,n,a,r={};for(t in e){r={},a=e[t];for(n in a)r[n.toLowerCase()]=a[n];e[t]=r}return e}function u(e){var t,n,a,r={};for(t=0,n=e.length;t<n;t++)a=e[t],r[a.Member]=f(!0,r[a.Member],s(a));return r}var c=window.kendo,l=/'/gi,f=e.extend,p=e.isArray,m=e.isPlainObject,v=".",g=function(e){e=e||{},this.culture=e.culture||c.culture(),this.stringifyDates=e.stringifyDates,this.decimalSeparator=this.culture.numberFormat[v]};g.prototype=g.fn={serialize:function(e,t,n){var a,r;for(r in t)a=n?n+"."+r:r,this.serializeField(e,t[r],t,r,a)},serializeField:function(e,n,a,r,i){p(n)?this.serializeArray(e,n,i):m(n)?this.serialize(e,n,i):e[i]===t&&(e[i]=a[r]=this.serializeValue(n))},serializeArray:function(e,t,n){var a,r,i,o,s;for(o=0,s=0;o<t.length;o++)a=t[o],r="["+s+"]",i=n+r,this.serializeField(e,a,t,r,i),s++},serializeValue:function(e){return e instanceof Date?e=this.stringifyDates?c.stringify(e).replace(/"/g,""):c.toString(e,"G",this.culture.name):"number"==typeof e&&(e=(""+e).replace(v,this.decimalSeparator)),e}},f(!0,c.data,{schemas:{"aspnetmvc-ajax":{groups:function(t){return e.map(this._dataAccessFunction(t),o)},aggregates:function(t){var n,a;if(t=t.d||t,n=t.AggregateResults||[],!e.isArray(n)){for(a in n)n[a]=u(n[a]);return n}return u(n)}}}}),f(!0,c.data,{transports:{"aspnetmvc-ajax":c.data.RemoteTransport.extend({init:function(e){var t=this,a=(e||{}).stringifyDates;c.data.RemoteTransport.fn.init.call(this,f(!0,{},this.options,e,{parameterMap:function(e,r){return n.call(t,e,r,{encode:!1,stringifyDates:a})}}))},read:function(e){var t=this.options.data,n=this.options.read.url;m(t)?(n&&(this.options.data=null),!t.Data.length&&n?c.data.RemoteTransport.fn.read.call(this,e):e.success(t)):c.data.RemoteTransport.fn.read.call(this,e)},options:{read:{type:"POST"},update:{type:"POST"},create:{type:"POST"},destroy:{type:"POST"},parameterMap:n,prefix:""}})}}),f(!0,c.data,{schemas:{webapi:c.data.schemas["aspnetmvc-ajax"]}}),f(!0,c.data,{transports:{webapi:c.data.RemoteTransport.extend({init:function(e){var t,a,r=this,i=(e||{}).stringifyDates;e.update&&(t="string"==typeof e.update?e.update:e.update.url,e.update=f(e.update,{url:function(n){return c.format(t,n[e.idField])}})),e.destroy&&(a="string"==typeof e.destroy?e.destroy:e.destroy.url,e.destroy=f(e.destroy,{url:function(t){return c.format(a,t[e.idField])}})),e.create&&"string"==typeof e.create&&(e.create={url:e.create}),c.data.RemoteTransport.fn.init.call(this,f(!0,{},this.options,e,{parameterMap:function(e,t){return n.call(r,e,t,{encode:!1,stringifyDates:i,culture:c.cultures["en-US"]})}}))},read:function(e){var t=this.options.data,n=this.options.read.url;m(t)?(n&&(this.options.data=null),!t.Data.length&&n?c.data.RemoteTransport.fn.read.call(this,e):e.success(t)):c.data.RemoteTransport.fn.read.call(this,e)},options:{read:{type:"GET"},update:{type:"PUT"},create:{type:"POST"},destroy:{type:"DELETE"},parameterMap:n,prefix:""}})}}),f(!0,c.data,{transports:{"aspnetmvc-server":c.data.RemoteTransport.extend({init:function(e){var t=this;c.data.RemoteTransport.fn.init.call(this,f(e,{parameterMap:function(e,a){return n.call(t,e,a,{encode:!0})}}))},read:function(t){var n,a,r=this.options.prefix,i=[r+"sort",r+"page",r+"pageSize",r+"group",r+"aggregate",r+"filter"],o=RegExp("("+i.join("|")+")=[^&]*&?","g");a=location.search.replace(o,"").replace("?",""),a.length&&!/&$/.test(a)&&(a+="&"),t=this.setup(t,"read"),n=t.url,n.indexOf("?")>=0?(a=a.replace(/(.*?=.*?)&/g,function(e){return n.indexOf(e.substr(0,e.indexOf("=")))>=0?"":e}),n+="&"+a):n+="?"+a,n+=e.map(t.data,function(e,t){return t+"="+e}).join("&"),location.href=n}})}})}(window.kendo.jQuery)},"function"==typeof define&&define.amd?define:function(e,t,n){(n||t)()}),function(e,define){define("aspnetmvc/kendo.combobox.aspnetmvc.min",["aspnetmvc/kendo.data.aspnetmvc.min"],e)}(function(){!function(e,t){var n=window.kendo,a=n.ui;a&&a.ComboBox&&(a.ComboBox.requestData=function(t){var n,a,r=e(t).data("kendoComboBox");if(r)return n=r.dataSource.filter(),a=r.input.val(),n&&n.filters.length||(a=""),{text:a}})}(window.kendo.jQuery)},"function"==typeof define&&define.amd?define:function(e,t,n){(n||t)()}),function(e,define){define("aspnetmvc/kendo.dropdownlist.aspnetmvc.min",["aspnetmvc/kendo.data.aspnetmvc.min"],e)}(function(){!function(e,t){var n=window.kendo,a=n.ui;a&&a.DropDownList&&(a.DropDownList.requestData=function(t){var n,a,r,i=e(t).data("kendoDropDownList");if(i)return n=i.dataSource.filter(),a=i.filterInput,r=a?a.val():"",n&&n.filters.length||(r=""),{text:r}})}(window.kendo.jQuery)},"function"==typeof define&&define.amd?define:function(e,t,n){(n||t)()}),function(e,define){define("aspnetmvc/kendo.multiselect.aspnetmvc.min",["aspnetmvc/kendo.combobox.aspnetmvc.min"],e)}(function(){!function(e,t){var n=window.kendo,a=n.ui;a&&a.MultiSelect&&(a.MultiSelect.requestData=function(t){var n,a=e(t).data("kendoMultiSelect");if(a)return n=a.input.val(),{text:n!==a.options.placeholder?n:""}})}(window.kendo.jQuery)},"function"==typeof define&&define.amd?define:function(e,t,n){(n||t)()}),function(e,define){define("aspnetmvc/kendo.imagebrowser.aspnetmvc.min",["aspnetmvc/kendo.multiselect.aspnetmvc.min"],e)}(function(){!function(e,t){var n=window.kendo,a=e.extend,r=e.isFunction;a(!0,n.data,{schemas:{"imagebrowser-aspnetmvc":{data:function(e){return e||[]},model:{id:"name",fields:{name:{field:"Name"},size:{field:"Size"},type:{field:"EntryType",parse:function(e){return 0==e?"f":"d"}}}}}}}),a(!0,n.data,{schemas:{"filebrowser-aspnetmvc":n.data.schemas["imagebrowser-aspnetmvc"]}}),a(!0,n.data,{transports:{"imagebrowser-aspnetmvc":n.data.RemoteTransport.extend({init:function(t){n.data.RemoteTransport.fn.init.call(this,e.extend(!0,{},this.options,t))},_call:function(t,a){a.data=e.extend({},a.data,{path:this.options.path()}),r(this.options[t])?this.options[t].call(this,a):n.data.RemoteTransport.fn[t].call(this,a)},read:function(e){this._call("read",e)},create:function(e){this._call("create",e)},destroy:function(e){this._call("destroy",e)},update:function(){},options:{read:{type:"POST"},update:{type:"POST"},create:{type:"POST"},destroy:{type:"POST"},parameterMap:function(e,t){return"read"!=t&&(e.EntryType="f"===e.EntryType?0:1),e}}})}}),a(!0,n.data,{transports:{"filebrowser-aspnetmvc":n.data.transports["imagebrowser-aspnetmvc"]}})}(window.kendo.jQuery)},"function"==typeof define&&define.amd?define:function(e,t,n){(n||t)()}),function(e,define){define("aspnetmvc/kendo.validator.aspnetmvc.min",["aspnetmvc/kendo.imagebrowser.aspnetmvc.min"],e)}(function(){!function(e,t){function n(){var e,t={};for(e in p)t["mvc"+e]=s(e);return t}function a(){var e,t={};for(e in p)t["mvc"+e]=d(e);return t}function r(e,t){var n,a,r,i={},o=e.data(),s=t.length;for(r in o)a=r.toLowerCase(),n=a.indexOf(t),n>-1&&(a=a.substring(n+s,r.length),a&&(i[a]=o[r]));return i}function i(t){var n,a,r=t.Fields||[],i={};for(n=0,a=r.length;n<a;n++)e.extend(!0,i,o(r[n]));return i}function o(e){var t,n,a,r,i={},o={},s=e.FieldName,d=e.ValidationRules;for(a=0,r=d.length;a<r;a++)t=d[a].ValidationType,n=d[a].ValidationParameters,i[s+t]=c(s,t,n),o[s+t]=u(d[a].ErrorMessage);return{rules:i,messages:o}}function s(e){return function(t){return t.attr("data-val-"+e)}}function d(e){return function(t){return!t.filter("[data-val-"+e+"]").length||p[e](t,r(t,e))}}function u(e){return function(){return e}}function c(e,t,n){return function(a){return!a.filter("[name="+e+"]").length||p[t](a,n)}}function l(e,t){return"string"==typeof t&&(t=RegExp("^(?:"+t+")$")),t.test(e)}var f=/("|\%|'|\[|\]|\$|\.|\,|\:|\;|\+|\*|\&|\!|\#|\(|\)|<|>|\=|\?|\@|\^|\{|\}|\~|\/|\||`)/g,p={required:function(e){var t,n,a,r=e.val(),i=e.filter("[type=checkbox]");return i.length&&(t=i[0].name.replace(f,"\\$1"),n="input:hidden[name='"+t+"']",a=i.next(n),a.length||(a=i.next("label.k-checkbox-label").next(n)),r=a.length?a.val():"checked"===e.attr("checked")),!(""===r||!r||0===r.length)},number:function(e){return""===e.val()||null==e.val()||null!==kendo.parseFloat(e.val())},regex:function(e,t){return""===e.val()||l(e.val(),t.pattern)},range:function(e,t){return""===e.val()||this.min(e,t)&&this.max(e,t)},min:function(e,t){var n=parseFloat(t.min)||0,a=kendo.parseFloat(e.val());return n<=a},max:function(e,t){var n=parseFloat(t.max)||0,a=kendo.parseFloat(e.val());return a<=n},date:function(e){return""===e.val()||null!==kendo.parseDate(e.val())},length:function(t,n){if(""!==t.val()){var a=e.trim(t.val()).length;return(!n.min||a>=(n.min||0))&&(!n.max||a<=(n.max||0))}return!0}};e.extend(!0,kendo.ui.validator,{rules:a(),messages:n(),messageLocators:{mvcLocator:{locate:function(e,t){return t=t.replace(f,"\\$1"),e.find(".field-validation-valid[data-valmsg-for='"+t+"'], .field-validation-error[data-valmsg-for='"+t+"']")},decorate:function(e,t){e.addClass("field-validation-error").attr("data-valmsg-for",t||"")}},mvcMetadataLocator:{locate:function(e,t){return t=t.replace(f,"\\$1"),e.find("#"+t+"_validationMessage.field-validation-valid")},decorate:function(e,t){e.addClass("field-validation-error").attr("id",t+"_validationMessage")}}},ruleResolvers:{mvcMetaDataResolver:{resolve:function(t){var n,a=window.mvcClientValidationMetadata||[];if(a.length)for(t=e(t),n=0;n<a.length;n++)if(a[n].FormId==t.attr("id"))return i(a[n]);return{}}}}})}(window.kendo.jQuery)},"function"==typeof define&&define.amd?define:function(e,t,n){(n||t)()}),function(e,define){define("kendo.aspnetmvc.min",["kendo.data.min","kendo.combobox.min","kendo.dropdownlist.min","kendo.multiselect.min","kendo.validator.min","aspnetmvc/kendo.data.aspnetmvc.min","aspnetmvc/kendo.combobox.aspnetmvc.min","aspnetmvc/kendo.dropdownlist.aspnetmvc.min","aspnetmvc/kendo.multiselect.aspnetmvc.min","aspnetmvc/kendo.imagebrowser.aspnetmvc.min","aspnetmvc/kendo.validator.aspnetmvc.min"],e)}(function(){!function(e,t){function n(t){kendo.__documentIsReady?t():e(t)}var a=e.extend;e(function(){kendo.__documentIsReady=!0}),a(kendo,{syncReady:n})}(window.kendo.jQuery)},"function"==typeof define&&define.amd?define:function(e,t,n){(n||t)()});
//# sourceMappingURL=kendo.aspnetmvc.min.js.map
;/** 
 * Kendo UI v2017.2.504 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2017 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(e){"function"==typeof define&&define.amd?define(["kendo.core.min"],e):e()}(function(){!function(e,y){kendo.cultures["en-AU"]={name:"en-AU",numberFormat:{pattern:["-n"],decimals:2,",":",",".":".",groupSize:[3],percent:{pattern:["-n%","n%"],decimals:2,",":",",".":".",groupSize:[3],symbol:"%"},currency:{name:"Australian Dollar",abbr:"AUD",pattern:["-$n","$n"],decimals:2,",":",",".":".",groupSize:[3],symbol:"$"}},calendars:{standard:{days:{names:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],namesAbbr:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],namesShort:["Su","Mo","Tu","We","Th","Fr","Sa"]},months:{names:["January","February","March","April","May","June","July","August","September","October","November","December"],namesAbbr:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]},AM:["AM","am","AM"],PM:["PM","pm","PM"],patterns:{d:"d/MM/yyyy",D:"dddd, d MMMM yyyy",F:"dddd, d MMMM yyyy h:mm:ss tt",g:"d/MM/yyyy h:mm tt",G:"d/MM/yyyy h:mm:ss tt",m:"MMMM d",M:"MMMM d",s:"yyyy'-'MM'-'dd'T'HH':'mm':'ss",t:"h:mm tt",T:"h:mm:ss tt",u:"yyyy'-'MM'-'dd HH':'mm':'ss'Z'",y:"MMMM yyyy",Y:"MMMM yyyy"},"/":"/",":":":",firstDay:1}}}}(this)});
//# sourceMappingURL=kendo.culture.en-AU.min.js.map
;/** 
 * Kendo UI v2017.2.504 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2017 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(e){"function"==typeof define&&define.amd?define(["kendo.core.min"],e):e()}(function(){!function(e,y){kendo.cultures["en-GB"]={name:"en-GB",numberFormat:{pattern:["-n"],decimals:2,",":",",".":".",groupSize:[3],percent:{pattern:["-n%","n%"],decimals:2,",":",",".":".",groupSize:[3],symbol:"%"},currency:{name:"Pound Sterling",abbr:"GBP",pattern:["-$n","$n"],decimals:2,",":",",".":".",groupSize:[3],symbol:"£"}},calendars:{standard:{days:{names:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],namesAbbr:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],namesShort:["Su","Mo","Tu","We","Th","Fr","Sa"]},months:{names:["January","February","March","April","May","June","July","August","September","October","November","December"],namesAbbr:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]},AM:["AM","am","AM"],PM:["PM","pm","PM"],patterns:{d:"dd/MM/yyyy",D:"dd MMMM yyyy",F:"dd MMMM yyyy HH:mm:ss",g:"dd/MM/yyyy HH:mm",G:"dd/MM/yyyy HH:mm:ss",m:"d MMMM",M:"d MMMM",s:"yyyy'-'MM'-'dd'T'HH':'mm':'ss",t:"HH:mm",T:"HH:mm:ss",u:"yyyy'-'MM'-'dd HH':'mm':'ss'Z'",y:"MMMM yyyy",Y:"MMMM yyyy"},"/":"/",":":":",firstDay:1}}}}(this)});
//# sourceMappingURL=kendo.culture.en-GB.min.js.map
;/** 
 * Kendo UI v2017.2.504 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2017 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(e){"function"==typeof define&&define.amd?define(["kendo.core.min"],e):e()}(function(){!function(e,y){kendo.cultures["en-NZ"]={name:"en-NZ",numberFormat:{pattern:["-n"],decimals:2,",":",",".":".",groupSize:[3],percent:{pattern:["-n %","n %"],decimals:2,",":",",".":".",groupSize:[3],symbol:"%"},currency:{name:"New Zealand Dollar",abbr:"NZD",pattern:["-$n","$n"],decimals:2,",":",",".":".",groupSize:[3],symbol:"$"}},calendars:{standard:{days:{names:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],namesAbbr:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],namesShort:["Su","Mo","Tu","We","Th","Fr","Sa"]},months:{names:["January","February","March","April","May","June","July","August","September","October","November","December"],namesAbbr:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]},AM:["a.m.","a.m.","A.M."],PM:["p.m.","p.m.","P.M."],patterns:{d:"d/MM/yyyy",D:"dddd, d MMMM yyyy",F:"dddd, d MMMM yyyy h:mm:ss tt",g:"d/MM/yyyy h:mm tt",G:"d/MM/yyyy h:mm:ss tt",m:"d MMMM",M:"d MMMM",s:"yyyy'-'MM'-'dd'T'HH':'mm':'ss",t:"h:mm tt",T:"h:mm:ss tt",u:"yyyy'-'MM'-'dd HH':'mm':'ss'Z'",y:"MMMM yyyy",Y:"MMMM yyyy"},"/":"/",":":":",firstDay:1}}}}(this)});
//# sourceMappingURL=kendo.culture.en-NZ.min.js.map
;/** 
 * Kendo UI v2017.2.504 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2017 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(e){"function"==typeof define&&define.amd?define(["kendo.core.min"],e):e()}(function(){!function(e,y){kendo.cultures["en-US"]={name:"en-US",numberFormat:{pattern:["-n"],decimals:2,",":",",".":".",groupSize:[3],percent:{pattern:["-n %","n %"],decimals:2,",":",",".":".",groupSize:[3],symbol:"%"},currency:{name:"US Dollar",abbr:"USD",pattern:["($n)","$n"],decimals:2,",":",",".":".",groupSize:[3],symbol:"$"}},calendars:{standard:{days:{names:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],namesAbbr:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],namesShort:["Su","Mo","Tu","We","Th","Fr","Sa"]},months:{names:["January","February","March","April","May","June","July","August","September","October","November","December"],namesAbbr:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]},AM:["AM","am","AM"],PM:["PM","pm","PM"],patterns:{d:"M/d/yyyy",D:"dddd, MMMM dd, yyyy",F:"dddd, MMMM dd, yyyy h:mm:ss tt",g:"M/d/yyyy h:mm tt",G:"M/d/yyyy h:mm:ss tt",m:"MMMM d",M:"MMMM d",s:"yyyy'-'MM'-'dd'T'HH':'mm':'ss",t:"h:mm tt",T:"h:mm:ss tt",u:"yyyy'-'MM'-'dd HH':'mm':'ss'Z'",y:"MMMM, yyyy",Y:"MMMM, yyyy"},"/":"/",":":":",firstDay:0}}}}(this)});
//# sourceMappingURL=kendo.culture.en-US.min.js.map
;/*
    Constants
*/
var COLUMNS = {
    TD: {
        ICON: "td:nth-child(1)",
        NAME: "td:nth-child(3)",
        GROUP: "td:nth-child(11)",
    }
}
/*
    override the filterable options
*/
var EQ = "Equal to", NEQ = "Not equal to";
kendo.ui.FilterMenu.fn.options.operators.string = {
    eq: EQ,
    neq: NEQ,
    startswith: 'Starts with',
    contains: 'Contains',
    doesnotcontain: 'Does not contain',
    endswith: 'Ends with',
};

kendo.ui.FilterMenu.fn.options.operators.number = {
    eq: EQ,
    neq: NEQ,
    gte: 'Is greater than or equal to',
    gt: 'Is greater than',
    lte: 'Is less than or equal to',
    lt: 'Is less than',
};

kendo.ui.FilterMenu.fn.options.operators.date = {
    eq: EQ,
    neq: NEQ,
    gte: 'Is after or equal to',
    gt: 'Is after',
    lte: 'Is before or equal to',
    lt: 'Is before',
};

kendo.ui.FilterMenu.fn.options.operators.enums = {
    eq: EQ,
    neq: NEQ,
};

/*
    Extended functionalities for the Kendo UI Grid widget
*/
$.extend(kendo.ui.Grid.prototype, {
    _hiddenColumns: [],
    _status: null,
    _navCurrent: null,
    _progressCounter: 0,
    validateNewFields: function () {
        var valid = true;

        var rfields = this.findRawFields("");

        for (var ix in rfields) {
            var rfield = rfields[ix];
            var col = 1;
            for (var fieldName in this.dataSource.options.schema.model.fields) {
                var field = this.dataSource.options.schema.model.fields[fieldName];
                if (field.validation && field.validation.required === true) {
                    if (rfield[fieldName] == null || rfield[fieldName] === "") {
                        var row = this.tbody.find("tr[data-uid='" + rfield.uid + "']");
                        var reqCell = row.find("td:nth-child(" + col + ")");
                        reqCell.click();
                        //reqCell.kendoValidator().data("kendoValidator").validate();
                        valid = false;
                        break;
                    }
                }
                col++;
            }
            if (!valid) break;
        }
        return valid;
    },
    /*
        Validate table for input fields marked as invalid
        And manually validate fields has a field relationship
    */
    hasInvalidFields: function () {
        var invalid = this.tbody.find("tr > td input:not(:visible).k-invalid").length != 0;
        if (!invalid) {
            var selected = this.select(), fieldsConf = this.dataSource.options.schema.model.fields;
            for (var f in fieldsConf) {
                var c = fieldsConf[f];
                if (c.relationalField && c.relationalField != "") {
                    var cell = selected.children("td:nth-child(" + (c.index + 1) + ")");
                    if (cell && cell.length > 0 && this.editable) {
                        invalid = !this.editable.validatable.validate();
                        if (invalid) break;
                        this.closeCell();
                        this.editCell(cell);
                    }
                    this.editable && this.closeCell();
                }
            }
        }
        return invalid;
    },
    findRawFields: function (rowIx) {
        return this._data ? $.grep(this._data, function (e) { return e.RowIndex == rowIx; }) : [];
    },
    hideColumnEx: function (column) {
        if (-1 == $.inArray(column, this._hiddenColumns, 0)) {
            this._hiddenColumns.push(column);
        }
        kendo.ui.Grid.prototype.hideColumn.call(this, column);
    },
    showColumnEx: function (column) {
        var i = $.inArray(column, this._hiddenColumns, 0)
        if (-1 != i) {
            this._hiddenColumns.splice(i, 1);
        }
        kendo.ui.Grid.prototype.showColumn.call(this, column);
    },
    /*
    * Double click column resize handling extension for kendoGrid
    */
    resizeColumnOnDblClick: function (enable) {
        var gridObj = this;
        if (enable) {
            gridObj.element.on("dblclick", ".k-resize-handle", function (e) {
                var th = $(this).data("th");
                var index = th.index();

                var iTitleWidth = $('body').measureText(th.data().title);

                var currentWidth = th.width();
                var referenceWidth = 0;
                var widths = [];

                widths.push(iTitleWidth);

                gridObj.element.find("td:nth-child(" + (index + 1) + "):visible").each(function (i, el) {
                    var str = $(el).text();
                    var iWidth = $('body').measureText(str);
                    if (iWidth > currentWidth) {
                        widths.push(iWidth);
                    }
                });

                if (widths.length == 0 && iTitleWidth < currentWidth) {
                    widths.push(iTitleWidth);
                }

                var maxWidth = Math.max.apply(Math, widths) + 30;
                var hiddenLength = gridObj._hiddenColumns.length;
                if (hiddenLength > 0) {
                    var siblings = th.siblings();
                    for (var i = 0; i < siblings.length; i++) {
                        var sibling = $(siblings[i]);
                        if (sibling.css("display") == "none") {
                            if (sibling.index() < index) {
                                index -= 1;
                                if ((--hiddenLength) == 0) break;
                            }
                        }
                    }
                }

                gridObj.thead.siblings(0).find("col:eq(" + index + ")").css("width", maxWidth);
                gridObj.table.children("colgroup").find("col:eq(" + index + ")").css("width", maxWidth);
            });
        } else {
            gridObj.element.off("dblclick", ".k-resize-handle");
        }
        return gridObj;
    },
    /*
        Expands a specific tree in the grid described by groupData.Template and groupData.Group
    */
    expandTemplateWithData: function (groupData) {
        if (groupData) {
            var templateP = this.tbody.find("p:contains('" + groupData.Template + "')");
            if (templateP) {
                templateP.find("a").click();
                var templateTr = templateP.closest("tr");
                var group = templateTr.nextWithChild("p:contains('" + groupData.Group + "')");
                if (group) {
                    group.find("a").click();
                }
            }
        }
    },
    /*
        Clean up and hide rows that are empty to properly display empty groups
    */
    cleanUpGrid: function (groups) {
        var selectors = [];
        for (var i in groups) {
            selectors.push("p:contains('" + groups[i] + "')");
        }

        var groupCaps = this.tbody.find(selectors.join(", "));

        groupCaps.each(function (i, e) {
            var $e = $(e);
            var caption = $e.text();
            var groupCount = caption.match(/\(([0-9]+)\)/g)[0].match(/[0-9]+/g)[0];//caption.match(/[0-9]+/g)[0];
            var tr = $e.closest("tr"), groupTR = tr;
            var hideC = 0;
            for (var count = 0; count < groupCount; count++) {
                var childTr = tr.next();
                var tdName = childTr.find(COLUMNS.TD.NAME);
                
                if (tdName && tdName.size() > 0) {
                    if (tdName.text() == "{empty}") {
                        hideC++;
                        childTr.css("position", "absolute");
                        childTr.css("color", "white");
                        childTr.css("z-index", -1);
                    }
                }

                var tdGroup = childTr.find(COLUMNS.TD.GROUP);
                if (tdGroup && tdGroup.size() > 0) {
                    if (tdGroup.text() == "My Works") {
                        childTr.toggleClass("my-works");
                        var tdI = childTr.find(COLUMNS.TD.ICON);
                        tdI.prepend('<a class="k-icon icon-my-work" tabindex="-1">My Works</a>');
                    } else if (tdGroup.text() == "My Documents") {
                        childTr.toggleClass("my-documents");
                        var tdI = childTr.find(COLUMNS.TD.ICON);
                        tdI.prepend('<a class="k-icon icon-my-doc" tabindex="-1">My Documents</a>');
                    }
                }
                tr = childTr;
            }
            var rem = groupCount - hideC;
            groupTR.data("child", rem);
            if (rem != groupCount) {
                $e.text(caption.replace("(" + groupCount + ")", "(" + (rem) + ")"));
                $e.prepend('<a class="k-icon k-i-expand" tabindex="-1" style="pointer-events: none;"></a>');
            }
        });
    },
    /*
        Enable collapse/expand upon clicking of the group label 
    */
    setGroupCollapsible: function () {
        var thisGrid = this;
        thisGrid.tbody.find("tr.k-grouping-row").click(function (e) {
            var thisGroup = this, $thisGroup = $(thisGroup), a = $thisGroup.find("a");
            if ($thisGroup.data("child") == 0) return;

            if (!a || a.length == 0 || a[0] == e.srcElement) return;

            if (a.hasClass("k-i-expand") == true) {
                thisGrid.expandGroup(thisGroup);
            } else if (a.hasClass("k-i-collapse") == true) {
                thisGrid.collapseGroup(thisGroup);
            }
            e.preventDefault();
        });

        thisGrid.tbody.find("tr.k-grouping-row > td > p > a").css("pointer-events", "none");
        return this;
    },
    /*
        Get the ItemID of the item next to the specified Item
    */
    getNextItem: function (itemID, process) {
        var recycle = false;
        var thisGroupedData = this.getGroupedData();
        var groupSiblings = [];
        var thisItemIx = -1;
        var thisProc = null;
        var thisGroup = null;
        var targetItem = null;

        if ((thisProc = thisGroupedData[process]) != null && thisProc.length > 0) {
            targetItem = $.grep(thisProc, function (i) {
                return (i.ItemID == itemID);
            });
        }
        
        if (targetItem.length === 1 && (thisItemIx = thisProc.indexOf(targetItem[0])) != -1) {
            if (thisProc.length > 1) {
                if (thisItemIx + 1 >= thisProc.length) {
                    if (recycle) {
                        return thisProc[0].ItemID;
                    } else {
                        return thisProc[thisItemIx-1].ItemID
                    }
                } else {
                    return thisProc[thisItemIx + 1].ItemID;
                }
            }

            var nextGroup = this.getNextGroup(thisGroupedData, targetItem[0].Process);
            if (nextGroup && nextGroup.length > 0) {
                return nextGroup[0].ItemID;
            } else {
                return -1;
            }
        } else {
            return -1;
        }
    },
    getNextGroup: function (processes, processName) {
        var processFound = false;
        var skippedProcesses = [];
        var next = null;
        for (var process in processes) {
            if (processFound == false && process != processName) {
                skippedProcesses.push(processes[process]);
            } else if (processFound == false && process == processName) {
                processFound = true;
            } else if (processFound && process != processName) {
                next = processes[process];
                break;
            }
        }

        if (next == null) {
            for (var process in skippedProcesses) {
                next = skippedProcesses[process];
                break;
            }
        }
        return next;
    },
    selectNext: function () {             
        var source = this.dataSource;
        var current = this.select();
        this.clearSelection();
        if (current.length == 0) {
            this.selectFirst();
        } else {
            var next = current.next();
            if (next.length > 0) {
                this.select(next[0]);
                this.scrollTo(this.select());
            } else {
                var pagesize = source.pageSize();
                var total = source.data().length;
                var totalpages = Math.round(total / pagesize);
                var page = source.page() + 1;

                if (page > totalpages) {
                    this.selectLast();
                    return;
                }
                source.page(page);
                this.dataSource = source;
                this.selectFirst();
            }
        }
    },
    selectPrevious: function () {        
        var source = this.dataSource;
        var current = this.select();
        this.clearSelection();
        if (current.length == 0) {
            this.selectLast();
        } else {
            var prev = current.prev();
            if (prev.length > 0) {
                this.select(prev[0]);
                this.scrollTo(this.select());
            } else {
                var pagesize = source.pageSize();
                var total = source.data().length;
                var totalpages = Math.round(total / pagesize);
                var page = source.page() - 1;

                if (page == 0) {
                    this.selectFirst();
                    return;
                }
                source.page(page);
                this.dataSource = source;
                this.selectLast();
            }
        }
    },
    selectFirst: function () {
        var body = typeof (this.tbody) != "undefined" ? this.tbody : this.table.children("tbody"), rows = body.children();
        if (rows.length > 0) {
            this.clearSelection();
            this.select(rows[0]);
            this.scrollTo(this.select());
        }
    },
    selectLast: function () {
        var body = typeof (this.tbody) != "undefined" ? this.tbody : this.table.children("tbody"), rows = body.children();
        if (rows.length > 0) {
            this.clearSelection();
            this.select(rows[rows.length - 1]);
            this.scrollTo(this.select());
        }
    },
    scrollTo: function (row) {
        if (!row && !row.offset()) return;
        var scrollContentOffset = this.content.offset().top;
        var selectContentOffset = row.offset().top;
        var distance = (selectContentOffset - scrollContentOffset);

        if (distance >= 0) {
            distance += row.height();
        }

        if (distance > this.content.height() || distance < 0) {
            this.element.find(".k-grid-content").animate({
                scrollTop: distance
            }, 100);
        }
    },
    getGroupedData: function () {
        var rawData = this.dataSource.view();
        var groupedData = {};
        for (var i = 0; i < rawData.length; i++) {
            var data = rawData[i];
            if (data.Name != "{empty}") {
                if (!groupedData[data.Process]) groupedData[data.Process] = [];
                
                groupedData[data.Process].push(data);
            }
        }
        return groupedData;
    },
    // Retrieve the row element object identified by the uid
    getItem: function (uid) {
        return this.tbody.find("tr[data-uid='" + uid + "']");
    },
    /* Retrieve the row element object identified by the row index */
    getItemByLineNumber: function (line, data) {
        var item = this.dataSource.data().filter(function (o) {
            return o.RowIndex === line;
        });
        if (item.length == 0) return null;
        data && (data.dataItem = item[0]);
        return this.getItem(item[0].uid);
    },
    /* Retrieve the row element object identified by the ItemID */
    getItemByItemID: function (itemid) {
        var item = this.dataSource.data().filter(function (o) {
            return o.ItemID === itemid;
        });
        if (item.length == 0) return null;
        return this.getItem(item[0].uid);
    },
    // Mark the selected row item as deleted 
    toggleDeleteMark: function () {
        var table = this,
            rows = this.tbody.find("input[role='mark-for-deletion']"),
            rowsToDelete = [];
        // loop through all grid rows
        $.each(rows, function () {
            var row = $(this).closest("tr"),
                dataItem = table.dataItem(row);
            // check if row is checked
            if (this.checked || dataItem.deleted) {
                if (!dataItem.deleted) {
                    rowsToDelete.push(dataItem);
                }
                row.css("display", "none")
                    .addClass("rm-deleted");
                dataItem.deleted = true;
                dataItem.new = false;
            }
        });

        return rowsToDelete;
    },
    /*
        Handler for the grid edit cell event, this should be bound manually.
        expects:
            e: jQuery event object
    */
    onEdit: function (e) {
        var tr = e.container.parent(), grid = this;
        if (tr.hasClass("row-marked-delete") || tr.hasClass("k-state-selected") == false ||
            e.container.find("input[name='mark_row']").length > 0) {
            grid.closeCell();
            grid.table.focus();
        } else {
            var td = tr.children("td");
            td.removeClass("k-dirty-cell");
        }
    },
    /* Mark the field of the row as dirty/modified
        Expects:
            e : {
                field : the field name,
                items : array of data item if the row to be marked as dirty
            }    
    */
    saveDirtyField: function (e) {
        var fconf = this.dataSource.options.schema.model.fields[e.field];
        e.items[0].dirtyFields = e.items[0].dirtyFields || {};
        e.items[0].dirtyFields[e.field] = "Dirty";
        if (fconf && fconf.type == "number" && e.items[0][e.field] == null && e.field != "RowIndex" && e.field != "id") {
            e.items[0].set(e.field, 0);
        }
    },
    /*
        Get the datasource schema definition for a field
        expects:
            fieldName : Name of the field to retrieve its schema definition
    */
    getFieldSchema: function(fieldName) {
        return this.dataSource.options.schema.model.fields[fieldName];
    },
    // Delete the row marked as deleted from the view and from the datasource
    deleteMarkedRows: function () {
        this.setState("deleting");
        var data = this.dataSource.data(), count = data.length, $row, row, trash = [];
        for (var i = 0; i < count; i++) {
            if ((row = data[i]) && row.deleted) {
                trash.push(row);
            }
        }

        for (var i = 0; i < trash.length; i++) {
            this.dataSource.remove(trash[i]);
        }
        this.setState(null);
        return trash;
    },
    /* Save the field configuration of the table that includes an index
        Expects:
            array of fields : [{
                field : field/column name,
                index : field/column index
            }]
    */
    saveFields: function (fields) {
        this._fields = fields;
        return this;
    },
    /* Set the cell state to Dirty or ConstraintError*/
    setFieldState: function ($row, field, state) {
        var fieldConfig, $td, tdIx;
        if (fieldConfig = this.dataSource.options.schema.model.fields[field]) {
            tdIx = fieldConfig.index + 1;
            $td = $row.find("td:nth-child(" + tdIx + ")");
            if (state === "Dirty") {
                $td.removeClass("k-failed-cell");
                $td.addClass("k-dirty-cell");
                $td.prepend("<span class='k-dirty'></span>");
            } else if (state === "ConstraintError") {
                $td.removeClass("k-dirty-cell");
                $td.removeClass("k-unbalanced-cell");
                $td.addClass("k-failed-cell");
            }
            return $td;
        }
        return null;
    },
    /* Refresh the row with the updated values. */
    refreshRow: function (itemid, fieldsToUpdate) {
        var $row = this.getItemByItemID(itemid);
        if (!$row) return;

        var row = this.dataItem($row);
        for (var field in fieldsToUpdate) {
            row.set(fieldsToUpdate[field].ColumnName, fieldsToUpdate[field].FieldValue);
        }
    },
    /* Remove the constraint failure state from the cells. */
    refreshRowState: function ($row) {
        var $tds = $row.children(".k-failed-cell"), row = this.dataItem($row);
        if (!row) return;
        $tds.toggleClass("k-failed-cell");
        for (var field in row.dirtyFields) {
            var fieldConfig, dirtyValue = row.dirtyFields[field];
            if ((fieldConfig = this.dataSource.options.schema.model.fields[field])
                && (tdIx = fieldConfig.index + 1)) {
                $td = $row.find("td:nth-child(" + tdIx + ")");
                if (dirtyValue === "Dirty") {
                    $td.addClass("k-dirty-cell");
                    $td.prepend("<span class='k-dirty'></span>");
                } else if (dirtyValue === "ConstraintError") {
                    $td.addClass("k-failed-cell");
                }
            }
        }
    },
    /* Mark the view of the the data items as deleted, new or dirty
        since delete/new/dirty marks are discarded when the datasource rebinds prematurely
    */
    refreshRowsState: function () {
        var data = this.dataSource.view(), count = data.length, $row, row, dirty = false, tdIx = 0, $td;
        if (this.getState() === "adding") return true;
        for (var i = 0; i < count; i++) {
            row = data[i], $row = this.getItem(row.uid);
            
            if (row.deleted) {
                if (!dirty) dirty = true;
                continue;
            } else if (row.new) {
                if (!dirty) dirty = true;
                $row.length > 0 && !$row.hasClass("row-marked-new") && $row.toggleClass("row-marked-new");
            }

            if (row.dirty || row.dirtyFields) {
                if (!dirty) dirty = true;
                for (var field in row.dirtyFields) {
                    var fieldConfig, dirtyValue = row.dirtyFields[field];
                    if ((fieldConfig = this.dataSource.options.schema.model.fields[field])
                        && (tdIx = fieldConfig.index + 1)) {
                        $td = $row.find("td:nth-child(" + tdIx + ")");
                        if (dirtyValue === "Dirty") {
                            $td.addClass("k-dirty-cell");
                            $td.prepend("<span class='k-dirty'></span>");
                        } else if (dirtyValue === "ConstraintError") {
                            $td.addClass("k-failed-cell");
                        }
                    }
                }
            }
        }
        return dirty;
    },
    /*
        Get the tolerance value from an array of tolerance configuration.
        Return the tolerance from Amount or Multiplier (Percent or Decimal) whichever is lower
    */
    getTolerance: function (tolerances, base) {
        if (tolerances && Array.isArray(tolerances)) {
            var amountTolerance = amountTolerance = tolerances[ToleranceIndex.Amount],
                multiplier = tolerances[ToleranceIndex.Percent];
            if (multiplier) {
                var tolerance = Number(kendo._round(base * multiplier, 2));
                if (amountTolerance === 0 || tolerance < amountTolerance)
                    amountTolerance = tolerance;
            }
            return amountTolerance;
        } else {
            return tolerances || 0.0;
        }
    },
    /*
        Check existence of relational fields and determine if the field is balanced to its corresponding relational
        field value.
        Update the cells state if the fields are unbalanced.
        expects:
            targetfield: If specified, check only the relationship balance for this field.
                            If not, check all fields with DG relationship
    */
    checkFieldRelationshipBalance: function (targetField) {
        var relationalFields = {}, fieldsConf = this.dataSource.options.schema.model.fields,
            fieldRelationship,arrFieldRelationship=[], operationResult;

        if (targetField) {
            var c = fieldsConf[targetField];
            if (c.relationalField && c.relationalField != "") {
                relationalFields[targetField] = c;
            }
        } else {
            for (var f in fieldsConf) {
                var c = fieldsConf[f];
                if (c.relationalField && c.relationalField != "") {
                    relationalFields[f] = c;
                }
            }
        }
        for (var fieldName in relationalFields) {
            var field = relationalFields[fieldName];

            if (field && field.relationalFieldOperation == "Sum") {
                var sum = this.getSum(fieldName) || 0, total = this.options.getRelationalData(field.relationalField) || 0,
                    index = this.getFieldIndex(field), tolerances = field.tolerance, toleranceValue = this.getTolerance(tolerances, total),
                    relationalHeader = this.thead.find("th:nth-child(" + (index + 1) + ")");
                operationResult = sum;
                relationalHeader.addClass("relational-field");

                var $indicator = relationalHeader.find("span.rf-indicator");
                if ($indicator.length == 0) {
                    ($indicator = $("<span class='rf-indicator fa'></span>")).prependTo(relationalHeader[0]);
                } else {
                    $indicator.attr("class", null).addClass("fa").addClass("rf-indicator");
                }

                var relationalState = RelationalStates.Balanced;
                var absDiff = 0;
                if (total != sum) {
                    var relationalCells = this.tbody.find("td:not(.k-failed-cell):nth-child(" + (index + 1) + ")");

                    relationalCells.addClass("k-unbalanced-cell");
                    
                    absDiff = Number(kendo._round(Math.abs(total - sum), 2));
                    if (absDiff <= toleranceValue) {
                        // if the relational difference falls within tolerance, display the amber check icon
                        $indicator.addClass("rf-unbalanced-intol-head").addClass("fa-check-circle");
                        relationalState = RelationalStates.UnbalancedInTolerance;
                        fieldRelationship = {
                            fieldName:field.name,
                            caption:field.caption,
                            state: relationalState,
                            relationalField:field.relationalField,
                            tolerance:field.tolerance[0],
                            toleranceSaveSettings:field.toleranceSaveSettings,
                            relationalFieldOperation: field.relationalFieldOperation,
                            relationalFieldData: total,
                            operationResult: operationResult
                        }
                        arrFieldRelationship.push(fieldRelationship);
                    } else {
                        // if the relational difference falls outside tolerance, display the red fail icon
                        $indicator.addClass("rf-unbalanced-head").addClass("fa-times-circle");
                        relationalState = RelationalStates.Unbalanced;
                    }
                } else if (sum == total) {
                    var relationalCells = this.tbody.find("td:nth-child(" + (index + 1) + ")");
                    relationalCells.removeClass("k-unbalanced-cell");
                    $indicator.addClass("rf-balanced-head").addClass("fa-check-circle");
                }

                var title = field.relationalField + ": " + total;

                // if tolerance is available, display the tolerance value in percent
                if (toleranceValue) {
                    title = kendo.format("{0}, Tolerance: {1} (+/- {2}{3})", title, toleranceValue,
                        tolerances.join(" or "));

                    absDiff = sum > total ? absDiff * -1 : absDiff;

                    title = kendo.format("{0}, Difference: {1}", title, absDiff);
                }

                relationalHeader.attr("title", title);

                $("body").message("event_RelationalField", {
                    field: field.relationalField,
                    state: relationalState,
                    tdField: fieldName,
                    tolerance: tolerances.join(" or ")
                });
            }
        }
        return arrFieldRelationship;
    },
    /*
        Get the field index in the current grid layout given the the field schema config
    */
    getFieldIndex: function (field) {
        // current columns order
        var columns = this.columns;
        if (columns == null || columns == undefined || columns.length == 0)
            throw "No columns defined";

        // if the field index is the same as the current column index, do nothing
        if (columns.length > field.index) { //to avoid "index out of bound" error

            if (columns[field.index].field == field.name) {
                return field.index;
            }
        }
        
        // look for the field's index if the current index does not coincide with the column index
        for (var i = 0; i < columns.length; i++) {
            if (columns[i].field == field.name) {
                // update the field index so we do not need to look for it's index the next time
                return field.index = i;
            }
        }
    },
    /*
        Determine if the the grid column is balanced based on the field relationship configuration of the column.
        expects:
            fieldName : the name of the column,
            ignoreTolerance: ignore the tolerance property of the DG-TD relationship
    */
    isBalanced: function (fieldName, ignoreTolerance) {
        var field = this.dataSource.options.schema.model.fields[fieldName],
            sum = this.getSum(fieldName), total = this.options.getRelationalData(field.relationalField),
            tolerances = field.tolerance, toleranceValue = ignoreTolerance ? 0 : this.getTolerance(tolerances, total);
        var balanced = (sum != 0 && total == sum)

        // if not balanced, check if the difference falls within tolerance
        var absDiff = Number(kendo._round(Math.abs(total - sum), 2));
        if (!balanced && (absDiff <= toleranceValue))
            balanced = true;

        return balanced;
    },
    /* Set the page of the grid given the row index        
    */
    setPage: function (rowIndex, notChange) {
        var grid = this, pageSize = grid.dataSource.options.pageSize, currentPage = grid.pager.page(),
            itemPage = Math.ceil(rowIndex / pageSize);
        if (itemPage != currentPage && !notChange) {
            grid.pager.page(itemPage);
        }
        return itemPage != currentPage;
    },
    /* Get the sum of all the line items of the specified field.
        expects:
            fieldName : name of the field/column
            skipIndex: RowIndex to skip from calculation (necessary for cases that value change of the dataitem viewmodel
                                                            occurs later than validation)
    */
    getSum: function (fieldName, skipIndex) {
        var fconfig = this.dataSource.options.schema.model.fields[fieldName], data = this.dataSource.data(),
            length = data.length, sum = 0;
        if (fconfig.type == "number") {
            for (var i = 0; i < length; i++) {
                var value = parseFloat(data[i].get(fieldName)), valDec = value.countDecimals(), sumDec = sum.countDecimals(),
                    decimals = valDec > sumDec ? valDec : sumDec;
                sum += ((data[i].deleted) || (data[i].RowIndex == skipIndex)) ? 0 : value || 0;
                sum = parseFloat(sum.toFixed(decimals));
            }
        } else {
            throw fieldName + " is not a numeric type! Sum cannot be computed.";
        }
        return sum;
    },
    /*
        Validate the relational field.
        expects:
            fname: field name of column to be validated to its relational field
            value: value of the currently focused line item
            skipIndex: RowIndex to be skipped from the calculation of the column/field total
            info: out parameter to provide to the caller
                {
                    relationalField: name of the relational field associated to the column
                }

                If the header relational value is a negative value, do not allow relational total to be lesser than the relational header value.
                If the header relational value is a positive value, do not allow relational total to be greater than the relational header value
    */
    relationalValidation: function (fname, value, skipIndex, info) {
        if (!fname) return true;

        var valid = true;

        var f = this.dataSource.options.schema.model.fields[fname], options = this.options;
        var relationalValue = options && options.getRelationalData ? options.getRelationalData(f.relationalField) : 0;

        if (f.relationalFieldOperation == "Sum") {
            var difference = this.getRelationalRemainder(fname, relationalValue, skipIndex, value);
            info && (info.relationalField = f.relationalField);

            var tolerances = f.tolerance, toleranceValue = this.getTolerance(tolerances, relationalValue);
            
            // if the relational value is positive, do not allow the remaining difference to be negative (less than zero)
            if (relationalValue > 0) {
                if (difference < 0 || (difference > 0 && difference < 0.01)) { valid = false };
            }
                // if the relational value is negative, do not allow the remaining difference to be positive (greater than zero)
            else if (relationalValue < 0) {
                if (difference > 0 || (difference < 0 && difference > -0.01)) { valid = false };
            }
            
            // if the relational field balance fails, check if the difference falls within tolerance
            var absDiff = Number(kendo._round(Math.abs(difference), 2));
            if (!valid && absDiff <= toleranceValue) {
                valid = true;
            }
        }

        return valid;
    },
    /*
        Calculate the remainder value for a field with DG relationship
        expects:
            fname: TD field name to calculate the remainder from
            relationalValue: DG relational field value 
            skipIndex: index of the row to exclude from calculation
            skipValue: value of the field to deduct from the remainder
    */
    getRelationalRemainder: function (fname, relationalValue, skipIndex, skipValue) {
        var sum = this.getSum(fname, skipIndex), difference = (relationalValue = Number(relationalValue)) - sum - (skipValue || 0), decimals = [0];
        decimals.push((relationalValue && relationalValue.countDecimals()) || 0);
        decimals.push((sum && sum.countDecimals()) || 0);
        skipValue && decimals.push((skipValue && skipValue.countDecimals()) || 0);
        var decimal = Math.max.apply(Math, decimals);
        return (difference && Number(difference.toFixed(decimal))) || 0;
    },
    /* Insert a new row to the grid/table
        * Insert next to the selected item, or
        * Append to the last row when nothing is selected
    */
    insertRow: function (focusField, fromCSV) {
        fromCSV = fromCSV || false;
        var selected = this.select(), selectedData, newRowData, newRawData,
            index, $newRow, grid = this, rowIndex, options = this.options;
        grid.setState("adding");
        if (selected.length > 0) {
            index = this.dataSource._data.indexOf(selectedData = this.dataItem(selected[0]));
            rowIndex = selectedData.get("RowIndex");
            rowIndex += 1;
            index < 0 ? index = 0 : index += 1;
        } else {
            index = this.dataSource._data.length;
            if (index > 0) {
                rowIndex = (selectedData = this.dataSource._data[index - 1]).get("RowIndex") + 1;
            } else {
                rowIndex = 1;
            }
        }
        
        newRawData = {};
        for (var fname in this.dataSource.options.schema.model.fields) {
            var f = this.dataSource.options.schema.model.fields[fname]; /*get the datasource field's schema definition */
            //var carryValue = selectedData && !selectedData.deleted && selectedData[fname];
            if (this.dataSource.view().length == $(".rm-deleted").length || $(".rm-deleted").length == 0) {
                var carryValue = selectedData && !selectedData.deleted && selectedData[fname]
            } else {
                var valueToInsert = this.dataItems()[(this.dataSource.view().length - $(".rm-deleted").length) - 1];
                if (valueToInsert.deleted) {
                    var carryValue = selectedData && selectedData[fname];
                } else {
                    if (this.dataItems()[(this.dataSource.view().length - $(".rm-deleted").length)].deleted) {
                        var carryValue = valueToInsert && valueToInsert[fname];
                    } else {
                        var carryValue = selectedData && selectedData[fname];
                    }
                }
            }
            
            if (f.type == "number" && f.relationalField && f.relationalField != "" && !fromCSV) {
                var relationalValue = options && options.getRelationalData ? options.getRelationalData(f.relationalField) : 0;

                if (f.relationalFieldOperation == "Sum") {
                    var difference = this.getRelationalRemainder(fname, relationalValue);
                    if ($("li#" + fname).data().decimalPlace >=0) {
                        var differenceDecimalPlaces = String(difference).indexOf('.') > -1 ? String(difference).split('.')[1].length : 0;
                        if ($("li#" + fname).data().decimalPlace != differenceDecimalPlaces) {
                            difference = parseFloat(difference.toFixed($("li#" + fname).data().decimalPlace));
                        }
                    }
                    newRawData[fname] = !difference //||
                                            /*difference < 0 ||*/ // allow negative values
                    //commented since difference now can be greater than 0 but less than 0.01
                    //(difference > 0 && difference < 0.01) ?
                    ?
                                            0 : (difference / parseInt(difference)) == 1 ? parseInt(difference) : difference;
                    if (newRawData[fname] === 0) {
                        newRawData[fname] = f.defaultValue || 0;
                    }
                } else {
                    newRawData[fname] = relationalValue;
                }
            } else if (f.type == "date") {
                var dateVal = f.autoValue ? carryValue || (f.defaultValue || null) : (f.defaultValue || null);
                newRawData[fname] = dateVal && new Date(dateVal);
            } else {
                var fallValue, autoValue = f.autoValue;
                if (f.type == "number") {
                    fallValue = f.defaultValue || 0;
                } else if (f.type == "boolean") {
                    fallValue = f.defaultValue || false;
                    fallValue = rowIndex == 1 && fallValue ? fallValue || false: carryValue || false;
                } else if (f.type == "string"){
                    fallValue = f.defaultValue || "";
                } else if (f.type == "list") {
                    if (f.parentField) {
                        var parent = this.dataSource.options.schema.model.fields[f.parentField];
                        if (parent != undefined) {
                            autoValue = parent && parent.autoValue;
                        } else {
                            var avField = this.dataSource.options.schema.model.fields[fname];
                            autoValue = avField && avField.autoValue;
                        }
                    }
                    fallValue = f.defaultValue || "";
                } else {
                    newRawData[fname] = "";
                    continue;
                }
                newRawData[fname] = autoValue ? carryValue || fallValue : fallValue;
            }
        }

        for (var fname in this.dataSource.options.schema.model.fields) {
            var f = this.dataSource.options.schema.model.fields[fname],
                execRuls = f && f.executeRules || [],
                executeRulesConstraints = f && f.executeRulesConstraints || [];

            for (var i = 0; i < execRuls.length; i++) {
                var rule = this.options.rules[execRuls[i]];
                rule && rule._executeonadd && rule.run(fname, newRawData);
            }

            for (var i = 0; i < executeRulesConstraints.length; i++) {
                var ruleset = executeRulesConstraints[i].split(':');
                var constraint = ruleset[0], constraint_rules = ruleset[1];
                var rules = constraint_rules.split(',');

                //check if constraint is satisfied
                var valid = SupplementaryTable.validateHeaderConstraints(constraint);
                if (valid) {
                    // loop thru rules and execute
                    for (var r = 0; r < rules.length; r++) {
                        var rule = this.options.rules[rules[r]];
                        rule && rule._executeonadd && rule.run(fname, newRawData);
                    }
                }
            }
        }

        // call extra add row routines
        //this.options.onAddRow && this.options.onAddRow(newRawData);

        newRawData.RowIndex = rowIndex;
        newRowData = this.dataSource.insert(index, newRawData);
        newRowData.new = true;

        // offset check and reset rowindexes
        var rowCount = this.dataSource._data.length, row;
        for (var i = index + 1; i < rowCount; i++) {
            row = this.dataSource._data[i];
            if (row.RowIndex != i + 1) {
                row.set("RowIndex", i + 1);
                row.IndexChanged = true;
            }
        }

        this.setPage(rowIndex);

        $newRow = this.getItem(newRowData.uid);
        setTimeout(function () {
            // select automatically the added row
            grid.select($newRow);
            var $cell = $newRow.children("td:first-child");
            // and set the target cell to edit state
            if (focusField) {
                var focusFieldConf = grid.getFieldSchema(focusField);
                if ($newRow.length > 0 && focusFieldConf) {
                    $cell = $newRow.children("td:nth-child(" + (focusFieldConf.index + 1) + ")");
                }
            }
            else
                $cell = $newRow.children("td:visible").length > 1 ? $($newRow.children("td:visible")[1]) : $cell; //$newRow.children("td:nth-child(2)");

            if (!grid._current || grid._current.length == 0 || grid._current[0] != $cell[0]) {
                grid._current = $cell;
                grid.table.focus();
            }

            // check if the first cell of first row is focused then clear it
            grid.tbody.find("tr:first-child").find("td.k-state-focused").toggleClass("k-state-focused");
            grid.scrollTo($newRow);
            grid.editCell($cell);
        }, 50);

        grid.setState(null);

        grid.refreshRowsState();
        return newRowData;
    },
    /*
        Execute rules for that are only for table data editing.
        Expects: 
            field : Name of field to execute the rules from.
    */
    runFieldUpdateRules: function (field) {
        var f = this.dataSource.options.schema.model.fields[field],
                execRuls = f && f.executeRules || [],
                selected = this.select(),
                rowData = this.dataItem(selected);
        for (var i = 0; i < execRuls.length; i++) {
            var rule = this.options.rules[execRuls[i]];
            rule && rule.run(field, rowData, true /*update*/);
        }

        var executeRulesConstraints = f && f.executeRulesConstraints || [];
        for (var i = 0; i < executeRulesConstraints.length; i++) {
            var ruleset = executeRulesConstraints[i].split(':');
            var constraint = ruleset[0], constraint_rules = ruleset[1];
            var rules = constraint_rules.split(',');
            //check if constraint is satisfied
            var valid = SupplementaryTable.validateHeaderConstraints(constraint);
            if (valid) {
                // loop thru rules and execute
                for (var r = 0; r < rules.length; r++) {
                    var rule = this.options.rules[rules[r]];
                    rule && rule.run(field, rowData, true /*update*/);
                }
            }
        }

    },
    refreshAggregate: function () {
        var grid = this,
            focusCell = grid.tbody.find("td.k-edit-cell, td.k-state-focused"),
            focusCellIndex = focusCell.length == 0 ? -1 : focusCell.index(),
            editable = focusCell.find("input").length > 0;
        if (focusCellIndex != -1) {
            var selectedRow = grid.select();
            if (selectedRow.length > 0) {
                focusCell = selectedRow.find(kendo.format("td:nth-child({0})", focusCellIndex + 1));
                if (editable)
                    grid.editCell(focusCell);
                else {
                    focusCell.focus();
                    grid.tbody.find(".k-state-focused").removeClass("k-state-focused");
                    focusCell.addClass("k-state-focused");
                    grid._current = focusCell;
                    if (focusCell.is(":last-child")) {
                        if (grid._reachedLast) {
                            grid._navCurrent = focusCell[0];
                            delete grid._reachedLast;
                        } else {
                            grid._reachedLast = true;
                        }
                    }
                }
            }
        }
    },
    /* Enable notification for the keyboard navigation in the grid
        Expects:
            options : {
                onLeaveLastCellInRow : callback to be called when leaving the last cell in the row,
                onLeaveLastRow : callback to be called when leaving the last row in the grid
            }
    */
    enableNavNotification: function (options, $el) {
        var grid = this, keys = kendo.keys;

        this.table.on("keydown", function (e) {
            var keyCode = e.keyCode || e.which;
            SupplementaryTable.itemchangeInsert = false;
            if (keyCode == keys.TAB /*tab keycode*/) {
                // refresh the table after edit if aggregates are present
                // so that the aggregate data will be updated
                if (grid.dataSource.options.aggregate != null && grid.dataSource.options.aggregate.length > 0) {
                    SupplementaryTable.calculateAggregateFooter(SupplementaryTable.table.dataSource._data.filter(function (item) {
                        return item.deleted != true;
                        grid.refreshAggregate();
                    }));
                    
                }
                
                var focused = $(this).find("td.k-state-focused, td.k-edit-cell"),
                    selected = grid.select();
                if (focused.length == 0) {
                    var lastRow = selected.is(":last-child");
                    if (!lastRow) {
                        options.onLeaveLastCellInRow && options.onLeaveLastCellInRow();
                    }
                } else {
                    focused = $(focused[focused.length - 1]);
                    var lastRow = selected.is(":last-child"), editable = grid.editable,
                        focusParent = focused.parent();
                    if (lastRow && (focusParent[0] == grid.select()[0])) {
                        var now = focused;
                        if (grid._navCurrent == now[0]) {
                            if (grid.editable) grid.editable.element.find("input:visible").trigger("blur");
                            if (!e.shiftKey)
                                options.onLeaveLastRow && options.onLeaveLastRow(e);
                        } else {
                            grid._navCurrent = now[0];
                            if (e.shiftKey) {
                                grid.select(focusParent);
                            }
                        }
                    } else if (!lastRow && focusParent[0] != grid.select()[0]) {
                        if (!e.shiftKey) {
                            options.onLeaveLastCellInRow && options.onLeaveLastCellInRow();
                        } else {
                            grid.select(focusParent);
                            grid.editCell($(focused[0]));
                        }
                    } else if (lastRow && focusParent[0] != grid.select()[0]) {
                        grid._navCurrent = focused[0];

                        grid.select(focusParent);
                        grid.editCell($(focused[0]));
                    }
                }
                e.preventDefault();
            } else if (keyCode == keys.ENTER /*enter keycode*/) {
                if (!grid.editable) {
                    // refresh the table after edit if aggregates are present
                    // so that the aggregate data will be updated
                    if (grid.dataSource.options.aggregate != null && grid.dataSource.options.aggregate.length > 0) {
                        SupplementaryTable.calculateAggregateFooter(SupplementaryTable.table.dataSource._data.filter(function (item) {
                            return item.deleted != true;
                            grid.refreshAggregate();
                        }));
                    }

                    var focused = $(this).find("td.k-state-focused"),
                        index, selected, next, parent;
                    if ((selected = grid.select()) && ( focused.length > 0 ||
                        (focused.length == 0 && grid._current.length > 0 && (focused = grid._current)))
                        ) {
                        if (selected[0] != (parent = focused.parent())[0]) {
                            next = parent;
                        } else {
                            var last = grid.tbody[0].lastChild, next = selected;
                            do {
                                next = next.next();
                            } while (next && next.length != 0 && next.hasClass("rm-deleted") && last != next[0])

                            if (next.hasClass("rm-deleted"))
                                next = [];
                        }

                        if (next.length == 0) return;

                        
                        var f = (function (req) {
                            next = !req ? next : grid.getItem(next.data("uid"));
                            grid.editable && grid.closeCell(grid._current);
                            index = focused.index();
                            var td = next.find("td:nth-child(" + (index + 1) + ")");

                            grid.select(next);                            
                            grid._navCurrent = grid._current = td;
                            grid.editCell(td);

                            // force the focus to the new cell in case that the focus does not
                            // correspond to the cell to be edited (e.g. read-only cells)
                            var checkfocus = grid.table.find("td.k-state-focused");
                            if (checkfocus[0] != td[0]) {
                                checkfocus.removeClass("k-state-focused");
                                td.addClass("k-state-focused");
                            }
                        });

                        if (!grid._progressCounter) {
                            f();
                        } else {
                            grid._queue = f;
                        }
                    }
                }
            } else if (keyCode == keys.DELETE) {
                var selected = grid.select(), current = grid._current,
                    curParent = current.parent();

                if (!grid.options.allowDelete) return;

                if (selected[0] != curParent[0]) {
                    grid.select(curParent[0]);
                }
                if (!grid.editable && grid.toggleDeleteMark().length > 0) {
                    grid.options.onDelete && grid.options.onDelete();
                    grid.table.focus();
                }
            } else if (keyCode == keys.UP || keyCode == keys.DOWN ||
                keyCode == keys.LEFT || keyCode == keys.RIGHT) {
                if (grid._current && grid._current.length > 0) {
                    grid._navCurrent = grid._current[0];
                }
            }
        });
    },
    /*
        Set the value of the field/cell of row
        Expects:
            field: name of the field/column
            value: value to set
            all: apply to all rows if true, apply to selected row if false
    */
    setFieldValue: function (field, value, all, overrideReadonly, uid) {
        if (!all) {
            var selRow = this.select();
            if (selRow.data("uid") != uid) {
                selRow = this.getItem(uid);
            } 

            var rowData = selRow.length > 0 && this.dataItem(selRow);
            if (rowData) {
                if (rowData.get(field) || value) {
                    rowData.set(field, value, null, overrideReadonly);
                }
            }
        } else {
            var data = this.dataSource._data, len = data.length;
            for (var i = 0; i < len; i++) {
                var rowData = data[i];
                if (rowData.get(field) || value) {
                    rowData.set(field, value, null, overrideReadonly);
                }
            }
        }
        if (this._progressCounter > 0) {
            kendo.ui.progress(this.content, true);
        }
    },
    /*
        Show or hide the progress indicator.
        Expects:
            show:   true {show indicator},
                    false { hide indicator}
    */
    progress: function (show) {
        if (show) {
            this._progressCounter++;
            kendo.ui.progress(this.content, true);
        } else {
            --this._progressCounter == 0  && kendo.ui.progress(this.content, false);
        }
        this._progressCounter < 0 && (this._progressCounter = 0);
        if (this._progressCounter == 0 && this._queue) {
            this._queue(true);
            this._queue = null;
        }
    },
    /*
        Set the grid editing status.
        e.g. saving, deleting, adding
    */
    setState: function (state) {
        this._status = state;
    },
    /*
        Get the grid editing status.
    */
    getState: function (state) {
        return this._status;
    },
    /*
        Get all dirty and new rows from the table.
    */
    getDirtyNew: function () {
        var t, r, g = this, d = g.dataSource, f = d._flatData(d._data),
            data = {
                _new: [],
                _updated: []
            };
        for (t = 0, r = f.length; r > t; t++) {
            var l = f[t];

            if (l.deleted) continue;

            var item = g.clone(l, ["RowIndex"]);
            if (l.AttachmentId == 0 && l.attachment_tid) {
                item.Attachment = l.attachment_tid;
            }
            if (l.isNew()) {
                data._new.push(item);
            } else if (l.dirty) {
                data._updated.push(item);
            }
        }
        return data;
    },
    /*
        Clone a given row according to the datasource schema definition and
            some extra fields definition
        expects:
            o : Object to be cloned
            extras: array of field names that does not exist in the schema
    */
    clone: function (o, extras) {
        var d = this.dataSource, fields = d.options.schema.model.fields,
            out = {};
        for (var f in fields) {
            var field = fields[f];
            out[f] = field.type == "number" && !o[f] ? 0 : o[f];
        }
        if (extras) {
            for (var i = 0; i < extras.length; i++) {
                var f = extras[i];
                out[f] = o[f];
            }
        }
        return out;
    },
    /*
        Get the width of each column of the grid.
    */
    getColumnsWidth: function () {
        var table = this, columns = table.options.columns,
        columnsCount = columns.length, config = {}, hiddenCount = 0;
        // save columns width
        table.thead.find("th").each(function (index) {
            var $colHeader = $(this);
            var colObj = $.grep(columns, function (i) {
                return i.field == $colHeader.data('field');
            }), col = colObj.length > 0 ? colObj[0] : [];

            var colIx = $colHeader.index() - hiddenCount;
            if (col) {
                var conf = config[col.field] || {};
                if ($colHeader.css('display') === 'none') {
                    conf.width = 0;
                    conf.hidden = true;
                    config[col.field] = conf;
                    hiddenCount++;
                    return;
                }
                else {
                    col.hidden = false;
                    if (colIx != -1) {
                        var colGroupItem = table.table.find("colgroup > col:nth-child(" + (colIx + 1) + ")");
                        col.width = parseInt(colGroupItem.css("width"));
                        if (col.width == 0) {
                            col.width = $('body').measureText(col.title) + 30;
                        }
                    }
                    if (col.field == 'mark_row')
                        col.width = 28;
                }
                conf.width = col.width;
                conf.hidden = col.hidden;
                config[col.field] = conf;
            }
            
        });

        //for (var i = 0; i < columnsCount; i++) {
        //    var col = columns[i], $colHeader = table.thead.find("th[data-field=" + col.field + "]"),
        //        colIx = $colHeader.index() - hiddenCount;
        //    //if (colIx < 0) colIx = $colHeader.index();
        //    
        //    var conf = config[col.field] || {};
        //    if ($colHeader.css('display') === 'none') {
        //        conf.width = 0;
        //        conf.hidden = true;
        //        config[col.field] = conf;
        //        hiddenCount++;
        //        continue;
        //    }
        //    else {
        //        col.hidden = false;
        //        if (colIx != -1) {
        //            var colGroupItem = table.table.find("colgroup > col:nth-child(" + (colIx + 1) + ")");
        //            
        //            col.width = parseInt(colGroupItem.css("width"));
        //            if (col.width == 0) {
        //                col.width = $('body').measureText(col.title) + 30;
        //            }
        //        }
        //        if (col.field == 'mark_row')
        //            col.width = 28;
        //    }
        //    conf.width = col.width;
        //    conf.hidden = col.hidden;
        //    config[col.field] = conf;
        //}
        return config;
    },
    /*
        Set the grid columns width
        expects:
            config - Columns width configuration
    */
    setColumnsWidth: function (config) {
        //debugger;
        var table = this, columns = table.options.columns,
        columnsCount = columns.length, hiddenCount = 0;
        // save columns width
        for (var i = 0; i < columnsCount; i++) {
            var col = columns[i], $colHeader = table.thead.find("th[data-field=" + "'" + col.field  + "']"),
                colIx = $colHeader.index() - hiddenCount;

            if (colIx != -1 && col.field) {
                var colGroupItem = table.element.find("colgroup > col:nth-child(" + (colIx + 1) + ")"),
                    field = config && config[col.field], width = (field && field.width) || 0;
                if (width == 0) {
                    width = $('body').measureText(col.title) + 30;
                }
                colGroupItem.css("width", width + "px");

                if (field && field.hidden) {
                    table.hideColumnEx(col.field);
                    hiddenCount++;
                }
            }
        }
    },
    //kendo2017Update: Grid column resizing is not working in Chrome if scaling applied.
    //https://www.telerik.com/forums/column-resize-in-chrome-(61)
    _positionColumnResizeHandle: function () {
        var that = this,
            indicatorWidth = that.options.columnResizeHandleWidth,
            lockedHead = that.lockedHeader ? that.lockedHeader.find("thead:first") : $();

        that.thead.add(lockedHead).on("mousemove" + ".kendoGrid", "th", function (e) {
            var th = $(this);
            if (th.hasClass("k-group-cell") || th.hasClass("k-hierarchy-cell")) {
                return;
            }
            that._createResizeHandle(th.closest("div"), th);
        });
    }
});


// Kendo UI Combobox overrides
$.extend(kendo.ui.ComboBox.prototype, {
    /* Override the kendo combo box _accept prototype function to 
       allow clearing the combobox selected value when pressing enter
       and there's a previous valid selection
	*/
    _accept: function (e) {
        var t = this;
        (e && !e.is(".k-state-selected")) || t.text() !== "" ? t._focus(e) : (t.text(t.text()), t._change())
    },
    /*
        Get the next item in the combobox list
        Expects:
            show:   condition {function executor of the condition},
                    current {the current index selection position}
    */
    getNext: function (condition, current) {
        var current = current || this.select(), max = this.dataSource._data.length - 1;
        if (current < max) {
            current++;
            var dataItem = this.dataItem(current);
            if (dataItem.marked) return -1;
            if (condition && condition(this.dataItem(current))) {
                for (var i = 0; i < this.dataSource._data.length; i++) {
                    this.dataSource._data[i].marked = false;
                }
                return current;
            } else {
                dataItem.marked = true;
                return this.getNext(condition, current);
            }
        } else {
            return this.getNext(condition, -1);
        }
    },
    // override the kendo combo box _keydown prototype function to allow
    // trigger of change event every time a new text filter takes effect
    _search: function () {
        var that = this;
        that._typingTimeout = setTimeout(function () {
            var value = that.text();
            if (that._prev !== value) {
                that._prev = value;
                if (that.options.filter === 'none') {
                    that.listView.select(-1);
                }
                if (that.options.supplementaryHint && that.options.supplementaryHint === true) {
                    //Hints is being accessed in TD
                    (that._prev !== value && (that._prev = value, that.search(value))) || that.trigger("change");
                    that.search(value);
                    that.trigger("change");
                    that._toggleCloseVisibility();
                } else {
                    that.search(value);
                    
                    that._toggleCloseVisibility();
                }
            }
            that._typingTimeout = null;
        },that.options.delay);
    },
    /* Override the kendo combo box _keydown prototype function to allow
      opening of the list when pressing up or down arrow
   */
    _keydown: function (e) {
        var that = this, key = e.keyCode;
        d = kendo.keys,
        l = that.list;
        that._last = key;
        clearTimeout(that._typingTimeout);
        that._typingTimeout = null; 
        that._last = key, clearTimeout(that._typing), ((key == d.DOWN || key == d.UP) && !l.is(":visible")) ? that.open() : ((that._move(e) && that._change()) || that._search())
    },
});
;// customize the _show method to call options.beforeShow 
// to allow preventing the tooltip from being shown..
kendo.ui.Tooltip.fn._show = function (show) {
    return function (target) {
        var e = {
            sender: this,
            target: target,
            preventDefault: function () {
                this.isDefaultPrevented = true;
            },
            popup: show.popup
        };

        if (typeof this.options.beforeShow === "function") {
            this.options.beforeShow.call(this, e);
        }
        if (!e.isDefaultPrevented) {
            // only show the tooltip if preventDefault() wasn't called..
            show.call(this, target);
        }
    };
}(kendo.ui.Tooltip.fn._show);;/*
* Jquery custom methods
*/

/*
* Kendo view model binding jQuery extension
*/
$.prototype.bindToViewModel = function (viewModel) {
    kendo.bind(this, viewModel);
    return viewModel;
}

/*
* Groups toggler in grouped kendo grid
*/
$.prototype.toggleAllGroups = function () {
    this.find("a.k-icon").click();
}

/*
* Measures the text width.
*/
$.prototype.measureText = function (text, fontClass) {
    var textHtml = $('<span class="text_caption"></span>').css({
        display: 'none', whiteSpace: 'nowrap'
    }).appendTo(this).text(text);
    fontClass && textHtml.addClass(fontClass);
    var width = textHtml.width();
    textHtml.remove();
    return width;
}

/*
* Measures the text height.
*/
$.prototype.measureTextHeight = function (text, fontClass) {
    var textHtml = $('<span class="text_caption"></span>').css({
        display: 'none', whiteSpace: 'nowrap'
    }).appendTo(this).text(text);
    fontClass && textHtml.addClass(fontClass);
    var height = textHtml.height();
    textHtml.remove();
    return height;
}

/*
 * Decode encoded input values 
 */
$.prototype.decodeEntities = function () {
    try {
        var y = document.createElement('textarea');
        y.innerHTML = $(this) && $(this).val();
        y.value = y.value.replace(/(<([^>]+)>)/gi, "");
        $(this).attr('title', y.value);
        $(this).val(y.value);
        return y.value;
    }
    catch (e) {
        console.error(e.message);
    }
}

/*
* Finds the next element that contains the element described by the selector
*/
$.prototype.nextWithChild = function (selector) {
    var next = this.next();
    if (next && next.size() > 0) {
        var target = next.find(selector);
        if (target && target.size() > 0) {
            return target;
        } else {
            // recurse to the next element
            return next.nextWithChild(selector);
        }
    } else {
        // recurse until no next element is found
        return null;
    }
}

/*
    Easy disabling of element with queue
*/
$.prototype.disable = function (id) {
    this.attr("disabled", true);
    var dis = this.data("disabling");
    if (!dis) {
        dis = [];
    }
    dis.push(id);
    this.data("disabling", dis);
}

/*
    Apply style array to element
*/
$.prototype.applyStyles = function (s) {
    var styles = s || {};

    //for (var i = 0; i < styles.length; i++) {
    for (var i in styles) {
        var style = styles[i];
            //name = style.name, val = style.value;
        this.css(i, style);
    }
}

/*
    Easy enabling of element with queue
*/
$.prototype.enable = function (id) {
    var dis = this.data("disabling");
    if (dis) {
        dis.splice(dis.indexOf(id), 1);
    }
    if (!dis || dis.length == 0) {
        this.removeAttr("disabled");
    }
}

var RequestResultValidator = {
    redirectUrl : "",
    setSessionRedirectUrl: function (url) {
        RequestResultValidator.redirectUrl = url;
    },
    validate: function (data) {
        if (!data && typeof(data) != "boolean") {
            return false;
        } else if (typeof (data) == "boolean") {
            return true;
        } else if (data.result === false
            && data.session === -1) {
            if (RequestResultValidator.redirectUrl &&
                    RequestResultValidator.redirectUrl != "") {
                $.jAlert("Your session has expired. Please log in again.", "Relogin",
                    function () {
                        window.location.href = RequestResultValidator.redirectUrl;
                    });
            }
            return false;
        } else if (data.result === false) {
            return false;
        } else {
            return true;
        }
    }
}


/* show or hide panes embedding a kendo tabstrip li element */
function setPaneVisible($el, visible) {
    var sibsVisible = $el.siblings("li:visible");
    if (sibsVisible.length == 0 || visible === true) {
        var l, p = $el.closest(".ui-layout-pane").data("layoutPane"),
            layout = null;

        while (true) {
            l = p.pane.parent();
            if (!l.data("layoutPane") || p.name != "center") {
                break;
            } else {
                p = l.data("layoutPane");
            }
        }

        if ((layout = l.data("layout"))) {
            if (!visible) {
                if (!p.state.isClosed) {
                    if (p.pane.find("li.tab-title.k-item:visible").length >= 0) {
                        layout.close(p.name);
                    }
                }
            } else {
                if (p.state.isClosed) {
                    layout.open(p.name);
                }
                sibsVisible.css("pointer-events", "auto");
            }
        }
    } else if (sibsVisible.length > 0) {
        var l, p = $el.closest(".ui-layout-pane").data("layoutPane");
        if (p.name == "center") {
            l = p.pane.parent();
            var citems = p.pane.find("li.tab-title.k-item:visible");

            if (citems.length == 1 && l.find("li.tab-title.k-item:visible").length > 1) {
                citems.css("pointer-events", "none");
            } else {
                citems.css("pointer-events", "auto");
            }
        }
    }
}

/*
    Makes sure that array elements are unique strings
*/
function unique (array) {
    return array.filter(
        function (a) { return !this[a] ? this[a] = true : false; }, {}
    );
}

/*
    Workflow Session ID Utility
*/

function WorkflowSessionID(name, guid) {
    if (!guid || !name)
        throw "Name and Guid is required to create a Workflow Session ID";
    var _guid = guid, _user = name;
    return {
        getID: function () {
            return _guid;
        },
        getUser: function () {
            return _user;
        }
    }
}
/*
    Utility to debounce events and make multiple event
    routines to be called only once in a timespan
*/
function debouncer(debounceCallback, immediateCallback, to) {
    var _kpTO = null;
    var _debounceCallback = debounceCallback;
    var _immediateCallback = immediateCallback;
    return {
        debounce: function (data) {
            _immediateCallback && _immediateCallback(data);

            _kpTO && clearTimeout(_kpTO);
            _kpTO = setTimeout(function () {
                _debounceCallback && _debounceCallback(data);
            }, to || 500);
        }
    }
}

function isBrowserCanReadPdf() {
    var getActiveXObject = function (name) {
        try { return new ActiveXObject(name); } catch (e) { }
    };

    var getNavigatorPlugin = function (name) {
        for (key in navigator.plugins) {
            var plugin = navigator.plugins[key];
            if (plugin.name == name) return plugin;
        }
    };

    var canRead = function () {
        return this.plugin = this.plugin || function () {
            var userAgent = navigator ? navigator.userAgent.toLowerCase() : "other";
            var canRead = false, isAdobe = false;

            // for IE11 and below
            if (userAgent.indexOf("msie") > -1 ||
                userAgent.indexOf("trident") > -1) {
                // AcroPDF.PDF is used by version 7 and later
                canRead = getActiveXObject('AcroPDF.PDF') ||
                    // PDF.PdfCtrl is used by version 6 and earlier
                    getActiveXObject('PDF.PdfCtrl');
                isAdobe = canRead;
            } else {
                canRead = getNavigatorPlugin('Adobe Acrobat') ||
                    getNavigatorPlugin('Chrome PDF Viewer') ||
                    getNavigatorPlugin('WebKit built-in PDF');
                // In firefox, there's no need to hide the wiever 
                // since it does not overlaps any dialog
                isAdobe = getNavigatorPlugin('Adobe Acrobat');
            }

            return {
                canRead: canRead,
                isAdobe: isAdobe
            }
        }();
    };

    return canRead();
}

/*
	Utility to check a string's end part
*/
if (typeof String.prototype.endsWith !== 'function') {
    String.prototype.endsWith = function (suffix) {
        return this.indexOf(suffix, this.length - suffix.length) !== -1;
    };
}
/*
	Utility to check a string's starting string sequence
*/
if (typeof String.prototype.startsWith !== 'function') {
    String.prototype.startsWith = function (prefix) {
        return this.indexOf(prefix, 0) === 0;
    };
}
/*
    Hints utility.
*/
var Hints = (function () {
    return {
        /*
          Utility to get hints through ajax.
        */
        get: function (url, data, callback) {
            $.ajax({
                url: url,
                type: "GET",
                dataType: "JSON",
                data: data,
                success: function (data) {
                    if (RequestResultValidator.validate(data)) {
                        callback && callback(data);
                    }
                },
                error: function (jqXHR, status, error) {
                    debugger;
                    //if (globalVars.unloaded)
                     return;
                }
            });
        }
    }
})();

Number.prototype.countDecimals = function () {
    if (Math.floor(this.valueOf()) === this.valueOf()) return 0;
    var data = this.toString().split(".");
    return data && data.length == 2 ? data[1].length || 0 : 0;
}

function toDateTimeString(d) {
    if (d != null)
        return d.toLocaleString();
    else
        return "";
}

function toDateString(d) {
    if (d != null)
        return d.toLocaleDateString();
    else
        return "";
}


/*
    Browser
*/
var Browser = {
    is : {
        IE: function () {
            var ms_ie = false;
            var ua = window.navigator.userAgent;
            var old_ie = ua.indexOf('MSIE ');
            var new_ie = ua.indexOf('Trident/');

            if ((old_ie > -1) || (new_ie > -1)) {
                ms_ie = true;
            }
            return ms_ie;
        }
    },
    isMozilla: function () {
        var mozilla = false;
        if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
            mozilla = true;
        }
        return mozilla;
    },
    getIEVersion:function() {
        var sAgent = window.navigator.userAgent;
        var Idx = sAgent.indexOf("MSIE");

        // If IE, return version number.
        if (Idx > 0)
            return parseInt(sAgent.substring(Idx + 5, sAgent.indexOf(".", Idx)));
        // If IE 11 then look for Updated user agent string.
        else if (!!navigator.userAgent.match(/Trident\/7\./))
            return 11;
        else
            return 0; //It is not IE
    }
}

/*
    Function to resize result/supplementarytable grid to
    fit the dropdown of column menu and other controls
    if adobe reader plugin is enable on IE and Mozilla 
    browser to prevent displaying the control under the viewer.
*/
function resizeGridToDocumentView(hint,reset) {
    if ($('#document-view-content').hasClass("adobe")) {
        var layoutObject = $("#dock-area").data("layout"),
            south = layoutObject.panes.south[0];
        var north = layoutObject.panes.north[0],expand="45%";
            
        if (reset && reset == true) {
            layoutObject.sizePane("south", expand, false, true)
            return;
        }
        if (hint && hint == true) {
            expand = "100%";
        }
        if ($(south).height() < 388) {
            layoutObject.sizePane("south", expand, false, true)
            return;
        }
    }
}

function insertTextAtCursor(el, text) {
    var val = el.value, endIndex, range;
    if (typeof el.selectionStart != "undefined" && typeof el.selectionEnd != "undefined") {
        endIndex = el.selectionEnd;
        el.value = val.slice(0, el.selectionStart) + text + val.slice(endIndex);
        el.selectionStart = el.selectionEnd = endIndex + text.length;
    } else if (typeof document.selection != "undefined" && typeof document.selection.createRange != "undefined") {
        el.focus();
        range = document.selection.createRange();
        range.collapse(false);
        range.text = text;
        range.select();
    }
}
$.extend({
    distinctObj: function (obj, propertyName) {
        var result = [];
        $.each(obj, function (i, v) {
            var prop = v[propertyName];
            if (prop != undefined && prop != null) {
                if ($.inArray(prop, result) == -1) result.push(prop);
            }
        });
        return result;
    }
});

//TODO: Update with complete set of characters.
var CharReplace = {
    convert: function (str) {
        if (str != null) {
            str = str.replace(/&/g, "&amp;");
            str = str.replace(/>/g, "&gt;");
            str = str.replace(/</g, "&lt;");
            str = str.replace(/"/g, "&quot;");
            str = str.replace(/'/g, "&#039;");
        }
        return str;
    }
}

function GetSelectedGridItems(gridName, kendoGrid) {
    //kendoGrid example: RulesManagement.grid
    var ids = "";
    $(gridName + " input[type='checkbox']").each(function () {
        if (this.checked) {
            var item = kendoGrid.dataItem($(this).closest('tr'));
            if (item) ids += (ids != "" ? "," : "") + item.id;
        }
    });
    return ids;
}

//   var fields = [{ title: "ON", template: "AND a.#= SourceField # = b.#= JoinField #" }, "ColumnName"];
//   createGrid1("#JoinSummary", fields, { change: populateJoinFields });
function createKendoGrid(targetDiv, mycolums, source, others) {
    return $(targetDiv).kendoGrid({
        dataSource: source,
        height: others.height ? (others.height != "none" ? others.height : null) : 300,
        scrollable: others.scrollable ? others.scrollable : true,
        sortable: true,
        autobind: false,
        selectable: true,
        change: others.change ? others.change : null,
        columns: mycolums,
        editable: others.editable ? others.editable : null,
        edit: others.edit ? others.edit : null,
        save: others.save ? others.save : null,
        toolbar: others.toolbar ? others.toolbar : null,
        detailInit: others.detailInit ? others.detailInit : null,
        detailTemplate: others.detailTemplate ? others.detailTemplate : null,
        dataBound: others.dataBound ? others.dataBound : null,
        cancel: others.cancel ? others.cancel : null,
        navigatable: others.navigatable ? others.navigatable : true
    });
}

function createDropDownList(target, data, fnChange, others) {
    others = others || {};
    $(target).kendoDropDownList({
        dataSource: data,
        index: 0,
        change: fnChange,
        select: others.select ? others.select : null,
        enable: others.enable ? others.enable : true,
    });
}


function createComboBox(target, data, fnChange, others, width) {
    others = others || {};
    $(target).kendoComboBox({
        dataSource: data,
        index: 0,
        change: fnChange,
        select: others.select ? others.select : null,
        enable: others.enable ? others.enable : true
    });

    if (width) {
        var combobox = $(target).data('kendoComboBox');
        combobox.list.width(width);
    }
}

//return the first instance of value that match in a dataSource. 
function findDataSourceValue(dataSource, value) {
    var arObj = dataSource.toJSON();
    var obj = arObj.filter(function (o) {
        return o.Name === value;
    })[0];
    return obj;
}

//returns current date in YYYY/MM/DD (without time)
function getCurrentDate() {
    var now = new Date();
    var today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    return today;
}

//Helper to allow localStorage to store object
Storage.prototype.setObject = function (key, value) {
    this.setItem(key, JSON.stringify(value || null));
}

Storage.prototype.getObject = function (key) {
    var value = this.getItem(key);
    return value && JSON.parse(value);
}

Storage.prototype.clearObject = function (key) {
    var value = this.removeItem(key);
}

/*Check if in Iframe*/
function inIframe() {
    try {
        return window.self !== window.top;
    } catch (e) {
        debugger;
        return true;
    }
}

function isValidEmailAddress(emailAddress) {
    var pattern = new RegExp(/^(("[\w-\s]+")|([\w-]+(?:\.[\w-]+)*)|("[\w-\s]+")([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i);
    return pattern.test(emailAddress);
};
var Storage = {
    save: function (name, parameter, value) {
        var o;
        if (!(o = Storage.get(name))) {
            o = {};
        }
        o[parameter] = value;
        localStorage[name] = JSON.stringify(o);
    },
    get: function (name) {
        var d;
        if ((d = localStorage[name])) {
            return JSON.parse(d);
        } else {
            console.log("Warning: Storage for " + name + " was not found.");
            return null;
        }
    },
    delete: function (name, parameter) {
        var o, p;
        if ((o = Storage.get(name)) && o[parameter]) {
            delete o[parameter];
            localStorage[name] = JSON.stringify(o);
        }
    }
};    /*
        Create a flashing tab notification page title.
        Credit goes to http://curtistimson.co.uk/js/create-a-flashing-tab-notification-page-title
    */
    var PageTitleNotification = {
        Vars: {
            OriginalTitle: document.title,
            Interval: null
        },
        On: function (notification, intervalSpeed) {
            var _this = this;
            _this.Vars.Interval = setInterval(function () {
                document.title = (_this.Vars.OriginalTitle == document.title)
                                    ? notification
                                    : _this.Vars.OriginalTitle;
            }, (intervalSpeed) ? intervalSpeed : 500);
        },
        Off: function () {
            clearInterval(this.Vars.Interval);
            document.title = this.Vars.OriginalTitle;
        }
    }


    /*
        Global variables.
    */
    var _count = 0, _timerId, _warn_minutes;

    /*
      Object to save the time of access on the 
      Local Storage. The purpose is to have one point of access that will be
      available for the entire session.
    */
    var sessStorage = {
        saveLastAccess: function () {
            var s = Storage;
            if (s) {
                s.save("ActiveSession", "lastActivity", {
                    lastAccess: new Date(),
                    login: true
                });
                return new Date(s.get("ActiveSession").lastActivity.lastAccess);
            }
        },
        getLastAccess: function () {
            var s = Storage, sn = SessionNotify;
            try {
                if (s && s.get("ActiveSession"))
                    return new Date(s.get("ActiveSession").lastActivity.lastAccess);
            }
            catch (err) {
                console.log("Error: " + err.message);
                sn.sessEmptyAndLeave();
            }
        },
        saveLastRequest: function () {
            var s = Storage;
            if (s) {
                s.save("ActiveRequest", "lastActivity", {
                    lastAccess: new Date(),
                    login: true
                });
                return new Date(s.get("ActiveRequest").lastActivity.lastAccess);
            }
        },
        getLastServerRequest: function () {
            var s = Storage, sn = SessionNotify;
            try {
                if (s && s.get("ActiveRequest"))
                    return new Date(s.get("ActiveRequest").lastActivity.lastAccess);
            }
            catch (err) {
                console.log("Error: " + err.message);
                sn.sessEmptyAndLeave();
            }
        }
    };

    /*
        Callback to execute per second depending on the time set before the session timeout.
    */
    var ticker = function () {
        var sn = SessionNotify;
        if (_count != 1) {
            _count = _count - 1;
            $('#timer').text(_count);
            var now = new Date();
            //Check if available on local storage
            var s = Storage;
            if (s && s.get("SessionLogout") && typeof (s.get("SessionLogout").logout) === "undefined") {
                if (s && s.get("ActiveSession")) {
                    //get difference in milliseconds
                    var diff = now - sessStorage.getLastAccess();
                    //get interval in minutes
                    var diffMins = (diff / 1000 / 60);
                    //If user interrupt the dialogue by clicking the yes button.
                    //Then make a request to refresh the page
                    if (diffMins < (sn.sess_expirationMinutes - _warn_minutes)) {
                        $.get(ROOT + "Account/KeepSessionAlive", function (e) {
                            if (!e) {
                                sn.sessEmptyAndLeave();
                            }
                        }).fail(function () {
                            sn.sessEmptyAndLeave();
                        });
                        var sn = SessionNotify;
                        sn.initSession();
                        sn.sess_lastActivity = sessStorage.saveLastAccess();
                        clearInterval(_timerId);
                        $.alerts._hide();
                        PageTitleNotification.Off();
                    }
                }
            }
            else {
                sn.sessEmptyAndLeave();
            }
        }
        else {
            //If countdown ends, then exit R5.
            sn.sessEmptyAndLeave();
        }
    };

    /*
        Monitor ajax request, so that we can reset the time of the last http request.
    */
    var lastHttpRequest;
    var oldXHR = window.XMLHttpRequest;

    function newXHR() {
        var realXHR = new oldXHR();
        realXHR.addEventListener("readystatechange", function () {
            lastHttpRequest = sessStorage.saveLastAccess();
            if (realXHR.readyState == 4 && realXHR.status == 200) {
                lastHttpRequest = sessStorage.saveLastRequest();
                bindEvent();
            }

        }, false);
        return realXHR;
    }
    window.XMLHttpRequest = newXHR;
    /**************************************************************************************/

    /*
        Bind mouse and keyboard event. 
        We need to reset the time of access
        on each event.
    */

    function bindEvent() {
        $(document).bind('keypress', function (ed, e) {
            if (window != window.top) {
                parent.$('body').trigger('keypress');
                return;
            }
            var sn = SessionNotify;
            sn.sessKeyPressed(ed, e);
        });

        $(document).bind('click', function (ed, e) {
            if (window != window.top) {
                parent.$('body').trigger('click');
                return;
            }
            var sn = SessionNotify;
            sn.sessMouseClicked(ed, e);
        });
    }

    bindEvent();


    /*
      Main object to monitor the session expiration
    */
    var SessionNotify = {
        sess_pollInterval: 1000,
        sess_expirationMinutes: 0,
        sess_warningMinutes: 0,
        sess_intervalID: null,
        sess_lastActivity: null,
        sess_lastRequest: 1,
        init: function () {

            if (window != window.top) { return; }
            var sn = SessionNotify;
            _warn_seconds = 0;
            if (sn.sess_warningMinutes == "")
                //set to 120 seconds if there's no value on the webConfig
                sn.sess_warningMinutes = 120;
            if (sn.sess_warningMinutes >= parseInt(sn.sess_expirationMinutes) * 60) {
                _warn_minutes = parseInt(sn.sess_expirationMinutes) - (parseInt((sn.sess_expirationMinutes) * 60) / 2) / 60;
            }
            else {
                _warn_minutes = parseInt(sn.sess_warningMinutes) / 60;
            }
            if (ROOT.indexOf("undefined") > -1)
                ROOT = window.location.protocol + "//" + window.location.host + "/";
            sn.initSession();
        },
        initSession: function () {
            var sn = SessionNotify;
            sn.sess_lastActivity = sessStorage.saveLastAccess();
            sn.sessSetInterval();
        },
        sessSetInterval: function () {
            var sn = SessionNotify;
            sn.sess_intervalID = setInterval(sn.sessInterval, sn.sess_pollInterval);
        },
        sessClearInterval: function () {
            var sn = SessionNotify;
            clearInterval(sn.sess_intervalID);
            _count = (_warn_minutes) * 60
            _timerId = setInterval(ticker, 1000);
        },
        sessKeyPressed: function (ed, e) {
            var sn = SessionNotify;
            sn.sess_lastActivity = sessStorage.saveLastAccess();
        },
        sessMouseClicked: function (ed, e) {
            var sn = SessionNotify;
            sn.sess_lastActivity = sessStorage.saveLastAccess();
        },
        sessLogOut: function () {
            PageTitleNotification.Off();
            var s = Storage;
            if (s) {
                s.save("SessionLogout", "logout", true);
            }
        },
        sessEmptyAndLeave: function () {
            var s = Storage;
            clearInterval(_timerId);
            PageTitleNotification.Off();
            if (s) {
                s.delete("ActiveSession", "lastActivity");
            }

            //Save Search column state
            if (typeof (ResultList) != "undefined") {
                ResultList.saveColumns();
            }
            
            //Save MyWorks column state
            if (typeof (Queue) != "undefined") {
                Queue.saveColumns();
                if (typeof (BrowsePane) != "undefined") {
                    BrowsePane.saveState();
                }
            }
            //Save lines state
            if (typeof (SupplementaryTable) != "undefined") {
                SupplementaryTable.save();
            }
            //Save layout state
            if (typeof (RedmapLayout) != "undefined") {
                RedmapLayout.save();
            }
            window.onbeforeunload = null;
            window.location = ROOT + "Account/LogOff";
        },
        sessInterval: function () {
            var sn = SessionNotify, s = Storage;
            var Tick = new Date(); //Continue to monitor session if user is still active on the page.
        
            var diff = Tick - sessStorage.getLastAccess(); //get last event (kepressed or mouse click event) difference in milliseconds
            var diffMins = (diff / 1000 / 60);

            var lastAccess = Tick - sessStorage.getLastAccess();
            lastAccess = (lastAccess / 1000 / 60);
        
            var lastRequest = Tick - sessStorage.getLastServerRequest();
            lastRequest = (lastRequest / 1000 / 60);

            //If user is still active from its last request then reset session timeout.
            if (lastRequest >= (sn.sess_expirationMinutes - _warn_minutes) && (lastAccess < lastRequest)) {

                $.get(ROOT + "Account/KeepSessionAlive", function (e) {
                    if (!e) {
                        sn.sessClearInterval();
                        sn.sessLogOut();
                    }
                }).fail(function () {
                    sn.sessClearInterval();
                    sn.sessLogOut();
                });
                
                sn.sess_lastActivity = sessStorage.saveLastAccess();
                return;
            }

            //Timeout limit has reached.
            if (diffMins >= (sn.sess_expirationMinutes - _warn_minutes)) {
                //warn before expiring
                //stop the timer

                if (ROOT.indexOf("undefined") > -1)
                    ROOT = window.location.protocol + "//" + window.location.host + "/";

                //Lock the document so that confirmation window will not be interupted
                //by triggering the event on the background.
                $(document).unbind('click');
                $(document).unbind('keypress');
                sn.sessClearInterval();

                //Notify user, this will appear on page title of the tab.
                PageTitleNotification.On("Session soon to expire!");

                //Pop window notifier
                var active = $.jConfirm('Your session will expire in <b><text id="timer"></text></b> seconds. Press \"Yes"\ to remain logged in ' +
                        'or press \"No"\ to log off.', "Session is about to expire",
                        function (active) {
                            if (active) {
                                //HttpRequest to refresh the session
                                PageTitleNotification.Off();
                                $.get(ROOT + "Account/KeepSessionAlive", function (e) {
                                    if (!e) {
                                        sn.sessClearInterval();
                                        sn.sessLogOut();
                                    }
                                }).fail(function () {
                                    sn.sessClearInterval();
                                    sn.sessLogOut();
                                });

                                sn.initSession();
                                sn.sess_lastActivity = sessStorage.saveLastAccess();
                                clearInterval(_timerId);
                            }
                            else {
                                sn.sessLogOut();
                            }
                        });
            }
        }
    }


;

(function ($) {
    /*
    * jQuery extension for custom preloader
    */
    $.prototype.preloaderShow = function (user, hideIFrames, callback, timeout) {
        var users = this.data("users");
        if (!users) {
            users = {};
        }
        users[user] = {
            active: "true",
            callback: callback
        }
        this.data("users", users);

        if (this.data("visible") && this.data("visible") === true) {
            return;
        }

        if (!Redmap._isMobile) {
            this.show();
        } else {
            Redmap.Mobile._application.pane.loader.show();
        }

        if (hideIFrames) {
            $("iframe").hide();
        }
        this.data("visible", true)
        var thatPreloader = this;
        if (timeout != -1) {
            setTimeout(function () {
                thatPreloader.preloaderHide(user, true);
            }, 20000);
        }
    }

    $.prototype.preloaderHide = function (user, showIFrames) {
        var users = this.data("users");

        if (users && users[user]) {
            if (users[user].callback) {
                users[user].callback();
            }
            delete users[user];
        }

        if (!users || (Object.keys(users).length == 0)) {

            if (!this.data("visible")) {
                return;
            }

            if (!Redmap._isMobile) {
                this.hide();
            } else {
                Redmap.Mobile._application.pane.loader.hide();
            }

            if (showIFrames) {
                $("iframe:not(.download-frame)").show();
            }
            this.data("visible", false)
        }
        this.data("users", users);
    }
})(jQuery);




;// jQuery Alert Dialogs Plugin
//
// Version 1.1
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
// 14 May 2009
//
// Website: http://abeautifulsite.net/blog/2008/12/jquery-alert-dialogs/
//
// Usage:
//		jAlert( message, [title, callback] )
//		jConfirm( message, [title, callback] )
//		jPrompt( message, [value, title, callback] )
// 
// History:
//
//		1.00 - Released (29 December 2008)
//
//		1.01 - Fixed bug where unbinding would destroy all resize events
//
// License:
// 
// This plugin is dual-licensed under the GNU General Public License and the MIT License and
// is copyright 2008 A Beautiful Site, LLC. 
//
(function($) {
	
    $.alerts = {
		
        // These properties can be read/written by accessing $.alerts.propertyName from your scripts at any time
		
        verticalOffset: -75,                // vertical offset of the dialog from center screen, in pixels
        horizontalOffset: 0,                // horizontal offset of the dialog from center screen, in pixels/
        repositionOnResize: true,           // re-centers the dialog on window resize
        overlayOpacity: .5,                 // transparency level of overlay
        overlayColor: '#FFF',               // base color of overlay
        draggable: true,                    // make the dialogs draggable (requires UI Draggables plugin)
        sendButton: '&nbsp;Send&nbsp;',     // text for the send button
        yesButton: '&nbsp;Yes&nbsp;',       //text for the yes button    
        noButton:'&nbsp;No&nbsp;',          // text for the no button
        okButton: '&nbsp;OK&nbsp;',         // text for the OK button
        cancelButton: '&nbsp;Cancel&nbsp;', // text for the Cancel button
        dialogClass: null,                  // if specified, this class will be applied to all dialogs
		
        // Public methods
		
        alert: function(message, title, callback) {
            if (title == null) title = 'Alert';
            $.alerts._show(title, message, null, 'alert', function(result) {
                if( callback ) callback(result);
            });
        },

        success: function (message, title, callback) {
            if (title == null) title = 'Success';
            $.alerts._show(title, message, null, 'success', function (result) {
                if (callback) callback(result);
            });
        },

        info: function (message, title, callback) {
            if (title == null) title = 'Info';
            $.alerts._show(title, message, null, 'info', function (result) {
                if (callback) callback(result);
            });
        },
		
        confirm: function(message, title, callback) {
            if (title == null) title = 'Confirm';
            $.alerts._show(title, message, null, 'confirm', function(result) {
                if( callback ) callback(result);
            });
        },

        confirmEx: function (message, title, callback) {
            if (title == null) title = 'Confirm';
            $.alerts._show(title, message, null, 'confirm_ex', function (result) {
                if (callback) callback(result);
            });
        },
			
        prompt: function (message, value, title, callback, optional) {
            if( title == null ) title = 'Prompt';
            $.alerts._show(title, message, value, 'prompt', function(result) {
                if (callback) callback(result);
            }, optional);
        },
        check: function (message, value, title, callback, optional) {
            if (title == null) title = 'Check';
            if (optional) {
                $.alerts._show(title, message, value, 'check', function (result, chkval) {
                    if (callback) callback(result, chkval);
                }, optional);
            }
            else {
                $.alerts._show(title, message, null, 'confirm', function (result) {
                    if (callback) callback(result, false);
                });
            }
        },
		// Private methods
		
        _show: function (title, msg, value, type, callback, optional) {
            $.alerts._hide();
            $.alerts._overlay('show');
            $('#document-view-content.adobe').hide();
			
			$("BODY").append(
			  '<div id="popup_container" class="k-widget k-window">' +
			    '<h1 id="popup_title" class="k-header" style="font-size:18px;font-weight:bold;padding:5px 0 0 10px; height:30px"></h1>' +
			    '<div id="popup_content" class="k-content">' +
			      '<div id="popup_message"></div>' +
				'</div>' +
                '<div id="popup_footer" class="footer k-toolbar" style="height:40px; "></div>' +
			  '</div>');
			
			if( $.alerts.dialogClass ) $("#popup_container").addClass($.alerts.dialogClass);
			
			 //IE6 Fix
			var pos = ($.browser && $.browser.msie && parseInt($.browser.version) <= 6) ? 'absolute' : 'fixed';
			
			$("#popup_container").css({
				position: pos,
				zIndex: 99999,
				padding: 0
				//margin: 0 
			});
			
			$("#popup_title").text(title);
			$("#popup_content").addClass(type);
			$("#popup_message").text(msg);
			$("#popup_message").html( $("#popup_message").text().replace(/\n/g, '<br />') );
			

			$("#popup_container").css({
				minWidth: $("#popup_container").outerWidth(),
			});
			
			$.alerts._reposition();
			$.alerts._maintainPosition(true);
			
			switch( type ) {
				case 'alert':
				    $("#popup_footer").append('<input type="button" class="k-button k-button-default" value="' + $.alerts.okButton + '" id="popup_ok" style="width:50px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/>');
					$("#popup_ok").click( function() {
						$.alerts._hide();
						callback(true);
					});
					$("#popup_ok").focus().keypress( function(e) {
						if( e.keyCode == 13 || e.keyCode == 27 ) $("#popup_ok").trigger('click');
					});
					break;
			    case 'success':
			        $("#popup_footer").append('<input type="button" class="k-button k-button-default" value="' + $.alerts.okButton + '" id="popup_ok" style="width:50px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/>');
			        $("#popup_ok").click(function () {
			            $.alerts._hide();
			            callback(true);
			        });
			        $("#popup_ok").focus().keypress(function (e) {
			            if (e.keyCode == 13 || e.keyCode == 27) $("#popup_ok").trigger('click');
			        });
			        break;
			    case 'info':
			        $("#popup_footer").append('<input type="button" class="k-button k-button-default" value="' + $.alerts.okButton + '" id="popup_ok" style="width:50px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/>');
			        $("#popup_ok").click(function () {
			            $.alerts._hide();
			            callback(true);
			        });
			        $("#popup_ok").focus().keypress(function (e) {
			            if (e.keyCode == 13 || e.keyCode == 27) $("#popup_ok").trigger('click');
			        });
			        break;
			    case 'confirm_ex':
			        $("#popup_footer").append('<input type="button" class="k-button cancel" value="' + $.alerts.cancelButton + '" id="popup_cancel" style="width:60px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/> <input type="button" class="cancel k-button" value="' + $.alerts.noButton + '" id="popup_no" style="width:50px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/> <input type="button" class="k-button k-button-default" value="' + $.alerts.yesButton + '" id="popup_ok" style="width:50px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/>');
			        $("#popup_ok").click(function () {
			            $.alerts._hide();
			            if (callback) callback(true);
			        });
			        $("#popup_no").click(function () {
			            $.alerts._hide();
			            if (callback) callback(false);
			        });
			        $("#popup_cancel").click(function () {
			            $.alerts._hide();
			            if (callback) callback(null);
			        });
			        $("#popup_ok").focus();
			        $("#popup_ok, #popup_cancel").keypress(function (e) {
			            if (e.keyCode == 13) $("#popup_ok").trigger('click');
			            if (e.keyCode == 27) $("#popup_cancel").trigger('click');
			        });
			        break;
				case 'confirm':
				    $("#popup_footer").append('<input type="button" class="cancel k-button" value="' + $.alerts.noButton + '" id="popup_cancel" style="width:50px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/> <input type="button" class="k-button k-button-default" value="' + $.alerts.yesButton + '" id="popup_ok" style="width:50px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/>');
					$("#popup_ok").click( function() {
						$.alerts._hide();
						if( callback ) callback(true);
					});
					$("#popup_cancel").click( function() {
						$.alerts._hide();
						if( callback ) callback(false);
					});
					$("#popup_ok").focus();
					$("#popup_ok, #popup_cancel").keypress( function(e) {
						if( e.keyCode == 13 ) $("#popup_ok").trigger('click');
						if( e.keyCode == 27 ) $("#popup_cancel").trigger('click');
					});
				break;
			    case 'prompt':
			        if (optional == null) optional = false;
			        $("#popup_message").append('<br /><br />' + (optional ? 'Comment (optional)' : 'Provide comment <span style="color:red;">*</span>') + '<textarea class="textbox" type="textarea" rows="4" cols="50" size="30" id="popup_prompt" ' + (optional ? '' : 'required') + ' />');
			        $("#popup_footer").append('<input type="button" class="cancel k-button" value="' + $.alerts.cancelButton + '" id="popup_cancel" style="width:60px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/> <input type="button" class="k-button k-button-default" value="' + $.alerts.sendButton + '" id="popup_ok" style="width:60px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/>');
					$("#popup_prompt").width( $("#popup_message").width() * .9 );
					$("#popup_ok").click( function() {
					    var val = $("#popup_prompt").val();
					    if (val.trim() == "" && optional == false) return;
						$.alerts._hide();
						if( callback ) callback( val );
					});
					$("#popup_cancel").click( function() {
						$.alerts._hide();
						if( callback ) callback( null );
					});
					$("#popup_prompt, #popup_ok, #popup_cancel").keypress( function(e) {
						if( e.keyCode == 13 ) $("#popup_ok").trigger('click');
						if( e.keyCode == 27 ) $("#popup_cancel").trigger('click');
					});
					if( value ) $("#popup_prompt").val(value);
					$("#popup_prompt").focus().select();
					break;
			    case 'check':
			        $("#popup_message").append('<br /><br /></span><br /><input type="checkbox" id="popup_check"/>&nbsp;' + optional);
			        $("#popup_footer").append('<input type="button" class="cancel k-button" value="' + $.alerts.cancelButton + '" id="popup_cancel" style="width:60px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/> <input type="button" class="k-button k-button-default" value="' + $.alerts.okButton + '" id="popup_ok" style="width:50px; height:30px; text-align:center; padding:0px; margin-top:5px; margin-bottom:5px; "/>');
			        
			        $("#popup_ok").click(function () {
			            var val = document.getElementById("popup_check").checked;
			            $.alerts._hide();
			            if (callback) callback(true, val);
			        });
			        $("#popup_cancel").click(function () {
			            $.alerts._hide();
			            if (callback) callback(null, false);
			        });
			        $("#popup_ok, #popup_cancel").keypress(function (e) {
			            if (e.keyCode == 13) $("#popup_ok").trigger('click');
			            if (e.keyCode == 27) $("#popup_cancel").trigger('click');
			        });
			        if (value) $("#popup_check").val(value);
			        $("#popup_cancel").focus().select();
			        break;
			}
			
			// Make draggable
			if( $.alerts.draggable ) {
				try {
					$("#popup_container").draggable({ handle: $("#popup_title") });
					$("#popup_title").css({ cursor: 'move' });
				} catch(e) { /* requires jQuery UI draggables */ }
			}
		},
		
        _hide: function () {
		    $("#popup_container").remove();
			$.alerts._overlay('hide');
			$.alerts._maintainPosition(false);
			if (!$('#popup_container').is(':visible')) {
			    $('#document-view-content.adobe').show();
			}
		},
		
		_overlay: function(status) {
			switch( status ) {
				case 'show':
					$.alerts._overlay('hide');
					$("BODY").append('<div id="popup_overlay"></div>');
					$("#popup_overlay").css({
						position: 'absolute',
						zIndex: 99998,
						top: '0px',
						left: '0px',
						width: '100%',
						height: $(document).height(),
						background: $.alerts.overlayColor,
						opacity: $.alerts.overlayOpacity
					});
				break;
				case 'hide':
					$("#popup_overlay").remove();
				break;
			}
		},
		
		_reposition: function() {
		    var $container,
                top = (($(window).height() / 2) - (($container = $("#popup_container")).outerHeight() / 2)) + $.alerts.verticalOffset,
		        $content = $("#popup_content"), $message = $("#popup_message");
			var left = (($(window).width() / 2) - ($("#popup_container").outerWidth() / 2)) + $.alerts.horizontalOffset;
			if( top < 0 ) top = 0;
			if( left < 0 ) left = 0;
			
			// IE6 fix
			if( $.browser && $.browser.msie && parseInt($.browser.version) <= 6 ) top = top + $(window).scrollTop();
			
			$container.css({
				top: top + 'px',
				left: left + 'px'
			});
			$("#popup_overlay").height( $(document).height() );

			if ($container.height() < $content.height()) {
			    $content.height($container.height() - 150)
			    $message.height($content.height() - 20)
			}
		},
		
		_maintainPosition: function(status) {
			if( $.alerts.repositionOnResize ) {
				switch(status) {
					case true:
						$(window).bind('resize', $.alerts._reposition);
					break;
					case false:
						$(window).unbind('resize', $.alerts._reposition);
					break;
				}
			}
		}
		
	}
	
	// Shortuct functions
    $.jAlert = function (message, title, callback) {
        $.alerts.alert(message, title, callback);
    };

	$.jSuccess = function (message, title, callback) {
	    $.alerts.success(message, title, callback);
	};

	$.jInfo = function (message, title, callback) {
	    $.alerts.info(message, title, callback);
	};
	
	$.jConfirm = function(message, title, callback) {
		$.alerts.confirm(message, title, callback);
	};

	$.jConfirmEx = function (message, title, callback) {
	    $.alerts.confirmEx(message, title, callback);
	};
		
	$.jPrompt = function (message, value, title, callback, optional) {
	    if (optional == null) optional = false;
		$.alerts.prompt(message, value, title, callback, optional);
	};

	$.jCheck = function (message, value, title, callback, optional) {
	    if (optional == null) optional = false;
	    $.alerts.check(message, value, title, callback, optional);
	};
	
})(jQuery);
;